blob: 2702d5cbddb2e0e76ccb9ed7fd0556730bcc06a6 [file] [log] [blame]
Antoine Pitrou074e5ed2009-11-10 19:50:40 +00001/*
2 * Implementation of the Global Interpreter Lock (GIL).
3 */
4
5#include <stdlib.h>
6#include <errno.h>
7
8
9/* First some general settings */
10
11/* microseconds (the Python API uses seconds, though) */
12#define DEFAULT_INTERVAL 5000
13static unsigned long gil_interval = DEFAULT_INTERVAL;
14#define INTERVAL (gil_interval >= 1 ? gil_interval : 1)
15
16/* Enable if you want to force the switching of threads at least every `gil_interval` */
17#undef FORCE_SWITCHING
18#define FORCE_SWITCHING
19
20
21/*
22 Notes about the implementation:
23
24 - The GIL is just a boolean variable (gil_locked) whose access is protected
25 by a mutex (gil_mutex), and whose changes are signalled by a condition
26 variable (gil_cond). gil_mutex is taken for short periods of time,
27 and therefore mostly uncontended.
28
29 - In the GIL-holding thread, the main loop (PyEval_EvalFrameEx) must be
30 able to release the GIL on demand by another thread. A volatile boolean
31 variable (gil_drop_request) is used for that purpose, which is checked
32 at every turn of the eval loop. That variable is set after a wait of
33 `interval` microseconds on `gil_cond` has timed out.
34
35 [Actually, another volatile boolean variable (eval_breaker) is used
36 which ORs several conditions into one. Volatile booleans are
37 sufficient as inter-thread signalling means since Python is run
38 on cache-coherent architectures only.]
39
40 - A thread wanting to take the GIL will first let pass a given amount of
41 time (`interval` microseconds) before setting gil_drop_request. This
42 encourages a defined switching period, but doesn't enforce it since
43 opcodes can take an arbitrary time to execute.
44
45 The `interval` value is available for the user to read and modify
46 using the Python API `sys.{get,set}switchinterval()`.
47
48 - When a thread releases the GIL and gil_drop_request is set, that thread
49 ensures that another GIL-awaiting thread gets scheduled.
50 It does so by waiting on a condition variable (switch_cond) until
51 the value of gil_last_holder is changed to something else than its
52 own thread state pointer, indicating that another thread was able to
53 take the GIL.
54
55 This is meant to prohibit the latency-adverse behaviour on multi-core
56 machines where one thread would speculatively release the GIL, but still
57 run and end up being the first to re-acquire it, making the "timeslices"
58 much longer than expected.
59 (Note: this mechanism is enabled with FORCE_SWITCHING above)
60*/
61
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000062#include "condvar.h"
63#ifndef Py_HAVE_CONDVAR
64#error You need either a POSIX-compatible or a Windows system!
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000065#endif
66
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000067#define MUTEX_T PyMUTEX_T
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000068#define MUTEX_INIT(mut) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000069 if (PyMUTEX_INIT(&(mut))) { \
70 Py_FatalError("PyMUTEX_INIT(" #mut ") failed"); };
Antoine Pitrou1df15362010-09-13 14:16:46 +000071#define MUTEX_FINI(mut) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000072 if (PyMUTEX_FINI(&(mut))) { \
73 Py_FatalError("PyMUTEX_FINI(" #mut ") failed"); };
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000074#define MUTEX_LOCK(mut) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000075 if (PyMUTEX_LOCK(&(mut))) { \
76 Py_FatalError("PyMUTEX_LOCK(" #mut ") failed"); };
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000077#define MUTEX_UNLOCK(mut) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000078 if (PyMUTEX_UNLOCK(&(mut))) { \
79 Py_FatalError("PyMUTEX_UNLOCK(" #mut ") failed"); };
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000080
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000081#define COND_T PyCOND_T
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000082#define COND_INIT(cond) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000083 if (PyCOND_INIT(&(cond))) { \
84 Py_FatalError("PyCOND_INIT(" #cond ") failed"); };
Antoine Pitrou1df15362010-09-13 14:16:46 +000085#define COND_FINI(cond) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000086 if (PyCOND_FINI(&(cond))) { \
87 Py_FatalError("PyCOND_FINI(" #cond ") failed"); };
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000088#define COND_SIGNAL(cond) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000089 if (PyCOND_SIGNAL(&(cond))) { \
90 Py_FatalError("PyCOND_SIGNAL(" #cond ") failed"); };
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000091#define COND_WAIT(cond, mut) \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000092 if (PyCOND_WAIT(&(cond), &(mut))) { \
93 Py_FatalError("PyCOND_WAIT(" #cond ") failed"); };
Antoine Pitrou074e5ed2009-11-10 19:50:40 +000094#define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \
95 { \
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000096 int r = PyCOND_TIMEDWAIT(&(cond), &(mut), (microseconds)); \
97 if (r < 0) \
98 Py_FatalError("PyCOND_WAIT(" #cond ") failed"); \
99 if (r) /* 1 == timeout, 2 == impl. can't say, so assume timeout */ \
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000100 timeout_result = 1; \
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000101 else \
102 timeout_result = 0; \
103 } \
104
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000105
106
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000107/* Whether the GIL is already taken (-1 if uninitialized). This is atomic
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000108 because it can be read without any lock taken in ceval.c. */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000109static _Py_atomic_int gil_locked = {-1};
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000110/* Number of GIL switches since the beginning. */
111static unsigned long gil_switch_number = 0;
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000112/* Last PyThreadState holding / having held the GIL. This helps us know
113 whether anyone else was scheduled after we dropped the GIL. */
114static _Py_atomic_address gil_last_holder = {NULL};
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000115
116/* This condition variable allows one or several threads to wait until
117 the GIL is released. In addition, the mutex also protects the above
118 variables. */
119static COND_T gil_cond;
120static MUTEX_T gil_mutex;
121
122#ifdef FORCE_SWITCHING
123/* This condition variable helps the GIL-releasing thread wait for
124 a GIL-awaiting thread to be scheduled and take the GIL. */
125static COND_T switch_cond;
126static MUTEX_T switch_mutex;
127#endif
128
129
130static int gil_created(void)
131{
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000132 return _Py_atomic_load_explicit(&gil_locked, _Py_memory_order_acquire) >= 0;
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000133}
134
135static void create_gil(void)
136{
137 MUTEX_INIT(gil_mutex);
138#ifdef FORCE_SWITCHING
139 MUTEX_INIT(switch_mutex);
140#endif
141 COND_INIT(gil_cond);
142#ifdef FORCE_SWITCHING
143 COND_INIT(switch_cond);
144#endif
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000145 _Py_atomic_store_relaxed(&gil_last_holder, NULL);
146 _Py_ANNOTATE_RWLOCK_CREATE(&gil_locked);
147 _Py_atomic_store_explicit(&gil_locked, 0, _Py_memory_order_release);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000148}
149
Antoine Pitrou1df15362010-09-13 14:16:46 +0000150static void destroy_gil(void)
151{
Kristján Valur Jónsson187aa542012-06-05 22:17:42 +0000152 /* some pthread-like implementations tie the mutex to the cond
153 * and must have the cond destroyed first.
154 */
155 COND_FINI(gil_cond);
Antoine Pitrou1df15362010-09-13 14:16:46 +0000156 MUTEX_FINI(gil_mutex);
157#ifdef FORCE_SWITCHING
Antoine Pitrou1df15362010-09-13 14:16:46 +0000158 COND_FINI(switch_cond);
Kristján Valur Jónsson187aa542012-06-05 22:17:42 +0000159 MUTEX_FINI(switch_mutex);
Antoine Pitrou1df15362010-09-13 14:16:46 +0000160#endif
161 _Py_atomic_store_explicit(&gil_locked, -1, _Py_memory_order_release);
162 _Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked);
163}
164
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000165static void recreate_gil(void)
166{
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000167 _Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked);
Antoine Pitrou1df15362010-09-13 14:16:46 +0000168 /* XXX should we destroy the old OS resources here? */
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000169 create_gil();
170}
171
172static void drop_gil(PyThreadState *tstate)
173{
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000174 if (!_Py_atomic_load_relaxed(&gil_locked))
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000175 Py_FatalError("drop_gil: GIL is not locked");
Antoine Pitrou6a002c02011-01-15 11:37:11 +0000176 /* tstate is allowed to be NULL (early interpreter init) */
177 if (tstate != NULL) {
178 /* Sub-interpreter support: threads might have been switched
179 under our feet using PyThreadState_Swap(). Fix the GIL last
180 holder variable so that our heuristics work. */
181 _Py_atomic_store_relaxed(&gil_last_holder, tstate);
182 }
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000183
184 MUTEX_LOCK(gil_mutex);
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000185 _Py_ANNOTATE_RWLOCK_RELEASED(&gil_locked, /*is_write=*/1);
186 _Py_atomic_store_relaxed(&gil_locked, 0);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000187 COND_SIGNAL(gil_cond);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000188 MUTEX_UNLOCK(gil_mutex);
189
190#ifdef FORCE_SWITCHING
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000191 if (_Py_atomic_load_relaxed(&gil_drop_request) && tstate != NULL) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000192 MUTEX_LOCK(switch_mutex);
193 /* Not switched yet => wait */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000194 if (_Py_atomic_load_relaxed(&gil_last_holder) == tstate) {
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +0000195 RESET_GIL_DROP_REQUEST();
Antoine Pitroucf4cabb2009-11-11 18:11:36 +0000196 /* NOTE: if COND_WAIT does not atomically start waiting when
197 releasing the mutex, another thread can run through, take
198 the GIL and drop it again, and reset the condition
Antoine Pitroua1d23322009-11-12 22:56:02 +0000199 before we even had a chance to wait for it. */
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000200 COND_WAIT(switch_cond, switch_mutex);
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +0000201 }
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000202 MUTEX_UNLOCK(switch_mutex);
203 }
204#endif
205}
206
207static void take_gil(PyThreadState *tstate)
208{
209 int err;
210 if (tstate == NULL)
211 Py_FatalError("take_gil: NULL tstate");
212
213 err = errno;
214 MUTEX_LOCK(gil_mutex);
215
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000216 if (!_Py_atomic_load_relaxed(&gil_locked))
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000217 goto _ready;
218
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000219 while (_Py_atomic_load_relaxed(&gil_locked)) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000220 int timed_out = 0;
221 unsigned long saved_switchnum;
222
223 saved_switchnum = gil_switch_number;
224 COND_TIMED_WAIT(gil_cond, gil_mutex, INTERVAL, timed_out);
225 /* If we timed out and no switch occurred in the meantime, it is time
226 to ask the GIL-holding thread to drop it. */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000227 if (timed_out &&
228 _Py_atomic_load_relaxed(&gil_locked) &&
229 gil_switch_number == saved_switchnum) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000230 SET_GIL_DROP_REQUEST();
231 }
232 }
233_ready:
234#ifdef FORCE_SWITCHING
235 /* This mutex must be taken before modifying gil_last_holder (see drop_gil()). */
236 MUTEX_LOCK(switch_mutex);
237#endif
238 /* We now hold the GIL */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000239 _Py_atomic_store_relaxed(&gil_locked, 1);
240 _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil_locked, /*is_write=*/1);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000241
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000242 if (tstate != _Py_atomic_load_relaxed(&gil_last_holder)) {
243 _Py_atomic_store_relaxed(&gil_last_holder, tstate);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000244 ++gil_switch_number;
245 }
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000246
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000247#ifdef FORCE_SWITCHING
248 COND_SIGNAL(switch_cond);
249 MUTEX_UNLOCK(switch_mutex);
250#endif
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000251 if (_Py_atomic_load_relaxed(&gil_drop_request)) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000252 RESET_GIL_DROP_REQUEST();
253 }
254 if (tstate->async_exc != NULL) {
255 _PyEval_SignalAsyncExc();
256 }
257
258 MUTEX_UNLOCK(gil_mutex);
259 errno = err;
260}
261
262void _PyEval_SetSwitchInterval(unsigned long microseconds)
263{
264 gil_interval = microseconds;
265}
266
267unsigned long _PyEval_GetSwitchInterval()
268{
269 return gil_interval;
270}