An optional Closure parameter, but otherwise works the same way as Closure. --- generator/generator | 57 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/generator/generator b/generator/generator index 8cf95b6..8f15786 100755 --- a/generator/generator +++ b/generator/generator @@ -867,6 +867,7 @@ and arg = | UInt32 of string (* 32 bit unsigned int *) | UInt64 of string (* 64 bit unsigned int *) and optarg = +| OClosure of closure (* optional closure *) | OFlags of string * flags (* optional flags, uint32_t in C *) and ret = | RBool (* return a boolean, or error *) @@ -3184,16 +3185,6 @@ end = struct (* Check the API definition. *) let () = - (* Currently optargs can only be [] or [OFlags]. This condition - * will be relaxed later when we support more optional arguments. - *) - List.iter ( - function - | _, { optargs = [] } | _, { optargs = [OFlags _] } -> () - | (name, _) -> - failwithf "%s: optargs can only be empty list or [OFlags]" name - ) handle_calls; - (* Check functions using may_set_error. *) List.iter ( function @@ -3226,7 +3217,8 @@ let () = | name, { optargs; may_set_error = false } when List.exists (function - | OFlags _ -> true) optargs -> + | OFlags _ -> true + | _ -> false) optargs -> failwithf "%s: if optargs contains an OFlags parameter, may_set_error must be false" name | _ -> () @@ -3388,6 +3380,12 @@ let rec print_arg_list ?(handle = false) ?(types = true) args optargs = if !comma then pr ", "; comma := true; match optarg with + | OClosure { cbname; cbargs } -> + if types then pr "nbd_%s_callback " cbname; + pr "%s_callback" cbname; + pr ", "; + if types then pr "void *"; + pr "%s_user_data" cbname | OFlags (n, _) -> if types then pr "uint32_t "; pr "%s" n @@ -3718,6 +3716,7 @@ let generate_lib_api_c () = ) args; List.iter ( function + | OClosure _ -> () | OFlags (n, flags) -> print_flags_check n flags ) optargs; @@ -3767,6 +3766,7 @@ let generate_lib_api_c () = ) args; List.iter ( function + | OClosure { cbname } -> pr " %s=%%s" cbname | OFlags (n, _) -> pr " %s=0x%%x" n ) optargs; pr "\""; @@ -3789,6 +3789,7 @@ let generate_lib_api_c () = ) args; List.iter ( function + | OClosure { cbname } -> pr ", %s_callback ? \"<fun>\" : \"NULL\"" cbname | OFlags (n, _) -> pr ", %s" n ) optargs; pr ");\n" @@ -4297,6 +4298,8 @@ let print_python_binding name { args; optargs; ret; may_set_error } = ) args; List.iter ( function + | OClosure { cbname } -> + pr " PyObject *%s_user_data;\n" cbname | OFlags (n, _) -> pr " uint32_t %s_u32;\n" n; pr " unsigned int %s; /* really uint32_t */\n" n @@ -4327,6 +4330,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = ) args; List.iter ( function + | OClosure _ -> pr " \"O\"" | OFlags _ -> pr " \"I\"" ) optargs; pr "\n"; @@ -4353,6 +4357,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = ) args; List.iter ( function + | OClosure { cbname } -> pr ", &%s_user_data" cbname | OFlags (n, _) -> pr ", &%s" n ) optargs; pr "))\n"; @@ -4394,6 +4399,16 @@ let print_python_binding name { args; optargs; ret; may_set_error } = ) args; List.iter ( function + | OClosure { cbname } -> + pr " if (%s_user_data != Py_None) {\n" cbname; + pr " /* Increment refcount since pointer may be saved by libnbd. */\n"; + pr " Py_INCREF (%s_user_data);\n" cbname; + pr " if (!PyCallable_Check (%s_user_data)) {\n" cbname; + pr " PyErr_SetString (PyExc_TypeError,\n"; + pr " \"callback parameter %s is not callable\");\n" cbname; + pr " return NULL;\n"; + pr " }\n"; + pr " }\n" | OFlags (n, _) -> pr " %s_u32 = %s;\n" n n ) optargs; @@ -4423,6 +4438,9 @@ let print_python_binding name { args; optargs; ret; may_set_error } = ) args; List.iter ( function + | OClosure { cbname } -> + pr ", %s_user_data ? %s_wrapper : NULL" cbname cbname; + pr ", %s_user_data" cbname | OFlags (n, _) -> pr ", %s_u32" n ) optargs; pr ");\n"; @@ -4679,6 +4697,7 @@ class NBD (object): let optargs = List.map ( function + | OClosure { cbname } -> cbname, Some "None", None | OFlags (n, _) -> n, Some "0", None ) optargs in let args = args @ optargs in @@ -4767,6 +4786,8 @@ and ocaml_ret_to_string = function | RUInt -> "int" and ocaml_optarg_to_string = function + | OClosure { cbname; cbargs } -> + sprintf "?%s:(%s)" cbname (ocaml_closuredecl_to_string cbargs) | OFlags (n, { flag_prefix }) -> sprintf "?%s:%s.t list" n flag_prefix and ocaml_closuredecl_to_string cbargs = @@ -4805,6 +4826,7 @@ let ocaml_name_of_arg = function | UInt64 n -> n let ocaml_name_of_optarg = function + | OClosure { cbname } -> cbname | OFlags (n, _) -> n let num_params args optargs = @@ -5213,6 +5235,19 @@ let print_ocaml_binding (name, { args; optargs; ret }) = List.iter ( function + | OClosure { cbname } -> + pr " const void *%s_callback = NULL;\n" cbname; + pr " value *%s_user_data = NULL;\n" cbname; + pr " if (%sv != Val_int (0)) { /* Some closure */\n" cbname; + pr " /* The function may save a reference to the closure, so we\n"; + pr " * must treat it as a possible GC root.\n"; + pr " */\n"; + pr " %s_user_data = malloc (sizeof (value));\n" cbname; + pr " if (%s_user_data == NULL) caml_raise_out_of_memory ();\n" cbname; + pr " *%s_user_data = Field (%sv, 0);\n" cbname cbname; + pr " caml_register_generational_global_root (%s_user_data);\n" cbname; + pr " %s_callback = %s_wrapper;\n" cbname cbname; + pr " }\n"; | OFlags (n, { flag_prefix }) -> pr " uint32_t %s;\n" n; pr " if (%sv != Val_int (0)) /* Some [ list of %s.t ] */\n" -- 2.22.0