Subject:
Re: [ruby-ffi] SystemStackError of callback
From:
Wayne Meissner
Date:
7/2/10 1:05 AM
To:
ruby-ffi@googlegroups.com

There are a few problems in your code.

1) Using a block as an async callback won't work, and could
potentially crash the VM.  You need to instantiate it as a Proc or
Function and keep a strong ref to that object.
e.g.

cb = Proc.new do |a, b|
   100.times do |d|
       puts a, b.read_int
   end
end
async_call(cb, 1, p)


2) Your native function passes a pointer to data on its stack to the
newly created thread.  This is a really bad thing, since the new
thread might start running after the native function has returned, and
that stack space has been re-used for some other data.

You could use malloc in async_call(), and free in call() to manage that data.


3) Make sure you're using the latest FFI code from github with
ruby-1.9, or JRuby.  Callbacks from non-ruby threads were not properly
supported in earlier versions (up to and including 0.6.3).  JRuby has
always been fine though.  Ruby 1.8 won't work at all with callbacks
from non-ruby threads, and could result in undefined behaviour and/or
crashes.

On 2 July 2010 00:40, tlayboy <tlayboy@gmail.com> wrote:
> Hi all,
>
> I am in troble with SystemStackError of callback.
> Does anyone know why this error is occured?
>
> My code is like this.
>
> ############################
> C library
> ############################
> typedef void (*callback)(int, void *);
> pthread_t thread;
> struct cb_info info;
>
> struct cb_info {
>        callback cb;
>        int data;
>        void *p;
> };
>
> void *call(void *data)
> {
>        struct cb_info *info = (struct cb_info *)data;
>        info->cb(info->data, info->p);
> }
>
> void async_call(callback cb, unsigned int data, void *p)
> {
>        int ret;
>
>        info.cb = rcb;
>        info.data = data;
>        info.p = p;
>
>        if ((ret = pthread_create(&thread, NULL, call, (void *)&info)) != 0)
> {
>                perror("ptherad_create");
>                exit(EXIT_FAILURE);
>        }
> }
>
> ############################
> Ruby Code
> ############################
> p = FFI::MemoryPointer.new(:int)
> p.write_int(2)
>
> async_call(1, p) do |a, b|
>        100.times do |d|
>                puts a, b.read_int
>        end
> end
>
> ############################
> Output
> ############################
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> 1
> 2
> /usr/lib/ruby/1.8/pp.rb:133:in `pp': stack level too deep
> (SystemStackError)
>        from /usr/lib/ruby/1.8/pp.rb:77:in `pp'
>        from /usr/lib/ruby/1.8/pp.rb:119:in `guard_inspect_key'
>        from /usr/lib/ruby/1.8/pp.rb:77:in `pp'
>        from /usr/lib/ruby/1.8/pp.rb:60:in `pp'
>        from /usr/lib/ruby/1.8/pp.rb:59:in `each'
>        from /usr/lib/ruby/1.8/pp.rb:59:in `pp'
>        from libcb.rb:35
>        from (eval):6:in `call'
>        from (eval):6:in `async_call'
>        from libcb.rb:34
>        from libcb.rb:33:in `times'
>        from libcb.rb:33
>
> thank you,
>