Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it possible to release the GIL before a C function that blocks and might call back into Python?

I am wrapping a C function which performs a blocking operation (select) and then handles incoming messages. My understanding is that when a C function is going to block, the correct way to call it while allowing other threads to run is:

Py_BEGIN_ALLOW_THREADS                                                  
blocking_function();
Py_END_ALLOW_THREADS

However, it happens that this function takes as a parameter a callback pointer. This callback is called on handling the incoming message that is pre-processed by the C function. I have successfully wrapped this callback in a function which calls PyEval_CallObject(), allowing me to pass it a Python callback.

Now that I'm adding threading support, I'm wondering if it's possible to simultaneously:

  • Release the GIL before calling this blocking operation.
  • Have this blocking operation safely call back into the python interpreter.

Is this going to cause problems? If so, is there a way around it?

Thanks.

like image 223
Steve Avatar asked Feb 24 '23 22:02

Steve


2 Answers

I used these API functions several months ago, and my recollection is a bit hazy, but I believe this code will solve your problem. I am assuming version 2.x (3.x may be different):

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

/* Make your call to PyEval_CallObject() here (and any other PY API calls). */

PyGILState_Release(gstate);

(The above was taken from: Python C/API docs)

This is basically the inverse of the Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS macros. Within those, you release the GIL, but within the PyGILState functions you acquire the GIL.

like image 117
dappawit Avatar answered Feb 27 '23 15:02

dappawit


Works if I use a global to store the result of PyEval_SaveThread, and use this in the callback to call PyEval_RestoreThread. I just need to figure out how to more cleanly pass this to the callback in my code through the callback's context pointer.

like image 23
Steve Avatar answered Feb 27 '23 15:02

Steve