To use rb_protect flexible way (for example, to call the Ruby function with an arbitrary number of arguments), pass the small dispatch function rb_protect . Ruby requires that sizeof(VALUE) == sizeof(void*) and rb_protect blindly pass VALUE data to the send function without checking or changing. This means that you can transfer any data you want for the send function, allow them to unpack the data, and call the appropriate Ruby methods.
For example, to rb_protect call the Ruby method, you can use something like this:
#define MAX_ARGS 16 struct my_callback_stuff { VALUE obj; ID method_id; int nargs; VALUE args[MAX_ARGS]; }; VALUE my_callback_dispatch(VALUE rdata) { struct my_callback_stuff* data = (struct my_callback_stuff*) rdata; return rb_funcall2(data->obj, data->method_id, data->nargs, data->args); } ... in some other function ... { struct my_callback_stuff stuff; stuff.obj = the_object_to_call; stuff.method_id = rb_intern("the_method_id"); stuff.nargs = 3; stuff.args[0] = INT2FIX(1); stuff.args[1] = INT2FIX(2); stuff.args[2] = INT2FIX(3); int state = 0; VALUE ret = rb_protect(my_callback_dispatch, (VALUE)(&stuff), &state); if (state) { } }
Also, keep in mind that rb_rescue or rb_ensure may be the best approach for some problems.
source share