[Libguestfs] [PATCH nbdkit 3/4] python: Allow thread model to be set from Python code.

Richard W.M. Jones rjones at redhat.com
Wed Aug 5 16:40:08 UTC 2020


Thanks: Nir Soffer.
---
 plugins/python/nbdkit-python-plugin.pod | 26 +++++++++++++++-------
 plugins/python/python.c                 | 29 ++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod
index 852366f0..edd56d13 100644
--- a/plugins/python/nbdkit-python-plugin.pod
+++ b/plugins/python/nbdkit-python-plugin.pod
@@ -163,6 +163,15 @@ There are no arguments or return value.
 
 There are no arguments or return value.
 
+=item C<thread_model>
+
+(Optional, nbdkit E<ge> 1.22)
+
+ def thread_model():
+   return nbdkit.THEAD_MODEL_SERIALIZE_ALL_REQUESTS
+
+See L</Threads> below.
+
 =item C<get_ready>
 
 (Optional)
@@ -367,10 +376,6 @@ optionally using C<nbdkit.set_error> first.
 These are not needed because you can just use ordinary Python
 constructs.
 
-=item Missing: C<thread_model>
-
-See L</Threads> below.
-
 =item Missing:
 C<name>,
 C<version>,
@@ -387,10 +392,15 @@ These are not yet supported.
 
 =head2 Threads
 
-The thread model for Python callbacks currently cannot be set from
-Python.  It is hard-coded in the C part to
-C<NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS>.  This may change or be
-settable in future.
+The thread model for Python callbacks defaults to
+C<NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS>.  Since S<nbdkit 1.22>
+it is possible to set this by implementing a C<thread_model> function
+which returns one of the constants C<nbdkit.THREAD_MODEL_*>.
+
+The Python Global Interpreter Lock (GIL) usually means that you cannot
+execute Python code in parallel, but Python code which calls into
+libraries which block (eg. to make HTTP requests) might be executed in
+parallel.
 
 =head1 FILES
 
diff --git a/plugins/python/python.c b/plugins/python/python.c
index 229a46f1..398473f5 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -494,6 +494,28 @@ py_config_complete (void)
   return 0;
 }
 
+static int
+py_thread_model (void)
+{
+  ACQUIRE_PYTHON_GIL_FOR_CURRENT_SCOPE;
+  PyObject *fn;
+  PyObject *r;
+  int ret = NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS;
+
+  if (script && callback_defined ("thread_model", &fn)) {
+    PyErr_Clear ();
+
+    r = PyObject_CallObject (fn, NULL);
+    Py_DECREF (fn);
+    if (check_python_failure ("thread_model") == -1)
+      return -1;
+    ret = PyLong_AsLong (r);
+    Py_DECREF (r);
+  }
+
+  return ret;
+}
+
 static int
 py_get_ready (void)
 {
@@ -1002,7 +1024,11 @@ py_can_cache (void *handle)
   "script=<FILENAME>     (required) The Python plugin to run.\n" \
   "[other arguments may be used by the plugin that you load]"
 
-#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
+/* This is the maximum possible, but the default for plugins is
+ * NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS.  Plugins can override
+ * that by providing a thread_model() function.
+ */
+#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
 
 static struct nbdkit_plugin plugin = {
   .name              = "python",
@@ -1016,6 +1042,7 @@ static struct nbdkit_plugin plugin = {
   .config_complete   = py_config_complete,
   .config_help       = py_config_help,
 
+  .thread_model      = py_thread_model,
   .get_ready         = py_get_ready,
 
   .open              = py_open,
-- 
2.27.0




More information about the Libguestfs mailing list