Skip to content

Commit 08bf50d

Browse files
committed
Use PyGilState_Ensure to avoid accessing CPython internals
1 parent babf589 commit 08bf50d

1 file changed

Lines changed: 11 additions & 44 deletions

File tree

‎src/c/misc_thread_common.h‎

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,14 @@ thread_canary_register(PyThreadState *tstate)
224224
the reference) and in 'tls->local_thread_canary' (which doesn't). */
225225
assert(Py_REFCNT(canary) == 1);
226226
tls->local_thread_canary = canary;
227-
tstate->gilstate_counter++;
228-
/* ^^^ this means 'tstate' will never be automatically freed by
229-
PyGILState_Release() */
227+
{
228+
/* this extra PyGILState_Ensure() is deliberately never paired
229+
with a PyGILState_Release(), so 'tstate' is never
230+
automatically freed by PyGILState_Release() */
231+
PyGILState_STATE state = PyGILState_Ensure();
232+
assert(state == PyGILState_LOCKED);
233+
(void)state;
234+
}
230235
//fprintf(stderr, "CANARY: ready, tstate=%p, tls=%p, canary=%p\n", tstate, tls, canary);
231236
return;
232237

@@ -313,52 +318,16 @@ static void restore_errno_only(void)
313318
#endif
314319

315320

316-
/* MESS. We can't use PyThreadState_GET(), because that calls
317-
PyThreadState_Get() which fails an assert if the result is NULL.
318-
319-
* in Python 2.7 and <= 3.4, the variable _PyThreadState_Current
320-
is directly available, so use that.
321-
322-
* in Python 3.5, the variable is available too, but it might be
323-
the case that the headers don't define it (this changed in 3.5.1).
324-
In case we're compiling with 3.5.x with x >= 1, we need to
325-
manually define this variable.
326-
327-
* in Python >= 3.6 there is _PyThreadState_UncheckedGet().
328-
It was added in 3.5.2 but should never be used in 3.5.x
329-
because it is not available in 3.5.0 or 3.5.1.
330-
*/
331-
static PyThreadState *get_current_ts(void)
332-
{
333-
#if PY_VERSION_HEX >= 0x030D0000
334-
return PyThreadState_GetUnchecked();
335-
#else
336-
return _PyThreadState_UncheckedGet();
337-
#endif
338-
}
339-
340321
static PyGILState_STATE gil_ensure(void)
341322
{
342-
/* Called at the start of a callback. Replacement for
343-
PyGILState_Ensure().
344-
*/
323+
/* Called at the start of a callback. */
345324
PyGILState_STATE result;
346325
PyThreadState *ts = PyGILState_GetThisThreadState();
347326
//fprintf(stderr, "%p: gil_ensure(), tstate=%p, tls=%p\n", get_cffi_tls(), ts, get_cffi_tls());
348327

349328
if (ts != NULL) {
350-
ts->gilstate_counter++;
351-
if (ts != get_current_ts()) {
352-
/* common case: 'ts' is our non-current thread state and
353-
we have to make it current and acquire the GIL */
354-
PyEval_RestoreThread(ts);
355-
//fprintf(stderr, "%p: gil_ensure(), tstate=%p MADE CURRENT\n", get_cffi_tls(), ts);
356-
return PyGILState_UNLOCKED;
357-
}
358-
else {
359-
//fprintf(stderr, "%p: gil_ensure(), tstate=%p ALREADY CURRENT\n", get_cffi_tls(), ts);
360-
return PyGILState_LOCKED;
361-
}
329+
/* common case: this thread already has a thread state */
330+
return PyGILState_Ensure();
362331
}
363332
else {
364333
/* no thread state here so far. */
@@ -368,8 +337,6 @@ static PyGILState_STATE gil_ensure(void)
368337
ts = PyGILState_GetThisThreadState();
369338
//fprintf(stderr, "%p: gil_ensure(), made a new tstate=%p\n", get_cffi_tls(), ts);
370339
assert(ts != NULL);
371-
assert(ts == get_current_ts());
372-
assert(ts->gilstate_counter >= 1);
373340

374341
/* Use the ThreadCanary mechanism to keep 'ts' alive until the
375342
thread really shuts down */

0 commit comments

Comments
 (0)