You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

349 lines
12 KiB

  1. /*
  2. * Implementation of the Global Interpreter Lock (GIL).
  3. */
  4. #include <stdlib.h>
  5. #include <errno.h>
  6. #include "pycore_atomic.h"
  7. /*
  8. Notes about the implementation:
  9. - The GIL is just a boolean variable (locked) whose access is protected
  10. by a mutex (gil_mutex), and whose changes are signalled by a condition
  11. variable (gil_cond). gil_mutex is taken for short periods of time,
  12. and therefore mostly uncontended.
  13. - In the GIL-holding thread, the main loop (PyEval_EvalFrameEx) must be
  14. able to release the GIL on demand by another thread. A volatile boolean
  15. variable (gil_drop_request) is used for that purpose, which is checked
  16. at every turn of the eval loop. That variable is set after a wait of
  17. `interval` microseconds on `gil_cond` has timed out.
  18. [Actually, another volatile boolean variable (eval_breaker) is used
  19. which ORs several conditions into one. Volatile booleans are
  20. sufficient as inter-thread signalling means since Python is run
  21. on cache-coherent architectures only.]
  22. - A thread wanting to take the GIL will first let pass a given amount of
  23. time (`interval` microseconds) before setting gil_drop_request. This
  24. encourages a defined switching period, but doesn't enforce it since
  25. opcodes can take an arbitrary time to execute.
  26. The `interval` value is available for the user to read and modify
  27. using the Python API `sys.{get,set}switchinterval()`.
  28. - When a thread releases the GIL and gil_drop_request is set, that thread
  29. ensures that another GIL-awaiting thread gets scheduled.
  30. It does so by waiting on a condition variable (switch_cond) until
  31. the value of last_holder is changed to something else than its
  32. own thread state pointer, indicating that another thread was able to
  33. take the GIL.
  34. This is meant to prohibit the latency-adverse behaviour on multi-core
  35. machines where one thread would speculatively release the GIL, but still
  36. run and end up being the first to re-acquire it, making the "timeslices"
  37. much longer than expected.
  38. (Note: this mechanism is enabled with FORCE_SWITCHING above)
  39. */
  40. #include "condvar.h"
  41. #define MUTEX_INIT(mut) \
  42. if (PyMUTEX_INIT(&(mut))) { \
  43. Py_FatalError("PyMUTEX_INIT(" #mut ") failed"); };
  44. #define MUTEX_FINI(mut) \
  45. if (PyMUTEX_FINI(&(mut))) { \
  46. Py_FatalError("PyMUTEX_FINI(" #mut ") failed"); };
  47. #define MUTEX_LOCK(mut) \
  48. if (PyMUTEX_LOCK(&(mut))) { \
  49. Py_FatalError("PyMUTEX_LOCK(" #mut ") failed"); };
  50. #define MUTEX_UNLOCK(mut) \
  51. if (PyMUTEX_UNLOCK(&(mut))) { \
  52. Py_FatalError("PyMUTEX_UNLOCK(" #mut ") failed"); };
  53. #define COND_INIT(cond) \
  54. if (PyCOND_INIT(&(cond))) { \
  55. Py_FatalError("PyCOND_INIT(" #cond ") failed"); };
  56. #define COND_FINI(cond) \
  57. if (PyCOND_FINI(&(cond))) { \
  58. Py_FatalError("PyCOND_FINI(" #cond ") failed"); };
  59. #define COND_SIGNAL(cond) \
  60. if (PyCOND_SIGNAL(&(cond))) { \
  61. Py_FatalError("PyCOND_SIGNAL(" #cond ") failed"); };
  62. #define COND_WAIT(cond, mut) \
  63. if (PyCOND_WAIT(&(cond), &(mut))) { \
  64. Py_FatalError("PyCOND_WAIT(" #cond ") failed"); };
  65. #define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \
  66. { \
  67. int r = PyCOND_TIMEDWAIT(&(cond), &(mut), (microseconds)); \
  68. if (r < 0) \
  69. Py_FatalError("PyCOND_WAIT(" #cond ") failed"); \
  70. if (r) /* 1 == timeout, 2 == impl. can't say, so assume timeout */ \
  71. timeout_result = 1; \
  72. else \
  73. timeout_result = 0; \
  74. } \
  75. #define DEFAULT_INTERVAL 5000
  76. static void _gil_initialize(struct _gil_runtime_state *gil)
  77. {
  78. _Py_atomic_int uninitialized = {-1};
  79. gil->locked = uninitialized;
  80. gil->interval = DEFAULT_INTERVAL;
  81. }
  82. static int gil_created(struct _gil_runtime_state *gil)
  83. {
  84. return (_Py_atomic_load_explicit(&gil->locked, _Py_memory_order_acquire) >= 0);
  85. }
  86. static void create_gil(struct _gil_runtime_state *gil)
  87. {
  88. MUTEX_INIT(gil->mutex);
  89. #ifdef FORCE_SWITCHING
  90. MUTEX_INIT(gil->switch_mutex);
  91. #endif
  92. COND_INIT(gil->cond);
  93. #ifdef FORCE_SWITCHING
  94. COND_INIT(gil->switch_cond);
  95. #endif
  96. _Py_atomic_store_relaxed(&gil->last_holder, 0);
  97. _Py_ANNOTATE_RWLOCK_CREATE(&gil->locked);
  98. _Py_atomic_store_explicit(&gil->locked, 0, _Py_memory_order_release);
  99. }
  100. static void destroy_gil(struct _gil_runtime_state *gil)
  101. {
  102. /* some pthread-like implementations tie the mutex to the cond
  103. * and must have the cond destroyed first.
  104. */
  105. COND_FINI(gil->cond);
  106. MUTEX_FINI(gil->mutex);
  107. #ifdef FORCE_SWITCHING
  108. COND_FINI(gil->switch_cond);
  109. MUTEX_FINI(gil->switch_mutex);
  110. #endif
  111. _Py_atomic_store_explicit(&gil->locked, -1,
  112. _Py_memory_order_release);
  113. _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked);
  114. }
  115. static void recreate_gil(struct _gil_runtime_state *gil)
  116. {
  117. _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked);
  118. /* XXX should we destroy the old OS resources here? */
  119. create_gil(gil);
  120. }
  121. static void
  122. drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2,
  123. PyThreadState *tstate)
  124. {
  125. #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
  126. struct _gil_runtime_state *gil = &ceval2->gil;
  127. #else
  128. struct _gil_runtime_state *gil = &ceval->gil;
  129. #endif
  130. if (!_Py_atomic_load_relaxed(&gil->locked)) {
  131. Py_FatalError("drop_gil: GIL is not locked");
  132. }
  133. /* tstate is allowed to be NULL (early interpreter init) */
  134. if (tstate != NULL) {
  135. /* Sub-interpreter support: threads might have been switched
  136. under our feet using PyThreadState_Swap(). Fix the GIL last
  137. holder variable so that our heuristics work. */
  138. _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate);
  139. }
  140. MUTEX_LOCK(gil->mutex);
  141. _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1);
  142. _Py_atomic_store_relaxed(&gil->locked, 0);
  143. COND_SIGNAL(gil->cond);
  144. MUTEX_UNLOCK(gil->mutex);
  145. #ifdef FORCE_SWITCHING
  146. if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request) && tstate != NULL) {
  147. MUTEX_LOCK(gil->switch_mutex);
  148. /* Not switched yet => wait */
  149. if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate)
  150. {
  151. assert(is_tstate_valid(tstate));
  152. RESET_GIL_DROP_REQUEST(tstate->interp);
  153. /* NOTE: if COND_WAIT does not atomically start waiting when
  154. releasing the mutex, another thread can run through, take
  155. the GIL and drop it again, and reset the condition
  156. before we even had a chance to wait for it. */
  157. COND_WAIT(gil->switch_cond, gil->switch_mutex);
  158. }
  159. MUTEX_UNLOCK(gil->switch_mutex);
  160. }
  161. #endif
  162. }
  163. /* Check if a Python thread must exit immediately, rather than taking the GIL
  164. if Py_Finalize() has been called.
  165. When this function is called by a daemon thread after Py_Finalize() has been
  166. called, the GIL does no longer exist.
  167. tstate must be non-NULL. */
  168. static inline int
  169. tstate_must_exit(PyThreadState *tstate)
  170. {
  171. /* bpo-39877: Access _PyRuntime directly rather than using
  172. tstate->interp->runtime to support calls from Python daemon threads.
  173. After Py_Finalize() has been called, tstate can be a dangling pointer:
  174. point to PyThreadState freed memory. */
  175. PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime);
  176. return (finalizing != NULL && finalizing != tstate);
  177. }
  178. /* Take the GIL.
  179. The function saves errno at entry and restores its value at exit.
  180. tstate must be non-NULL. */
  181. static void
  182. take_gil(PyThreadState *tstate)
  183. {
  184. int err = errno;
  185. assert(tstate != NULL);
  186. if (tstate_must_exit(tstate)) {
  187. /* bpo-39877: If Py_Finalize() has been called and tstate is not the
  188. thread which called Py_Finalize(), exit immediately the thread.
  189. This code path can be reached by a daemon thread after Py_Finalize()
  190. completes. In this case, tstate is a dangling pointer: points to
  191. PyThreadState freed memory. */
  192. PyThread_exit_thread();
  193. }
  194. assert(is_tstate_valid(tstate));
  195. PyInterpreterState *interp = tstate->interp;
  196. struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
  197. struct _ceval_state *ceval2 = &interp->ceval;
  198. #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
  199. struct _gil_runtime_state *gil = &ceval2->gil;
  200. #else
  201. struct _gil_runtime_state *gil = &ceval->gil;
  202. #endif
  203. /* Check that _PyEval_InitThreads() was called to create the lock */
  204. assert(gil_created(gil));
  205. MUTEX_LOCK(gil->mutex);
  206. if (!_Py_atomic_load_relaxed(&gil->locked)) {
  207. goto _ready;
  208. }
  209. while (_Py_atomic_load_relaxed(&gil->locked)) {
  210. unsigned long saved_switchnum = gil->switch_number;
  211. unsigned long interval = (gil->interval >= 1 ? gil->interval : 1);
  212. int timed_out = 0;
  213. COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out);
  214. /* If we timed out and no switch occurred in the meantime, it is time
  215. to ask the GIL-holding thread to drop it. */
  216. if (timed_out &&
  217. _Py_atomic_load_relaxed(&gil->locked) &&
  218. gil->switch_number == saved_switchnum)
  219. {
  220. if (tstate_must_exit(tstate)) {
  221. MUTEX_UNLOCK(gil->mutex);
  222. PyThread_exit_thread();
  223. }
  224. assert(is_tstate_valid(tstate));
  225. SET_GIL_DROP_REQUEST(interp);
  226. }
  227. }
  228. _ready:
  229. #ifdef FORCE_SWITCHING
  230. /* This mutex must be taken before modifying gil->last_holder:
  231. see drop_gil(). */
  232. MUTEX_LOCK(gil->switch_mutex);
  233. #endif
  234. /* We now hold the GIL */
  235. _Py_atomic_store_relaxed(&gil->locked, 1);
  236. _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil->locked, /*is_write=*/1);
  237. if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) {
  238. _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate);
  239. ++gil->switch_number;
  240. }
  241. #ifdef FORCE_SWITCHING
  242. COND_SIGNAL(gil->switch_cond);
  243. MUTEX_UNLOCK(gil->switch_mutex);
  244. #endif
  245. if (tstate_must_exit(tstate)) {
  246. /* bpo-36475: If Py_Finalize() has been called and tstate is not
  247. the thread which called Py_Finalize(), exit immediately the
  248. thread.
  249. This code path can be reached by a daemon thread which was waiting
  250. in take_gil() while the main thread called
  251. wait_for_thread_shutdown() from Py_Finalize(). */
  252. MUTEX_UNLOCK(gil->mutex);
  253. drop_gil(ceval, ceval2, tstate);
  254. PyThread_exit_thread();
  255. }
  256. assert(is_tstate_valid(tstate));
  257. if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request)) {
  258. RESET_GIL_DROP_REQUEST(interp);
  259. }
  260. else {
  261. /* bpo-40010: eval_breaker should be recomputed to be set to 1 if there
  262. is a pending signal: signal received by another thread which cannot
  263. handle signals.
  264. Note: RESET_GIL_DROP_REQUEST() calls COMPUTE_EVAL_BREAKER(). */
  265. COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
  266. }
  267. /* Don't access tstate if the thread must exit */
  268. if (tstate->async_exc != NULL) {
  269. _PyEval_SignalAsyncExc(tstate);
  270. }
  271. MUTEX_UNLOCK(gil->mutex);
  272. errno = err;
  273. }
  274. void _PyEval_SetSwitchInterval(unsigned long microseconds)
  275. {
  276. #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
  277. PyInterpreterState *interp = PyInterpreterState_Get();
  278. struct _gil_runtime_state *gil = &interp->ceval.gil;
  279. #else
  280. struct _gil_runtime_state *gil = &_PyRuntime.ceval.gil;
  281. #endif
  282. gil->interval = microseconds;
  283. }
  284. unsigned long _PyEval_GetSwitchInterval()
  285. {
  286. #ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
  287. PyInterpreterState *interp = PyInterpreterState_Get();
  288. struct _gil_runtime_state *gil = &interp->ceval.gil;
  289. #else
  290. struct _gil_runtime_state *gil = &_PyRuntime.ceval.gil;
  291. #endif
  292. return gil->interval;
  293. }