1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
#ifndef WITH_THREAD
# error "xxx no-thread configuration not tested, please report if you need that"
#endif
struct cffi_tls_s {
/* The locally-made thread state. This is only non-null in case
we build the thread state here. It remains null if this thread
had already a thread state provided by CPython. */
PyThreadState *local_thread_state;
#ifndef USE__THREAD
/* The saved errno. If the C compiler supports '__thread', then
we use that instead. */
int saved_errno;
#endif
#ifdef MS_WIN32
/* The saved lasterror, on Windows. */
int saved_lasterror;
#endif
};
static struct cffi_tls_s *get_cffi_tls(void); /* in misc_thread_posix.h
or misc_win32.h */
static void cffi_thread_shutdown(void *p)
{
struct cffi_tls_s *tls = (struct cffi_tls_s *)p;
if (tls->local_thread_state != NULL) {
/* We need to re-acquire the GIL temporarily to free the
thread state. I hope it is not a problem to do it in
a thread-local destructor.
*/
PyEval_RestoreThread(tls->local_thread_state);
PyThreadState_DeleteCurrent();
}
free(tls);
}
/* USE__THREAD is defined by setup.py if it finds that it is
syntactically valid to use "__thread" with this C compiler. */
#ifdef USE__THREAD
static __thread int cffi_saved_errno = 0;
static void save_errno_only(void) { cffi_saved_errno = errno; }
static void restore_errno_only(void) { errno = cffi_saved_errno; }
#else
static void save_errno_only(void)
{
int saved = errno;
struct cffi_tls_s *tls = get_cffi_tls();
if (tls != NULL)
tls->saved_errno = saved;
}
static void restore_errno_only(void)
{
struct cffi_tls_s *tls = get_cffi_tls();
if (tls != NULL)
errno = tls->saved_errno;
}
#endif
/* Seems that CPython 3.5.1 made our job harder. Did not find out how
to do that without these hacks. We can't use PyThreadState_GET(),
because that calls PyThreadState_Get() which fails an assert if the
result is NULL. */
#if PY_MAJOR_VERSION >= 3 && !defined(_Py_atomic_load_relaxed)
/* this was abruptly un-defined in 3.5.1 */
void *volatile _PyThreadState_Current;
/* XXX simple volatile access is assumed atomic */
# define _Py_atomic_load_relaxed(pp) (*(pp))
#endif
static PyThreadState *get_current_ts(void)
{
#if defined(_Py_atomic_load_relaxed)
return (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current);
#else
return _PyThreadState_Current;
#endif
}
static PyGILState_STATE gil_ensure(void)
{
/* Called at the start of a callback. Replacement for
PyGILState_Ensure().
*/
PyGILState_STATE result;
struct cffi_tls_s *tls;
PyThreadState *ts = PyGILState_GetThisThreadState();
if (ts != NULL) {
ts->gilstate_counter++;
if (ts != get_current_ts()) {
/* common case: 'ts' is our non-current thread state and
we have to make it current and acquire the GIL */
PyEval_RestoreThread(ts);
return PyGILState_UNLOCKED;
}
else {
return PyGILState_LOCKED;
}
}
else {
/* no thread state here so far. */
result = PyGILState_Ensure();
assert(result == PyGILState_UNLOCKED);
ts = PyGILState_GetThisThreadState();
assert(ts != NULL);
assert(ts == get_current_ts());
assert(ts->gilstate_counter >= 1);
/* Save the now-current thread state inside our 'local_thread_state'
field, to be removed at thread shutdown */
tls = get_cffi_tls();
if (tls != NULL) {
tls->local_thread_state = ts;
ts->gilstate_counter++;
}
return result;
}
}
static void gil_release(PyGILState_STATE oldstate)
{
PyGILState_Release(oldstate);
}
|