X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=generator%2Fgenerator_ruby.ml;h=1f75b46012c91138655aba833b2e826d23cead00;hp=8be9369452e1583c5c26b3c175efec98e25173a6;hb=HEAD;hpb=c50ed37b71a50b2570a3b16a82a9d73e026be739 diff --git a/generator/generator_ruby.ml b/generator/generator_ruby.ml index 8be9369..1f75b46 100644 --- a/generator/generator_ruby.ml +++ b/generator/generator_ruby.ml @@ -50,11 +50,22 @@ let rec generate_ruby_c () = #define RARRAY_LEN(r) (RARRAY((r))->len) #endif +/* For Ruby < 1.8 */ +#ifndef RSTRING_LEN +#define RSTRING_LEN(r) (RSTRING((r))->len) +#endif + +#ifndef RSTRING_PTR +#define RSTRING_PTR(r) (RSTRING((r))->ptr) +#endif + static VALUE m_guestfs; /* guestfs module */ 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 @@ -82,6 +93,7 @@ ruby_guestfs_free (void *gvp) rb_gc_unregister_address (roots[i]); free (roots[i]); } + free (roots); } } @@ -213,6 +225,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 +236,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 + */ + 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. */ - rb_funcall (*(VALUE *) data, rb_intern (\"call\"), 4, - eventv, event_handlev, bufv, arrayv); + fprintf (stderr, \"libguestfs: exception in callback: %%s\\n\", + StringValueCStr (exn)); + + return Qnil; } static VALUE ** @@ -264,6 +320,26 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) return r; } +/* + * call-seq: + * g.user_cancel() -> nil + * + * Call + * +guestfs_user_cancel+[http://libguestfs.org/guestfs.3.html#guestfs_user_cancel] + * to cancel the current transfer. This is safe to call from Ruby + * signal handlers and threads. + */ +static VALUE +ruby_user_cancel (VALUE gv) +{ + guestfs_h *g; + + Data_Get_Struct (gv, guestfs_h, g); + if (g) + guestfs_user_cancel (g); + return Qnil; +} + "; List.iter ( @@ -280,10 +356,6 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) doc ^ "\n\n" ^ protocol_limit_warning else doc in let doc = - if List.mem DangerWillRobinson flags then - doc ^ "\n\n" ^ danger_will_robinson - else doc in - let doc = match deprecation_notice flags with | None -> doc | Some txt -> doc ^ "\n\n" ^ txt in @@ -354,11 +426,11 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) pr " const char *%s = StringValueCStr (%sv);\n" n n; | BufferIn n -> pr " Check_Type (%sv, T_STRING);\n" n; - pr " const char *%s = RSTRING (%sv)->ptr;\n" n n; + pr " const char *%s = RSTRING_PTR (%sv);\n" n n; pr " if (!%s)\n" n; pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n"; pr " \"%s\", \"%s\");\n" n name; - pr " size_t %s_size = RSTRING (%sv)->len;\n" n n + pr " size_t %s_size = RSTRING_LEN (%sv);\n" n n | OptString n -> pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n | StringList n | DeviceList n -> @@ -367,7 +439,7 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) pr " {\n"; pr " size_t i, len;\n"; pr " len = RARRAY_LEN (%sv);\n" n; - pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n" + pr " %s = ALLOC_N (char *, len+1);\n" n; pr " for (i = 0; i < len; ++i) {\n"; pr " VALUE v = rb_ary_entry (%sv, i);\n" n; @@ -395,20 +467,19 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) pr " VALUE v;\n"; List.iter ( fun argt -> - let n = name_of_argt argt in + let n = name_of_optargt argt in let uc_n = String.uppercase n in pr " v = rb_hash_lookup (optargsv, ID2SYM (rb_intern (\"%s\")));\n" n; pr " if (v != Qnil) {\n"; (match argt with - | Bool n -> + | OBool n -> pr " optargs_s.%s = RTEST (v);\n" n; - | Int n -> + | OInt n -> pr " optargs_s.%s = NUM2INT (v);\n" n; - | Int64 n -> + | OInt64 n -> pr " optargs_s.%s = NUM2LL (v);\n" n; - | String _ -> + | OString _ -> pr " optargs_s.%s = StringValueCStr (v);\n" n - | _ -> assert false ); pr " optargs_s.bitmask |= GUESTFS_%s_%s_BITMASK;\n" uc_name uc_n; pr " }\n"; @@ -531,6 +602,8 @@ void Init__guestfs () ruby_set_event_callback, 2); rb_define_method (c_guestfs, \"delete_event_callback\", ruby_delete_event_callback, 1); + rb_define_method (c_guestfs, \"user_cancel\", + ruby_user_cancel, 0); ";