[Libguestfs] [libnbd PATCH v3 1/5] python: Simplify passing of mutable *error to callbacks

Richard W.M. Jones rjones at redhat.com
Thu Jun 9 14:22:42 UTC 2022


On Thu, Jun 09, 2022 at 08:34:43AM -0500, Eric Blake wrote:
> Instead of open-coding our code to create a PyObject wrapper of the
> mutable *error to be passed to each callback, extract this into a
> helper function.  We can then slightly optimize things to hang on to a
> single pointer to the ctypes module, rather than looking it up on
> every callback.  The generated code shrinks by more than the added
> code in utils.c:
> 
> | --- python/methods.h.bak	2022-06-08 14:35:00.454786844 -0500
> | +++ python/methods.h	2022-06-08 14:43:24.681596853 -0500
> | @@ -35,6 +35,7 @@
> |  extern PyObject *nbd_internal_py_get_aio_view (PyObject *, bool);
> |  extern int nbd_internal_py_init_aio_buffer (PyObject *);
> |  extern PyObject *nbd_internal_py_get_nbd_buffer_type (void);
> | +extern PyObject *nbd_internal_py_wrap_errptr (int);
> |
> |  static inline struct nbd_handle *
> |  get_handle (PyObject *obj)
> | --- python/methods.c.bak	2022-06-08 14:35:00.450786838 -0500
> | +++ python/methods.c	2022-06-08 14:43:24.696596877 -0500
> | @@ -75,13 +75,7 @@ chunk_wrapper (void *user_data, const vo
> |    PyObject *py_args, *py_ret;
> |    PyObject *py_error = NULL;
> |
> | -  PyObject *py_error_modname = PyUnicode_FromString ("ctypes");
> | -  if (!py_error_modname) { PyErr_PrintEx (0); goto out; }
> | -  PyObject *py_error_mod = PyImport_Import (py_error_modname);
> | -  Py_DECREF (py_error_modname);
> | -  if (!py_error_mod) { PyErr_PrintEx (0); goto out; }
> | -  py_error = PyObject_CallMethod (py_error_mod, "c_int", "i", *error);
> | -  Py_DECREF (py_error_mod);
> | +  py_error = nbd_internal_py_wrap_errptr (*error);
> |    if (!py_error) { PyErr_PrintEx (0); goto out; }
> |
> |    py_args = Py_BuildValue ("(y#KIO)", subbuf, (int) count, offset, status,
> | @@ -132,13 +126,7 @@ completion_wrapper (void *user_data, int
> |    PyObject *py_args, *py_ret;
> |    PyObject *py_error = NULL;
> |
> | -  PyObject *py_error_modname = PyUnicode_FromString ("ctypes");
> | -  if (!py_error_modname) { PyErr_PrintEx (0); goto out; }
> | -  PyObject *py_error_mod = PyImport_Import (py_error_modname);
> | -  Py_DECREF (py_error_modname);
> | -  if (!py_error_mod) { PyErr_PrintEx (0); goto out; }
> | -  py_error = PyObject_CallMethod (py_error_mod, "c_int", "i", *error);
> | -  Py_DECREF (py_error_mod);
> | +  py_error = nbd_internal_py_wrap_errptr (*error);
> |    if (!py_error) { PyErr_PrintEx (0); goto out; }
> |
> |    py_args = Py_BuildValue ("(O)", py_error);
> | @@ -239,13 +227,7 @@ extent_wrapper (void *user_data, const c
> |      if (!py_e_entries) { PyErr_PrintEx (0); goto out; }
> |      PyList_SET_ITEM (py_entries, i_entries, py_e_entries);
> |    }
> | -  PyObject *py_error_modname = PyUnicode_FromString ("ctypes");
> | -  if (!py_error_modname) { PyErr_PrintEx (0); goto out; }
> | -  PyObject *py_error_mod = PyImport_Import (py_error_modname);
> | -  Py_DECREF (py_error_modname);
> | -  if (!py_error_mod) { PyErr_PrintEx (0); goto out; }
> | -  py_error = PyObject_CallMethod (py_error_mod, "c_int", "i", *error);
> | -  Py_DECREF (py_error_mod);
> | +  py_error = nbd_internal_py_wrap_errptr (*error);
> |    if (!py_error) { PyErr_PrintEx (0); goto out; }
> |
> |    py_args = Py_BuildValue ("(sKOO)", metacontext, offset, py_entries,
> ---
>  generator/Python.ml |  9 ++-------
>  python/utils.c      | 19 +++++++++++++++++++
>  2 files changed, 21 insertions(+), 7 deletions(-)
> 
> diff --git a/generator/Python.ml b/generator/Python.ml
> index e94f37b..6980034 100644
> --- a/generator/Python.ml
> +++ b/generator/Python.ml
> @@ -41,6 +41,7 @@ let
>  extern PyObject *nbd_internal_py_get_aio_view (PyObject *, bool);
>  extern int nbd_internal_py_init_aio_buffer (PyObject *);
>  extern PyObject *nbd_internal_py_get_nbd_buffer_type (void);
> +extern PyObject *nbd_internal_py_wrap_errptr (int);
> 
>  static inline struct nbd_handle *
>  get_handle (PyObject *obj)
> @@ -184,13 +185,7 @@ let
>      | CBInt _
>      | CBInt64 _ -> ()
>      | CBMutable (Int n) ->
> -       pr "  PyObject *py_%s_modname = PyUnicode_FromString (\"ctypes\");\n" n;
> -       pr "  if (!py_%s_modname) { PyErr_PrintEx (0); goto out; }\n" n;
> -       pr "  PyObject *py_%s_mod = PyImport_Import (py_%s_modname);\n" n n;
> -       pr "  Py_DECREF (py_%s_modname);\n" n;
> -       pr "  if (!py_%s_mod) { PyErr_PrintEx (0); goto out; }\n" n;
> -       pr "  py_%s = PyObject_CallMethod (py_%s_mod, \"c_int\", \"i\", *%s);\n" n n n;
> -       pr "  Py_DECREF (py_%s_mod);\n" n;
> +       pr "  py_%s = nbd_internal_py_wrap_errptr (*%s);\n" n n;
>         pr "  if (!py_%s) { PyErr_PrintEx (0); goto out; }\n" n;
>      | CBString _
>      | CBUInt _
> diff --git a/python/utils.c b/python/utils.c
> index e0df181..cd44b90 100644
> --- a/python/utils.c
> +++ b/python/utils.c
> @@ -173,3 +173,22 @@ nbd_internal_py_get_nbd_buffer_type (void)
>    }
>    return type;
>  }
> +
> +/* Helper to package callback *error into modifiable PyObject */
> +PyObject *
> +nbd_internal_py_wrap_errptr (int err)
> +{
> +  static PyObject *py_ctypes_mod;
> +
> +  if (!py_ctypes_mod) {
> +    PyObject *py_modname = PyUnicode_FromString ("ctypes");
> +    if (!py_modname)
> +      return NULL;
> +    py_ctypes_mod = PyImport_Import (py_modname);
> +    Py_DECREF (py_modname);
> +    if (!py_ctypes_mod)
> +      return NULL;
> +  }
> +
> +  return PyObject_CallMethod (py_ctypes_mod, "c_int", "i", err);
> +}

I guess because of the Python GIL we don't need locking here?

We don't run the Python tests with valgrinding so there should be no
issue there.

Reviewed-by: Richard W.M. Jones <rjones at redhat.com>

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org


More information about the Libguestfs mailing list