Same as previous commit but for OCaml. --- generator/generator | 230 ++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 117 deletions(-) diff --git a/generator/generator b/generator/generator index a031bd0..7f97163 100755 --- a/generator/generator +++ b/generator/generator @@ -5038,123 +5038,118 @@ let print_ocaml_flag_val { flag_prefix; flags } = pr "}\n"; pr "\n" +let print_ocaml_closure_wrapper { cbname; cbargs } = + let argnames = + List.map ( + function + | CBArrayAndLen (UInt32 n, _) | CBBytesIn (n, _) + | CBInt n | CBInt64 n + | CBMutable (Int n) | CBString n | CBUInt n | CBUInt64 n -> + n ^ "v" + | CBArrayAndLen _ | CBMutable _ -> assert false + ) cbargs in + + pr "/* Wrapper for %s callback. */\n" cbname; + pr "static int\n"; + pr "%s_wrapper_locked " cbname; + C.print_cbarg_list ~valid_flag:false cbargs; + pr "\n"; + pr "{\n"; + pr " CAMLparam0 ();\n"; + assert (List.length argnames <= 5); + pr " CAMLlocal%d (%s);\n" (List.length argnames) + (String.concat ", " argnames); + pr " CAMLlocal2 (fnv, rv);\n"; + pr " int r;\n"; + pr " value args[%d];\n" (List.length argnames); + pr "\n"; + + List.iter ( + function + | CBArrayAndLen (UInt32 n, count) -> + pr " %sv = nbd_internal_ocaml_alloc_int32_array (%s, %s);\n" + n n count; + | CBBytesIn (n, len) -> + pr " %sv = caml_alloc_string (%s);\n" n len; + pr " memcpy (String_val (%sv), %s, %s);\n" n n len + | CBInt n | CBUInt n -> + pr " %sv = Val_int (%s);\n" n n + | CBInt64 n -> + pr " %sv = caml_copy_int64 (%s);\n" n n + | CBString n -> + pr " %sv = caml_copy_string (%s);\n" n n + | CBUInt64 n -> + pr " %sv = caml_copy_int64 (%s);\n" n n + | CBMutable (Int n) -> + pr " %sv = caml_alloc_tuple (1);\n" n; + pr " Store_field (%sv, 0, Val_int (*%s));\n" n n + | CBArrayAndLen _ | CBMutable _ -> assert false + ) cbargs; + + List.iteri (fun i n -> pr " args[%d] = %s;\n" i n) argnames; + + pr " fnv = * (value *) user_data;\n"; + + pr " rv = caml_callbackN_exn (fnv, %d, args);\n" + (List.length argnames); + + List.iter ( + function + | CBArrayAndLen (UInt32 _, _) + | CBBytesIn _ + | CBInt _ + | CBInt64 _ + | CBString _ + | CBUInt _ + | CBUInt64 _ -> () + | CBMutable (Int n) -> + pr " *%s = Int_val (Field (%sv, 0));\n" n n + | CBArrayAndLen _ | CBMutable _ -> assert false + ) cbargs; + + pr " if (Is_exception_result (rv)) {\n"; + pr " /* XXX This is not really an error as callbacks can return\n"; + pr " * an error indication. But perhaps we should direct this\n"; + pr " * to a more suitable place or formalize what exception\n"; + pr " * means error versus unexpected failure.\n"; + pr " */\n"; + pr " fprintf (stderr,\n"; + pr " \"libnbd: uncaught OCaml exception: %%s\\n\",\n"; + pr " caml_format_exception (Extract_exception (rv)));\n"; + pr " CAMLreturnT (int, -1);\n"; + pr " }\n"; + + pr "\n"; + pr " r = Int_val (rv);\n"; + pr " assert (r >= 0);\n"; + pr " CAMLreturnT (int, r);\n"; + pr "}\n"; + pr "\n"; + pr "static int\n"; + pr "%s_wrapper " cbname; + C.print_cbarg_list cbargs; + pr "\n"; + pr "{\n"; + pr " int ret = 0;\n"; + pr "\n"; + pr " if (valid_flag & LIBNBD_CALLBACK_VALID) {\n"; + pr " caml_leave_blocking_section ();\n"; + pr " ret = %s_wrapper_locked " cbname; + C.print_cbarg_list ~valid_flag:false ~types:false cbargs; + pr ";\n"; + pr " caml_enter_blocking_section ();\n"; + pr " }\n"; + pr "\n"; + pr " if (valid_flag & LIBNBD_CALLBACK_FREE) {\n"; + pr " caml_remove_generational_global_root ((value *)user_data);\n"; + pr " free (user_data);\n"; + pr " }\n"; + pr "\n"; + pr " return ret;\n"; + pr "}\n"; + pr "\n" + let print_ocaml_binding (name, { args; optargs; ret }) = - (* Functions with a callback parameter require special handling. *) - List.iter ( - function - | Closure { cbname; cbargs } -> - let argnames = - List.map ( - function - | CBArrayAndLen (UInt32 n, _) | CBBytesIn (n, _) - | CBInt n | CBInt64 n - | CBMutable (Int n) | CBString n | CBUInt n | CBUInt64 n -> - n ^ "v" - | CBArrayAndLen _ | CBMutable _ -> assert false - ) cbargs in - - pr "/* Wrapper for %s callback of %s. */\n" cbname name; - pr "static int\n"; - pr "%s_%s_wrapper_locked " name cbname; - C.print_cbarg_list ~valid_flag:false cbargs; - pr "\n"; - pr "{\n"; - pr " CAMLparam0 ();\n"; - assert (List.length argnames <= 5); - pr " CAMLlocal%d (%s);\n" (List.length argnames) - (String.concat ", " argnames); - pr " CAMLlocal2 (fnv, rv);\n"; - pr " int r;\n"; - pr " value args[%d];\n" (List.length argnames); - pr "\n"; - - List.iter ( - function - | CBArrayAndLen (UInt32 n, count) -> - pr " %sv = nbd_internal_ocaml_alloc_int32_array (%s, %s);\n" - n n count; - | CBBytesIn (n, len) -> - pr " %sv = caml_alloc_string (%s);\n" n len; - pr " memcpy (String_val (%sv), %s, %s);\n" n n len - | CBInt n | CBUInt n -> - pr " %sv = Val_int (%s);\n" n n - | CBInt64 n -> - pr " %sv = caml_copy_int64 (%s);\n" n n - | CBString n -> - pr " %sv = caml_copy_string (%s);\n" n n - | CBUInt64 n -> - pr " %sv = caml_copy_int64 (%s);\n" n n - | CBMutable (Int n) -> - pr " %sv = caml_alloc_tuple (1);\n" n; - pr " Store_field (%sv, 0, Val_int (*%s));\n" n n - | CBArrayAndLen _ | CBMutable _ -> assert false - ) cbargs; - - List.iteri (fun i n -> pr " args[%d] = %s;\n" i n) argnames; - - pr " fnv = * (value *) user_data;\n"; - - pr " rv = caml_callbackN_exn (fnv, %d, args);\n" - (List.length argnames); - - List.iter ( - function - | CBArrayAndLen (UInt32 _, _) - | CBBytesIn _ - | CBInt _ - | CBInt64 _ - | CBString _ - | CBUInt _ - | CBUInt64 _ -> () - | CBMutable (Int n) -> - pr " *%s = Int_val (Field (%sv, 0));\n" n n - | CBArrayAndLen _ | CBMutable _ -> assert false - ) cbargs; - - pr " if (Is_exception_result (rv)) {\n"; - pr " /* XXX This is not really an error as callbacks can return\n"; - pr " * an error indication. But perhaps we should direct this\n"; - pr " * to a more suitable place or formalize what exception\n"; - pr " * means error versus unexpected failure.\n"; - pr " */\n"; - pr " fprintf (stderr,\n"; - pr " \"libnbd: uncaught OCaml exception: %%s\\n\",\n"; - pr " caml_format_exception (Extract_exception (rv)));\n"; - pr " CAMLreturnT (int, -1);\n"; - pr " }\n"; - - pr "\n"; - pr " r = Int_val (rv);\n"; - pr " assert (r >= 0);\n"; - pr " CAMLreturnT (int, r);\n"; - pr "}\n"; - pr "\n"; - pr "static int\n"; - pr "%s_%s_wrapper " name cbname; - C.print_cbarg_list cbargs; - pr "\n"; - pr "{\n"; - pr " int ret = 0;\n"; - pr "\n"; - pr " if (valid_flag & LIBNBD_CALLBACK_VALID) {\n"; - pr " caml_leave_blocking_section ();\n"; - pr " ret = %s_%s_wrapper_locked " name cbname; - C.print_cbarg_list ~valid_flag:false ~types:false cbargs; - pr ";\n"; - pr " caml_enter_blocking_section ();\n"; - pr " }\n"; - pr "\n"; - pr " if (valid_flag & LIBNBD_CALLBACK_FREE) {\n"; - pr " caml_remove_generational_global_root ((value *)user_data);\n"; - pr " free (user_data);\n"; - pr " }\n"; - pr "\n"; - pr " return ret;\n"; - pr "}\n"; - pr "\n" - | _ -> () - ) args; - (* Get the names of all the value arguments including the handle. *) let values = List.map ocaml_name_of_optarg optargs @ ["h"] @ @@ -5233,7 +5228,7 @@ let print_ocaml_binding (name, { args; optargs; ret }) = pr " if (%s_user_data == NULL) caml_raise_out_of_memory ();\n" cbname; pr " *%s_user_data = %sv;\n" cbname cbname; pr " caml_register_generational_global_root (%s_user_data);\n" cbname; - pr " const void *%s_callback = %s_%s_wrapper;\n" cbname name cbname + pr " const void *%s_callback = %s_wrapper;\n" cbname cbname | Enum (n, { enum_prefix }) -> pr " int %s = %s_val (%sv);\n" n enum_prefix n | Flags (n, { flag_prefix }) -> @@ -5352,6 +5347,7 @@ let generate_ocaml_nbd_c () = pr "#pragma GCC diagnostic ignored \"-Wmissing-prototypes\"\n"; pr "\n"; + List.iter print_ocaml_closure_wrapper all_closures; List.iter print_ocaml_enum_val all_enums; List.iter print_ocaml_flag_val all_flags; List.iter print_ocaml_binding handle_calls -- 2.22.0