Simple refactoring to use a struct to store the function pointer passed to the callback wrapper. --- generator/generator | 69 ++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/generator/generator b/generator/generator index 16729cd..f6a4856 100755 --- a/generator/generator +++ b/generator/generator @@ -3979,6 +3979,7 @@ let print_python_closure_wrapper { cbname; cbargs } = C.print_cbarg_list cbargs; pr "\n"; pr "{\n"; + pr " const struct user_data *data = user_data;\n"; pr " int ret = 0;\n"; pr "\n"; pr " PyGILState_STATE py_save = PyGILState_UNLOCKED;\n"; @@ -4037,7 +4038,7 @@ let print_python_closure_wrapper { cbname; cbargs } = pr " if (PyEval_ThreadsInitialized ())\n"; pr " py_save = PyGILState_Ensure ();\n"; pr "\n"; - pr " py_ret = PyObject_CallObject ((PyObject *)user_data, py_args);\n"; + pr " py_ret = PyObject_CallObject (data->fn, py_args);\n"; pr "\n"; pr " if (PyEval_ThreadsInitialized ())\n"; pr " PyGILState_Release (py_save);\n"; @@ -4074,13 +4075,6 @@ let print_python_closure_wrapper { cbname; cbargs } = ) cbargs; pr " return ret;\n"; pr "}\n"; - pr "\n"; - pr "/* Free for %s callback. */\n" cbname; - pr "static void\n"; - pr "%s_free (void *user_data)\n" cbname; - pr "{\n"; - pr " Py_DECREF (user_data);\n"; - pr "}\n"; pr "\n" (* Generate the Python binding. *) @@ -4106,8 +4100,12 @@ let print_python_binding name { args; optargs; ret; may_set_error } = n; pr " struct py_aio_buffer *%s_buf;\n" n | Closure { cbname } -> - pr " nbd_%s_callback %s = { .callback = %s_wrapper, .free = %s_free };\n" - cbname cbname cbname cbname + pr " struct user_data *%s_user_data = alloc_user_data ();\n" cbname; + pr " if (%s_user_data == NULL) return NULL;\n" cbname; + pr " nbd_%s_callback %s = { .callback = %s_wrapper,\n" + cbname cbname cbname; + pr " .user_data = %s_user_data,\n" cbname; + pr " .free = free_user_data };\n" | Enum (n, _) -> pr " int %s;\n" n | Flags (n, _) -> pr " uint32_t %s_u32;\n" n; @@ -4139,8 +4137,12 @@ let print_python_binding name { args; optargs; ret; may_set_error } = List.iter ( function | OClosure { cbname } -> - pr " nbd_%s_callback %s = { .callback = %s_wrapper, .free = %s_free };\n" - cbname cbname cbname cbname + pr " struct user_data *%s_user_data = alloc_user_data ();\n" cbname; + pr " if (%s_user_data == NULL) return NULL;\n" cbname; + pr " nbd_%s_callback %s = { .callback = %s_wrapper,\n" + cbname cbname cbname; + pr " .user_data = %s_user_data,\n" cbname; + pr " .free = free_user_data };\n" | OFlags (n, _) -> pr " uint32_t %s_u32;\n" n; pr " unsigned int %s; /* really uint32_t */\n" n @@ -4183,7 +4185,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = | BytesIn (n, _) | BytesPersistIn (n, _) | BytesPersistOut (n, _) -> pr ", &%s" n | BytesOut (_, count) -> pr ", &%s" count - | Closure { cbname } -> pr ", &%s.user_data" cbname + | Closure { cbname } -> pr ", &%s_user_data->fn" cbname | Enum (n, _) -> pr ", &%s" n | Flags (n, _) -> pr ", &%s" n | Int n -> pr ", &%s" n @@ -4198,7 +4200,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } = ) args; List.iter ( function - | OClosure { cbname } -> pr ", &%s.user_data" cbname + | OClosure { cbname } -> pr ", &%s_user_data->fn" cbname | OFlags (n, _) -> pr ", &%s" n ) optargs; pr "))\n"; @@ -4215,8 +4217,8 @@ let print_python_binding name { args; optargs; ret; may_set_error } = pr " %s_buf = nbd_internal_py_get_aio_buffer (%s);\n" n n | Closure { 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 " Py_INCREF (%s_user_data->fn);\n" cbname; + pr " if (!PyCallable_Check (%s_user_data->fn)) {\n" cbname; pr " PyErr_SetString (PyExc_TypeError,\n"; pr " \"callback parameter %s is not callable\");\n" cbname; pr " return NULL;\n"; @@ -4241,10 +4243,10 @@ let print_python_binding name { args; optargs; ret; may_set_error } = List.iter ( function | OClosure { cbname } -> - pr " if (%s.user_data != Py_None) {\n" cbname; + pr " if (%s_user_data->fn != 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 " Py_INCREF (%s_user_data->fn);\n" cbname; + pr " if (!PyCallable_Check (%s_user_data->fn)) {\n" cbname; pr " PyErr_SetString (PyExc_TypeError,\n"; pr " \"callback parameter %s is not callable\");\n" cbname; pr " return NULL;\n"; @@ -4377,6 +4379,35 @@ let generate_python_methods_c () = pr "\n"; pr "#include <methods.h>\n"; pr "\n"; + + pr "/* This is passed to *_wrapper as the user_data pointer"; + pr " * and freed in the free_user_data function below.\n"; + pr " */\n"; + pr "struct user_data {\n"; + pr " PyObject *fn; /* Pointer to Python function. */\n"; + pr "};\n"; + pr "\n"; + pr "static struct user_data *\n"; + pr "alloc_user_data (void)\n"; + pr "{\n"; + pr " struct user_data *data = calloc (1, sizeof *data);\n"; + pr " if (data == NULL) {\n"; + pr " PyErr_NoMemory ();\n"; + pr " return NULL;\n"; + pr " }\n"; + pr " return data;\n"; + pr "}\n"; + pr "\n"; + pr "static void\n"; + pr "free_user_data (void *user_data)\n"; + pr "{\n"; + pr " struct user_data *data = user_data;\n"; + pr "\n"; + pr " Py_DECREF (data->fn);\n"; + pr " free (data);\n"; + pr "}\n"; + pr "\n"; + List.iter print_python_closure_wrapper all_closures; List.iter ( fun (name, fn) -> -- 2.22.0