--- generator/generator | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/generator/generator b/generator/generator index f6a4856..9bcb08d 100755 --- a/generator/generator +++ b/generator/generator @@ -3982,6 +3982,13 @@ let print_python_closure_wrapper { cbname; cbargs } = pr " const struct user_data *data = user_data;\n"; pr " int ret = 0;\n"; pr "\n"; + pr " /* The C callback is always registered, even if there's no Python\n"; + pr " * callback. This is because we may need to unregister an\n"; + pr " * associated persistent buffer.\n"; + pr " */\n"; + pr " if (data->fn == NULL)\n"; + pr " return 0;\n"; + pr "\n"; pr " PyGILState_STATE py_save = PyGILState_UNLOCKED;\n"; pr " PyObject *py_args, *py_ret;\n"; List.iter ( @@ -4253,10 +4260,24 @@ let print_python_binding name { args; optargs; ret; may_set_error } = pr " }\n"; pr " }\n"; pr " else\n"; - pr " %s.callback = NULL; /* we're not going to call it */\n" cbname + pr " %s_user_data->fn = NULL;\n" cbname | OFlags (n, _) -> pr " %s_u32 = %s;\n" n n ) optargs; + (* If there is a BytesPersistIn/Out parameter then we need to + * increment the refcount and save the pointer into + * completion_callback.user_data so we can decrement the + * refcount on command completion. + *) + List.iter ( + function + | BytesPersistIn (n, _) | BytesPersistOut (n, _) -> + pr " /* Increment refcount since buffer may be saved by libnbd. */\n"; + pr " Py_INCREF (%s);\n" n; + pr " completion_user_data->buf = %s;\n" n; + | _ -> () + ) args; + (* Call the underlying C function. *) pr " ret = nbd_%s (h" name; List.iter ( @@ -4384,7 +4405,8 @@ let generate_python_methods_c () = 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 " PyObject *fn; /* Optional pointer to Python function. */\n"; + pr " PyObject *buf; /* Optional pointer to persistent buffer. */\n"; pr "};\n"; pr "\n"; pr "static struct user_data *\n"; @@ -4403,7 +4425,10 @@ let generate_python_methods_c () = pr "{\n"; pr " struct user_data *data = user_data;\n"; pr "\n"; - pr " Py_DECREF (data->fn);\n"; + pr " if (data->fn != NULL)\n"; + pr " Py_DECREF (data->fn);\n"; + pr " if (data->buf != NULL)\n"; + pr " Py_DECREF (data->buf);\n"; pr " free (data);\n"; pr "}\n"; pr "\n"; -- 2.22.0