Subject:
[ruby-ffi] Re: Passing a String Pointer to Callback Procs -- How to append?
From:
Scott Gonyea
Date:
11/11/10 11:20 PM
To:
ruby-ffi

Thank you, Wayne.  Evan actually gave me some helpful info, as well,
along similar lines (just a little bit before you replied).  The fix
was to, basically, not make the Proc a constant (first).  Then, inside
the proc, I would simply append the "stream" variables data to an
instance variable.

This was then replaced by something NoKarma used (and I stole), which
was to pass a FFI::Function, which calls an instance method (which
then appends to an instance variable).

You can see my code in its current state, which seems to be largely
good / stable / etc.  There's another issue, which I'm going to post
about separately.

https://github.com/aitrus/streamly_ffi/blob/master/lib/streamly_ffi/base.rb#L120

Scott

On Nov 9, 5:56 pm, Wayne Meissner <wmeiss...@gmail.com> wrote:
> You can't pass ruby objects through C callbacks with FFI, so any
> variables you want to access from the callback have to be visible to
> the Proc when you create it.
>
> You seem to be mostly doing it correct with your data_handler() method
> - i.e. the _string parameter to data_handler() will be visible inside
> the proc callback, and you can just append the data to it.  The
> handler parameter to the callback will not be used (and is most likely
> nil anyway).
>
> I would change the first parameter (stream) of the curl handler to be
> of type pointer though, and get the data out like so:
>
>    _string << stream.get_string(0, size)
>
> I'm not sure if curl guarantees that the buffer is NUL terminated, but
> I suspect not, since it is binary data, so you only want to copy out
> as many bytes as curl indicates are ready (the size param).
>
> One _VERY_ important thing to remember, always keep a reference to the
> proc returned by data_handler somewhere - e.g. as an @variable in each
> Request instance.  FFI dynamically generates native code for the
> callback, and you need to keep a strong reference to it to avoid it
> being prematurely collected, and crashing the VM.  Stashing the proc
> somewhere for the lifetime of the Request instance should suffice.
>
> On 9 November 2010 10:30, Scott Gonyea <gon...@gmail.com> wrote:
>
>
>
> > I'm having a really painful time figuring this out.  I jumped onto
> > what NoKarma had already begun, with his curl-ffi library, and started
> > running with it.  I'm trying to emulate the ruby extension layers used
> > in some different Curl gems (Streamly and Patron, atm).
>
> > Curl wants you to pass a method reference, which it will then
> > callback.  You can see examples used in Streamly and Patron:
>
> > Streamly, lines 29-83:
> >https://github.com/aitrus/streamly/blob/master/ext/streamly.c#L29
>
> > Patron, lines 59-75 (Much simpler):
> >https://github.com/aitrus/patron/blob/master/ext/patron/session_ext.c...
>
> > Basically, they're allocating a buffer and providing a callback + that
> > buffer, which is sent to the callback. I've added this callback to
> > CurlFFI and I have the Proc working, etc... But I cannot seem to get
> > it to append to the string.
>
> > Callback Additions to CurlFFI:
> >https://github.com/aitrus/curl_ffi/blob/master/lib/bindings.rb#L923
> >https://github.com/aitrus/curl_ffi/blob/master/lib/bindings.rb#L926
>
> > I'll delete 926, as it's not necessary (I think).
>
> > Procs that get called:
> >https://github.com/aitrus/streamly/blob/master/lib/streamly/request.r...
>
> > I suppose the last resort can be to call C libraries, allocating /
> > freeing a string.  But that makes me think I'm doing it wrong.  I
> > can't imagine that I'm doing anything overly interesting with my code.
>
> > Scott