blob: 1ddf619d5fe52b22f761628d618ba8f5f0a78c87 (
plain)
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);
}
|