Subject:
[ruby-ffi] Re: pointers and out parameters
From:
Wayne Meissner
Date:
1/20/12 6:02 AM
To:
ruby-ffi@googlegroups.com

It looks like you need to pass the address of a zmsg_t pointer, so you need to use Pointer#write_pointer()
i.e. I think something like this might work:

  def once 
      raise "Worker needs a responder block" unless block_given? 

      ptr = FFI::MemoryPointer.new(:pointer) 
      reply = nil
      while true
        puts "calling receive" 
        request = Majordomo.mdwrk_recv @session, ptr 
        puts "worker interrupted" unless request 

        reply = yield request 
        # The block returned a zmsg_t pointer
        ptr.write_pointer(reply)
      end 
    end 

On Thursday, 19 January 2012 17:40:01 UTC+10, Mark Wotton wrote:
Hi all,

I'm trying to move some code from C to Ruby using FFI.

  The problematic chunk looks like this:

  int verbose = (argc > 1 && streq (argv [1], "-v"));
    mdwrk_t *session = mdwrk_new (
        "tcp://localhost:5555", "echo", verbose);

    zmsg_t *reply = NULL;
    while (1) {
        zmsg_t *request = mdwrk_recv (session, &reply);
        if (request == NULL)
            break;              //  Worker was interrupted
        reply = request;        //  Echo is complex... :-)
    }
    mdwrk_destroy (&session);
    return 0;


I'm not quite sure how to model the "reply = request" chunk - I have
this:


module Majordomo
  extend FFI::Library
  ffi_lib 'lib0mq_majordomo'

  attach_function :mdwrk_new, [:string, :string, :bool], :pointer
  attach_function :mdwrk_recv, [:pointer, :pointer], :pointer
  attach_function :mdwrk_destroy, [:pointer], :void
  class Worker < FFI::ManagedStruct
    def initialize(host, service, verbose=false)
      @session = Majordomo.mdwrk_new host, service, verbose
    end

    # this is a bit ugly, but the C expects to be in a run loop
    # and therefore makes mdwrk_recv do two things...
    def once
      raise "Worker needs a responder block" unless block_given?

      ptr = FFI::MemoryPointer.new(:pointer)
      while true
        puts "calling receive"
        request = Majordomo.mdwrk_recv @session, ptr
        puts "worker interrupted" unless request

        ptr = yield request
      end
    end
  end
end

calling it as

  while true
    worker.once {|x| x}
  end

to test. The first run goes through ok, but the "ptr = yield request"
is clearly bogus: it should really be one layer of indirection out.

I can't see how to model this, even after going through the out
parameter section in the wiki. Could you help?

cheers
Mark