converter::python make them thread safe with GIL
authorMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 12 Dec 2023 10:10:06 +0000 (19:10 +0900)
committerjaeyun-jung <39614140+jaeyun-jung@users.noreply.github.com>
Mon, 8 Jan 2024 10:17:42 +0000 (19:17 +0900)
Apply GIL control to converter::python3 as in we do with filter::python3.
Fixes converter part of #3834
Overrides #3872

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
ext/nnstreamer/tensor_converter/tensor_converter_python3.cc

index 736a0d3..4a47968 100644 (file)
@@ -215,9 +215,8 @@ PYConverterCore::init ()
 {
   /** Find nnstreamer_api module */
   PyObject *api_module = PyImport_ImportModule ("nnstreamer_python");
-  if (api_module == NULL) {
+  if (api_module == NULL)
     return -EINVAL;
-  }
 
   shape_cls = PyObject_GetAttrString (api_module, "TensorShape");
   Py_SAFEDECREF (api_module);
@@ -244,10 +243,12 @@ PYConverterCore::getScriptPath ()
 static void
 py_close (void **private_data)
 {
+  PyGILState_STATE gstate = PyGILState_Ensure ();
   PYConverterCore *core = static_cast<PYConverterCore *> (*private_data);
 
   g_return_if_fail (core != NULL);
   delete core;
+  PyGILState_Release (gstate);
 
   *private_data = NULL;
 }
@@ -260,7 +261,9 @@ py_close (void **private_data)
 static int
 py_open (const gchar *path, void **priv_data)
 {
+  int ret = 0;
   PYConverterCore *core;
+  PyGILState_STATE gstate;
 
   if (!Py_IsInitialized ())
     throw std::runtime_error ("Python is not initialize.");
@@ -278,20 +281,25 @@ py_open (const gchar *path, void **priv_data)
   /* init null */
   *priv_data = NULL;
 
+  gstate = PyGILState_Ensure ();
   core = new PYConverterCore (path);
   if (core == NULL) {
-    Py_ERRMSG ("Failed to allocate memory for converter subplugin: Python\n");
-    return -1;
+    Py_ERRMSG ("Failed to allocate memory for converter subplugin or path invalid: Python\n");
+    ret = -ENOMEM;
+    goto done;
   }
 
   if (core->init () != 0) {
     delete core;
-    Py_ERRMSG ("failed to initailize the object: Python\n");
-    return -2;
+    Py_ERRMSG ("failed to initailize the object or the python script is invalid: Python\n");
+    ret = -EINVAL;
+    goto done;
   }
-  *priv_data = core;
 
-  return 0;
+  *priv_data = core;
+done:
+  PyGILState_Release (gstate);
+  return ret;
 }
 
 /** @brief tensor converter plugin's NNStreamerExternalConverter callback */
@@ -340,10 +348,16 @@ python_get_out_config (const GstCaps *in_cap, GstTensorsConfig *config)
 static GstBuffer *
 python_convert (GstBuffer *in_buf, GstTensorsConfig *config, void *priv_data)
 {
+  GstBuffer *ret;
   PYConverterCore *core = static_cast<PYConverterCore *> (priv_data);
+  PyGILState_STATE gstate;
   g_return_val_if_fail (in_buf, NULL);
   g_return_val_if_fail (config, NULL);
-  return core->convert (in_buf, config);
+
+  gstate = PyGILState_Ensure ();
+  ret = core->convert (in_buf, config);
+  PyGILState_Release (gstate);
+  return ret;
 }
 
 static const gchar converter_subplugin_python[] = "python3";
@@ -361,6 +375,7 @@ static NNStreamerExternalConverter Python = {
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
+static PyThreadState *st;
 /** @brief Initialize this object for tensor converter sub-plugin */
 void
 init_converter_py (void)
@@ -369,6 +384,8 @@ init_converter_py (void)
   if (!Py_IsInitialized ()) {
     Py_Initialize ();
   }
+  PyEval_InitThreads_IfGood ();
+  st = PyEval_SaveThread ();
   registerExternalConverter (&Python);
 }
 
@@ -376,6 +393,7 @@ init_converter_py (void)
 void
 fini_converter_py (void)
 {
+  PyEval_RestoreThread (st);
   unregisterExternalConverter (Python.name);
 /**
  * @todo Remove below lines after this issue is addressed.