X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=generator%2Fgenerator_ruby.ml;h=d0551573a1f11f116ddda47eadb5ecfacf7dd4b1;hb=25791edff58665a949807081d131ef74e74a2d7c;hp=84d10e0017668a3286551794649743ffc3d9741a;hpb=cf26ef818e918c8c32658399e8aa9e31289109a7;p=libguestfs.git diff --git a/generator/generator_ruby.ml b/generator/generator_ruby.ml index 84d10e0..d055157 100644 --- a/generator/generator_ruby.ml +++ b/generator/generator_ruby.ml @@ -55,6 +55,8 @@ static VALUE c_guestfs; /* guestfs_h handle */ static VALUE e_Error; /* used for all errors */ static void ruby_event_callback_wrapper (guestfs_h *g, void *data, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len); +static VALUE ruby_event_callback_wrapper_wrapper (VALUE argv); +static VALUE ruby_event_callback_handle_exception (VALUE not_used, VALUE exn); static VALUE **get_all_event_callbacks (guestfs_h *g, size_t *len_rtn); static void @@ -213,6 +215,7 @@ ruby_event_callback_wrapper (guestfs_h *g, { size_t i; VALUE eventv, event_handlev, bufv, arrayv; + VALUE argv[5]; eventv = ULL2NUM (event); event_handlev = INT2NUM (event_handle); @@ -223,12 +226,55 @@ ruby_event_callback_wrapper (guestfs_h *g, for (i = 0; i < array_len; ++i) rb_ary_push (arrayv, ULL2NUM (array[i])); - /* XXX If the Ruby callback raises any sort of exception then - * it causes the process to segfault. I don't understand how - * to catch exceptions here. + /* This is a crap limitation of rb_rescue. + * http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/~poffice/mail/ruby-talk/65698 */ - rb_funcall (*(VALUE *) data, rb_intern (\"call\"), 4, - eventv, event_handlev, bufv, arrayv); + argv[0] = * (VALUE *) data; /* function */ + argv[1] = eventv; + argv[2] = event_handlev; + argv[3] = bufv; + argv[4] = arrayv; + + rb_rescue (ruby_event_callback_wrapper_wrapper, (VALUE) argv, + ruby_event_callback_handle_exception, Qnil); +} + +static VALUE +ruby_event_callback_wrapper_wrapper (VALUE argvv) +{ + VALUE *argv = (VALUE *) argvv; + VALUE fn, eventv, event_handlev, bufv, arrayv; + + fn = argv[0]; + + /* Check the Ruby callback still exists. For reasons which are not + * fully understood, even though we registered this as a global root, + * it is still possible for the callback to go away (fn value remains + * but its type changes from T_DATA to T_NONE). (RHBZ#733297) + */ + if (rb_type (fn) != T_NONE) { + eventv = argv[1]; + event_handlev = argv[2]; + bufv = argv[3]; + arrayv = argv[4]; + + rb_funcall (fn, rb_intern (\"call\"), 4, + eventv, event_handlev, bufv, arrayv); + } + + return Qnil; +} + +static VALUE +ruby_event_callback_handle_exception (VALUE not_used, VALUE exn) +{ + /* Callbacks aren't supposed to throw exceptions. The best we + * can do is to print the error. + */ + fprintf (stderr, \"libguestfs: exception in callback: %%s\\n\", + StringValueCStr (exn)); + + return Qnil; } static VALUE **