Forum: Ruby-core "fiber called across trap" - why would this be bad?

Posted by James Fairbairn (Guest)
on 2009-08-17 18:44
(Received via mailing list)
Hello,

I have a C program that embeds Ruby 1.9.1. When I call into the Ruby 
interpreter, and Ruby yield()s an object from a fiber back to my C 
program, then later call back the object from C, which causes the fiber 
to be resume()d, it causes a Ruby error with message "fiber called 
across trap".

If I comment out the relevant code in Ruby's cont.c (lines 876-877), the 
above case works fine. My question is, what is the danger of not doing 
the "fiber called across trap" check, or what is the badness that this 
check is protecting from? I know nothing about the Ruby VM, so go easy 
on me. :-)

If you want to know why I'm doing this, please read on. If this is a 
dumb way to be doing things, can anyone tell me what I should be doing 
instead of resuming fibers across C calls?

--8<----

First, my C program calls out to the Ruby interpreter with something 
like

  rb_funcall(obj, rb_intern("call"), argc, args...);

Ruby does some "business logic" processing then returns a Ruby array to 
C (actually yield()ed from a fiber) like this:

  [REQ_DB, query_str, callback_obj, callback_method]

The C program (the "server") then saves the pointers to callback_obj and 
callback_method, turns query_str into a query, and sends it to our 
internal database in a non-blocking fashion.

[There are also other response types, like REQ_HTTP (which performs a 
non-blocking HTTP request to a backend web service).]

On receiving the response from the database, the server then calls Ruby 
back with the result of the query as a Ruby string:

  rb_funcall(callback_obj, SYM2ID(callback_method), 
INT2FIX(db_result_code),
             rb_str_new(db_result_start, 
db_result_end-db_result_start));

This callback results in a call to resume() on the fiber that yielded 
(and was wrapped and docked into a Hash of in-flight requests).

The intention is that in Ruby we can write code that looks like:

  def dostuff
    return something_based_on(req_db(query_string1), 
req_db(query_string2))
  end

rather than

  def dostuff
    req_db(query_string1, self, :handle_query1)
  end

  def handle_query1(resultset1)
    @resultset1 = resultset1 # ugh.
    req_db(query_string2, self, :handle_query2)
  end

  def handle_query2(resultset2)
    return something_based_on(@resultset1, resultset2) # ugh!
  end

Thanks for reading,

James


Please consider the environment before printing this email :-)

This email and any files transmitted with it are confidential and 
intended solely for the use of the individual or entity to whom they are 
addressed.  If you have received this email in error please notify the 
sender immediately then delete this email.  Any views expressed in this 
email are solely that of the individual and not representative of the 
company as a whole.

Media Molecule Limited
Company Reg No 5665849
Registered in England.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.