blob: a284c5d8cef16d2d989081a7dfbff4b81f43e2fd [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
62#ifndef _POSIX_THREADS
63/* This means pthreads are not implemented in libc headers, hence the macro
64 not present in unistd.h. But they still can be implemented as an external
65 library (e.g. gnu pth in pthread emulation) */
66# ifdef HAVE_PTHREAD_H
67# include <pthread.h> /* _POSIX_THREADS */
68# endif
69#endif
70
71
72#ifdef _POSIX_THREADS
73
74/*
75 * POSIX support
76 */
77
78#include <pthread.h>
79
80#define ADD_MICROSECONDS(tv, interval) \
81do { \
82 tv.tv_usec += (long) interval; \
83 tv.tv_sec += tv.tv_usec / 1000000; \
84 tv.tv_usec %= 1000000; \
85} while (0)
86
87/* We assume all modern POSIX systems have gettimeofday() */
88#ifdef GETTIMEOFDAY_NO_TZ
89#define GETTIMEOFDAY(ptv) gettimeofday(ptv)
90#else
91#define GETTIMEOFDAY(ptv) gettimeofday(ptv, (struct timezone *)NULL)
92#endif
93
94#define MUTEX_T pthread_mutex_t
95#define MUTEX_INIT(mut) \
96 if (pthread_mutex_init(&mut, NULL)) { \
97 Py_FatalError("pthread_mutex_init(" #mut ") failed"); };
98#define MUTEX_LOCK(mut) \
99 if (pthread_mutex_lock(&mut)) { \
100 Py_FatalError("pthread_mutex_lock(" #mut ") failed"); };
101#define MUTEX_UNLOCK(mut) \
102 if (pthread_mutex_unlock(&mut)) { \
103 Py_FatalError("pthread_mutex_unlock(" #mut ") failed"); };
104
105#define COND_T pthread_cond_t
106#define COND_INIT(cond) \
107 if (pthread_cond_init(&cond, NULL)) { \
108 Py_FatalError("pthread_cond_init(" #cond ") failed"); };
Antoine Pitroua1d23322009-11-12 22:56:02 +0000109#define COND_RESET(cond)
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000110#define COND_SIGNAL(cond) \
111 if (pthread_cond_signal(&cond)) { \
112 Py_FatalError("pthread_cond_signal(" #cond ") failed"); };
113#define COND_WAIT(cond, mut) \
114 if (pthread_cond_wait(&cond, &mut)) { \
115 Py_FatalError("pthread_cond_wait(" #cond ") failed"); };
116#define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \
117 { \
118 int r; \
119 struct timespec ts; \
120 struct timeval deadline; \
121 \
122 GETTIMEOFDAY(&deadline); \
123 ADD_MICROSECONDS(deadline, microseconds); \
124 ts.tv_sec = deadline.tv_sec; \
125 ts.tv_nsec = deadline.tv_usec * 1000; \
126 \
127 r = pthread_cond_timedwait(&cond, &mut, &ts); \
128 if (r == ETIMEDOUT) \
129 timeout_result = 1; \
130 else if (r) \
131 Py_FatalError("pthread_cond_timedwait(" #cond ") failed"); \
132 else \
133 timeout_result = 0; \
134 } \
135
136#elif defined(NT_THREADS)
137
138/*
139 * Windows (2000 and later, as well as (hopefully) CE) support
140 */
141
142#include <windows.h>
143
144#define MUTEX_T HANDLE
145#define MUTEX_INIT(mut) \
146 if (!(mut = CreateMutex(NULL, FALSE, NULL))) { \
147 Py_FatalError("CreateMutex(" #mut ") failed"); };
148#define MUTEX_LOCK(mut) \
149 if (WaitForSingleObject(mut, INFINITE) != WAIT_OBJECT_0) { \
150 Py_FatalError("WaitForSingleObject(" #mut ") failed"); };
151#define MUTEX_UNLOCK(mut) \
152 if (!ReleaseMutex(mut)) { \
153 Py_FatalError("ReleaseMutex(" #mut ") failed"); };
154
155/* We emulate condition variables with events. It is sufficient here.
Antoine Pitroucf4cabb2009-11-11 18:11:36 +0000156 WaitForMultipleObjects() allows the event to be caught and the mutex
157 to be taken atomically.
158 As for SignalObjectAndWait(), its semantics are unfortunately a bit
159 more foggy. Many sources on the Web define it as atomically releasing
160 the first object while starting to wait on the second, but MSDN states
161 it is *not* atomic...
162
163 In any case, the emulation here is tailored for our particular use case.
164 For example, we don't care how many threads are woken up when a condition
165 gets signalled. Generic emulations of the pthread_cond_* API using
166 Win32 functions can be found on the Web.
167 The following read can be edificating (or not):
168 http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
169*/
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000170#define COND_T HANDLE
171#define COND_INIT(cond) \
172 /* auto-reset, non-signalled */ \
173 if (!(cond = CreateEvent(NULL, FALSE, FALSE, NULL))) { \
174 Py_FatalError("CreateMutex(" #cond ") failed"); };
Antoine Pitroua1d23322009-11-12 22:56:02 +0000175#define COND_RESET(cond) \
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000176 if (!ResetEvent(cond)) { \
177 Py_FatalError("ResetEvent(" #cond ") failed"); };
178#define COND_SIGNAL(cond) \
179 if (!SetEvent(cond)) { \
180 Py_FatalError("SetEvent(" #cond ") failed"); };
181#define COND_WAIT(cond, mut) \
182 { \
Antoine Pitroucf4cabb2009-11-11 18:11:36 +0000183 if (SignalObjectAndWait(mut, cond, INFINITE, FALSE) != WAIT_OBJECT_0) \
184 Py_FatalError("SignalObjectAndWait(" #mut ", " #cond") failed"); \
185 MUTEX_LOCK(mut); \
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000186 }
187#define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \
188 { \
189 DWORD r; \
190 HANDLE objects[2] = { cond, mut }; \
191 MUTEX_UNLOCK(mut); \
192 r = WaitForMultipleObjects(2, objects, TRUE, microseconds / 1000); \
193 if (r == WAIT_TIMEOUT) { \
194 MUTEX_LOCK(mut); \
195 timeout_result = 1; \
196 } \
197 else if (r != WAIT_OBJECT_0) \
198 Py_FatalError("WaitForSingleObject(" #cond ") failed"); \
199 else \
200 timeout_result = 0; \
201 }
202
203#else
204
205#error You need either a POSIX-compatible or a Windows system!
206
207#endif /* _POSIX_THREADS, NT_THREADS */
208
209
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000210/* Whether the GIL is already taken (-1 if uninitialized). This is atomic
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000211 because it can be read without any lock taken in ceval.c. */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000212static _Py_atomic_int gil_locked = {-1};
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000213/* Number of GIL switches since the beginning. */
214static unsigned long gil_switch_number = 0;
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000215/* Last PyThreadState holding / having held the GIL. This helps us know
216 whether anyone else was scheduled after we dropped the GIL. */
217static _Py_atomic_address gil_last_holder = {NULL};
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000218
219/* This condition variable allows one or several threads to wait until
220 the GIL is released. In addition, the mutex also protects the above
221 variables. */
222static COND_T gil_cond;
223static MUTEX_T gil_mutex;
224
225#ifdef FORCE_SWITCHING
226/* This condition variable helps the GIL-releasing thread wait for
227 a GIL-awaiting thread to be scheduled and take the GIL. */
228static COND_T switch_cond;
229static MUTEX_T switch_mutex;
230#endif
231
232
233static int gil_created(void)
234{
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000235 return _Py_atomic_load_explicit(&gil_locked, _Py_memory_order_acquire) >= 0;
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000236}
237
238static void create_gil(void)
239{
240 MUTEX_INIT(gil_mutex);
241#ifdef FORCE_SWITCHING
242 MUTEX_INIT(switch_mutex);
243#endif
244 COND_INIT(gil_cond);
245#ifdef FORCE_SWITCHING
246 COND_INIT(switch_cond);
247#endif
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000248 _Py_atomic_store_relaxed(&gil_last_holder, NULL);
249 _Py_ANNOTATE_RWLOCK_CREATE(&gil_locked);
250 _Py_atomic_store_explicit(&gil_locked, 0, _Py_memory_order_release);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000251}
252
253static void recreate_gil(void)
254{
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000255 _Py_ANNOTATE_RWLOCK_DESTROY(&gil_locked);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000256 create_gil();
257}
258
259static void drop_gil(PyThreadState *tstate)
260{
261 /* NOTE: tstate is allowed to be NULL. */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000262 if (!_Py_atomic_load_relaxed(&gil_locked))
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000263 Py_FatalError("drop_gil: GIL is not locked");
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000264 if (tstate != NULL &&
265 tstate != _Py_atomic_load_relaxed(&gil_last_holder))
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000266 Py_FatalError("drop_gil: wrong thread state");
267
268 MUTEX_LOCK(gil_mutex);
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000269 _Py_ANNOTATE_RWLOCK_RELEASED(&gil_locked, /*is_write=*/1);
270 _Py_atomic_store_relaxed(&gil_locked, 0);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000271 COND_SIGNAL(gil_cond);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000272 MUTEX_UNLOCK(gil_mutex);
273
274#ifdef FORCE_SWITCHING
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000275 if (_Py_atomic_load_relaxed(&gil_drop_request) && tstate != NULL) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000276 MUTEX_LOCK(switch_mutex);
277 /* Not switched yet => wait */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000278 if (_Py_atomic_load_relaxed(&gil_last_holder) == tstate) {
Antoine Pitroua1d23322009-11-12 22:56:02 +0000279 RESET_GIL_DROP_REQUEST();
Antoine Pitroucf4cabb2009-11-11 18:11:36 +0000280 /* NOTE: if COND_WAIT does not atomically start waiting when
281 releasing the mutex, another thread can run through, take
282 the GIL and drop it again, and reset the condition
Antoine Pitroua1d23322009-11-12 22:56:02 +0000283 before we even had a chance to wait for it. */
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000284 COND_WAIT(switch_cond, switch_mutex);
Antoine Pitroua1d23322009-11-12 22:56:02 +0000285 COND_RESET(switch_cond);
286 }
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000287 MUTEX_UNLOCK(switch_mutex);
288 }
289#endif
290}
291
292static void take_gil(PyThreadState *tstate)
293{
294 int err;
295 if (tstate == NULL)
296 Py_FatalError("take_gil: NULL tstate");
297
298 err = errno;
299 MUTEX_LOCK(gil_mutex);
300
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000301 if (!_Py_atomic_load_relaxed(&gil_locked))
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000302 goto _ready;
303
Antoine Pitroua1d23322009-11-12 22:56:02 +0000304 COND_RESET(gil_cond);
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000305 while (_Py_atomic_load_relaxed(&gil_locked)) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000306 int timed_out = 0;
307 unsigned long saved_switchnum;
308
309 saved_switchnum = gil_switch_number;
310 COND_TIMED_WAIT(gil_cond, gil_mutex, INTERVAL, timed_out);
311 /* If we timed out and no switch occurred in the meantime, it is time
312 to ask the GIL-holding thread to drop it. */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000313 if (timed_out &&
314 _Py_atomic_load_relaxed(&gil_locked) &&
315 gil_switch_number == saved_switchnum) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000316 SET_GIL_DROP_REQUEST();
317 }
318 }
319_ready:
320#ifdef FORCE_SWITCHING
321 /* This mutex must be taken before modifying gil_last_holder (see drop_gil()). */
322 MUTEX_LOCK(switch_mutex);
323#endif
324 /* We now hold the GIL */
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000325 _Py_atomic_store_relaxed(&gil_locked, 1);
326 _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil_locked, /*is_write=*/1);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000327
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000328 if (tstate != _Py_atomic_load_relaxed(&gil_last_holder)) {
329 _Py_atomic_store_relaxed(&gil_last_holder, tstate);
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000330 ++gil_switch_number;
331 }
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000332
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000333#ifdef FORCE_SWITCHING
334 COND_SIGNAL(switch_cond);
335 MUTEX_UNLOCK(switch_mutex);
336#endif
Jeffrey Yasskin39370832010-05-03 19:29:34 +0000337 if (_Py_atomic_load_relaxed(&gil_drop_request)) {
Antoine Pitrou074e5ed2009-11-10 19:50:40 +0000338 RESET_GIL_DROP_REQUEST();
339 }
340 if (tstate->async_exc != NULL) {
341 _PyEval_SignalAsyncExc();
342 }
343
344 MUTEX_UNLOCK(gil_mutex);
345 errno = err;
346}
347
348void _PyEval_SetSwitchInterval(unsigned long microseconds)
349{
350 gil_interval = microseconds;
351}
352
353unsigned long _PyEval_GetSwitchInterval()
354{
355 return gil_interval;
356}