| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "Python.h"
 | 
					
						
							|  |  |  | #include "pycore_ceval.h"         // _PyEval_SignalReceived()
 | 
					
						
							|  |  |  | #include "pycore_initconfig.h"    // _PyStatus_OK()
 | 
					
						
							| 
									
										
										
										
											2022-10-08 07:57:09 -07:00
										 |  |  | #include "pycore_interp.h"        // _Py_RunGC()
 | 
					
						
							| 
									
										
										
										
											2023-09-06 17:54:59 +02:00
										 |  |  | #include "pycore_pyerrors.h"      // _PyErr_GetRaisedException()
 | 
					
						
							|  |  |  | #include "pycore_pylifecycle.h"   // _PyErr_Print()
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | #include "pycore_pymem.h"         // _PyMem_IsPtrFreed()
 | 
					
						
							| 
									
										
										
										
											2023-09-06 17:54:59 +02:00
										 |  |  | #include "pycore_pystats.h"       // _Py_PrintSpecializationStats()
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |    Notes about the implementation: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    - The GIL is just a boolean variable (locked) whose access is protected | 
					
						
							|  |  |  |      by a mutex (gil_mutex), and whose changes are signalled by a condition | 
					
						
							|  |  |  |      variable (gil_cond). gil_mutex is taken for short periods of time, | 
					
						
							|  |  |  |      and therefore mostly uncontended. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    - In the GIL-holding thread, the main loop (PyEval_EvalFrameEx) must be | 
					
						
							|  |  |  |      able to release the GIL on demand by another thread. A volatile boolean | 
					
						
							|  |  |  |      variable (gil_drop_request) is used for that purpose, which is checked | 
					
						
							|  |  |  |      at every turn of the eval loop. That variable is set after a wait of | 
					
						
							|  |  |  |      `interval` microseconds on `gil_cond` has timed out. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [Actually, another volatile boolean variable (eval_breaker) is used | 
					
						
							|  |  |  |        which ORs several conditions into one. Volatile booleans are | 
					
						
							|  |  |  |        sufficient as inter-thread signalling means since Python is run | 
					
						
							|  |  |  |        on cache-coherent architectures only.] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    - A thread wanting to take the GIL will first let pass a given amount of | 
					
						
							|  |  |  |      time (`interval` microseconds) before setting gil_drop_request. This | 
					
						
							|  |  |  |      encourages a defined switching period, but doesn't enforce it since | 
					
						
							|  |  |  |      opcodes can take an arbitrary time to execute. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      The `interval` value is available for the user to read and modify | 
					
						
							|  |  |  |      using the Python API `sys.{get,set}switchinterval()`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    - When a thread releases the GIL and gil_drop_request is set, that thread | 
					
						
							|  |  |  |      ensures that another GIL-awaiting thread gets scheduled. | 
					
						
							|  |  |  |      It does so by waiting on a condition variable (switch_cond) until | 
					
						
							|  |  |  |      the value of last_holder is changed to something else than its | 
					
						
							|  |  |  |      own thread state pointer, indicating that another thread was able to | 
					
						
							|  |  |  |      take the GIL. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      This is meant to prohibit the latency-adverse behaviour on multi-core | 
					
						
							|  |  |  |      machines where one thread would speculatively release the GIL, but still | 
					
						
							|  |  |  |      run and end up being the first to re-acquire it, making the "timeslices" | 
					
						
							|  |  |  |      much longer than expected. | 
					
						
							|  |  |  |      (Note: this mechanism is enabled with FORCE_SWITCHING above) | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GH-89279: Force inlining by using a macro.
 | 
					
						
							|  |  |  | #if defined(_MSC_VER) && SIZEOF_INT == 4
 | 
					
						
							|  |  |  | #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) (assert(sizeof((ATOMIC_VAL)->_value) == 4), *((volatile int*)&((ATOMIC_VAL)->_value)))
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | /* bpo-40010: eval_breaker should be recomputed if there
 | 
					
						
							|  |  |  |    is a pending signal: signal received by another thread which cannot | 
					
						
							|  |  |  |    handle signals. | 
					
						
							|  |  |  |    Similarly, we set CALLS_TO_DO and ASYNC_EXCEPTION to match the thread. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | static inline void | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | update_eval_breaker_from_thread(PyInterpreterState *interp, PyThreadState *tstate) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (tstate == NULL) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (_Py_IsMainThread()) { | 
					
						
							|  |  |  |         int32_t calls_to_do = _Py_atomic_load_int32_relaxed( | 
					
						
							|  |  |  |             &_PyRuntime.ceval.pending_mainthread.calls_to_do); | 
					
						
							|  |  |  |         if (calls_to_do) { | 
					
						
							|  |  |  |             _Py_set_eval_breaker_bit(interp, _PY_CALLS_TO_DO_BIT, 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (_Py_ThreadCanHandleSignals(interp)) { | 
					
						
							| 
									
										
										
										
											2023-10-10 08:26:29 +09:00
										 |  |  |             if (_Py_atomic_load_int(&_PyRuntime.signals.is_tripped)) { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |                 _Py_set_eval_breaker_bit(interp, _PY_SIGNALS_PENDING_BIT, 1); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (tstate->async_exc != NULL) { | 
					
						
							|  |  |  |         _Py_set_eval_breaker_bit(interp, _PY_ASYNC_EXCEPTION_BIT, 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | SET_GIL_DROP_REQUEST(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     _Py_set_eval_breaker_bit(interp, _PY_GIL_DROP_REQUEST_BIT, 1); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | RESET_GIL_DROP_REQUEST(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     _Py_set_eval_breaker_bit(interp, _PY_GIL_DROP_REQUEST_BIT, 0); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | SIGNAL_PENDING_CALLS(PyInterpreterState *interp) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     _Py_set_eval_breaker_bit(interp, _PY_CALLS_TO_DO_BIT, 1); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     _Py_set_eval_breaker_bit(interp, _PY_CALLS_TO_DO_BIT, 0); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Implementation of the Global Interpreter Lock (GIL). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "condvar.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MUTEX_INIT(mut) \
 | 
					
						
							|  |  |  |     if (PyMUTEX_INIT(&(mut))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyMUTEX_INIT(" #mut ") failed"); }; | 
					
						
							|  |  |  | #define MUTEX_FINI(mut) \
 | 
					
						
							|  |  |  |     if (PyMUTEX_FINI(&(mut))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyMUTEX_FINI(" #mut ") failed"); }; | 
					
						
							|  |  |  | #define MUTEX_LOCK(mut) \
 | 
					
						
							|  |  |  |     if (PyMUTEX_LOCK(&(mut))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyMUTEX_LOCK(" #mut ") failed"); }; | 
					
						
							|  |  |  | #define MUTEX_UNLOCK(mut) \
 | 
					
						
							|  |  |  |     if (PyMUTEX_UNLOCK(&(mut))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyMUTEX_UNLOCK(" #mut ") failed"); }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define COND_INIT(cond) \
 | 
					
						
							|  |  |  |     if (PyCOND_INIT(&(cond))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyCOND_INIT(" #cond ") failed"); }; | 
					
						
							|  |  |  | #define COND_FINI(cond) \
 | 
					
						
							|  |  |  |     if (PyCOND_FINI(&(cond))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyCOND_FINI(" #cond ") failed"); }; | 
					
						
							|  |  |  | #define COND_SIGNAL(cond) \
 | 
					
						
							|  |  |  |     if (PyCOND_SIGNAL(&(cond))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyCOND_SIGNAL(" #cond ") failed"); }; | 
					
						
							|  |  |  | #define COND_WAIT(cond, mut) \
 | 
					
						
							|  |  |  |     if (PyCOND_WAIT(&(cond), &(mut))) { \ | 
					
						
							|  |  |  |         Py_FatalError("PyCOND_WAIT(" #cond ") failed"); }; | 
					
						
							|  |  |  | #define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \
 | 
					
						
							|  |  |  |     { \ | 
					
						
							|  |  |  |         int r = PyCOND_TIMEDWAIT(&(cond), &(mut), (microseconds)); \ | 
					
						
							|  |  |  |         if (r < 0) \ | 
					
						
							|  |  |  |             Py_FatalError("PyCOND_WAIT(" #cond ") failed"); \ | 
					
						
							|  |  |  |         if (r) /* 1 == timeout, 2 == impl. can't say, so assume timeout */ \ | 
					
						
							|  |  |  |             timeout_result = 1; \ | 
					
						
							|  |  |  |         else \ | 
					
						
							|  |  |  |             timeout_result = 0; \ | 
					
						
							|  |  |  |     } \ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define DEFAULT_INTERVAL 5000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void _gil_initialize(struct _gil_runtime_state *gil) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     gil->locked = -1; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     gil->interval = DEFAULT_INTERVAL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int gil_created(struct _gil_runtime_state *gil) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     if (gil == NULL) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     return (_Py_atomic_load_int_acquire(&gil->locked) >= 0); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void create_gil(struct _gil_runtime_state *gil) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MUTEX_INIT(gil->mutex); | 
					
						
							|  |  |  | #ifdef FORCE_SWITCHING
 | 
					
						
							|  |  |  |     MUTEX_INIT(gil->switch_mutex); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     COND_INIT(gil->cond); | 
					
						
							|  |  |  | #ifdef FORCE_SWITCHING
 | 
					
						
							|  |  |  |     COND_INIT(gil->switch_cond); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-10-13 10:07:27 +09:00
										 |  |  |     _Py_atomic_store_ptr_relaxed(&gil->last_holder, 0); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     _Py_ANNOTATE_RWLOCK_CREATE(&gil->locked); | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     _Py_atomic_store_int_release(&gil->locked, 0); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void destroy_gil(struct _gil_runtime_state *gil) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* some pthread-like implementations tie the mutex to the cond
 | 
					
						
							|  |  |  |      * and must have the cond destroyed first. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     COND_FINI(gil->cond); | 
					
						
							|  |  |  |     MUTEX_FINI(gil->mutex); | 
					
						
							|  |  |  | #ifdef FORCE_SWITCHING
 | 
					
						
							|  |  |  |     COND_FINI(gil->switch_cond); | 
					
						
							|  |  |  |     MUTEX_FINI(gil->switch_mutex); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     _Py_atomic_store_int_release(&gil->locked, -1); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_FORK
 | 
					
						
							|  |  |  | static void recreate_gil(struct _gil_runtime_state *gil) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked); | 
					
						
							|  |  |  |     /* XXX should we destroy the old OS resources here? */ | 
					
						
							|  |  |  |     create_gil(gil); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | drop_gil(PyInterpreterState *interp, PyThreadState *tstate) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     struct _ceval_state *ceval = &interp->ceval; | 
					
						
							| 
									
										
										
										
											2023-06-01 16:24:10 -06:00
										 |  |  |     /* If tstate is NULL, the caller is indicating that we're releasing
 | 
					
						
							|  |  |  |        the GIL for the last time in this thread.  This is particularly | 
					
						
							|  |  |  |        relevant when the current thread state is finalizing or its | 
					
						
							|  |  |  |        interpreter is finalizing (either may be in an inconsistent | 
					
						
							|  |  |  |        state).  In that case the current thread will definitely | 
					
						
							|  |  |  |        never try to acquire the GIL again. */ | 
					
						
							|  |  |  |     // XXX It may be more correct to check tstate->_status.finalizing.
 | 
					
						
							|  |  |  |     // XXX assert(tstate == NULL || !tstate->_status.cleared);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     struct _gil_runtime_state *gil = ceval->gil; | 
					
						
							| 
									
										
										
										
											2023-10-13 10:07:27 +09:00
										 |  |  |     if (!_Py_atomic_load_ptr_relaxed(&gil->locked)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         Py_FatalError("drop_gil: GIL is not locked"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* tstate is allowed to be NULL (early interpreter init) */ | 
					
						
							|  |  |  |     if (tstate != NULL) { | 
					
						
							|  |  |  |         /* Sub-interpreter support: threads might have been switched
 | 
					
						
							|  |  |  |            under our feet using PyThreadState_Swap(). Fix the GIL last | 
					
						
							|  |  |  |            holder variable so that our heuristics work. */ | 
					
						
							| 
									
										
										
										
											2023-10-13 10:07:27 +09:00
										 |  |  |         _Py_atomic_store_ptr_relaxed(&gil->last_holder, tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MUTEX_LOCK(gil->mutex); | 
					
						
							|  |  |  |     _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1); | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     _Py_atomic_store_int_relaxed(&gil->locked, 0); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     COND_SIGNAL(gil->cond); | 
					
						
							|  |  |  |     MUTEX_UNLOCK(gil->mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef FORCE_SWITCHING
 | 
					
						
							| 
									
										
										
										
											2023-06-01 16:24:10 -06:00
										 |  |  |     /* We check tstate first in case we might be releasing the GIL for
 | 
					
						
							|  |  |  |        the last time in this thread.  In that case there's a possible | 
					
						
							|  |  |  |        race with tstate->interp getting deleted after gil->mutex is | 
					
						
							|  |  |  |        unlocked and before the following code runs, leading to a crash. | 
					
						
							|  |  |  |        We can use (tstate == NULL) to indicate the thread is done with | 
					
						
							|  |  |  |        the GIL, and that's the only time we might delete the | 
					
						
							|  |  |  |        interpreter, so checking tstate first prevents the crash. | 
					
						
							|  |  |  |        See https://github.com/python/cpython/issues/104341. */
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (tstate != NULL && _Py_eval_breaker_bit_is_set(interp, _PY_GIL_DROP_REQUEST_BIT)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         MUTEX_LOCK(gil->switch_mutex); | 
					
						
							|  |  |  |         /* Not switched yet => wait */ | 
					
						
							| 
									
										
										
										
											2023-10-13 10:07:27 +09:00
										 |  |  |         if (((PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder)) == tstate) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |             assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |             RESET_GIL_DROP_REQUEST(tstate->interp); | 
					
						
							|  |  |  |             /* NOTE: if COND_WAIT does not atomically start waiting when
 | 
					
						
							|  |  |  |                releasing the mutex, another thread can run through, take | 
					
						
							|  |  |  |                the GIL and drop it again, and reset the condition | 
					
						
							|  |  |  |                before we even had a chance to wait for it. */ | 
					
						
							|  |  |  |             COND_WAIT(gil->switch_cond, gil->switch_mutex); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         MUTEX_UNLOCK(gil->switch_mutex); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Take the GIL.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    The function saves errno at entry and restores its value at exit. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    tstate must be non-NULL. */ | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | take_gil(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int err = errno; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert(tstate != NULL); | 
					
						
							| 
									
										
										
										
											2023-06-01 16:24:10 -06:00
										 |  |  |     /* We shouldn't be using a thread state that isn't viable any more. */ | 
					
						
							|  |  |  |     // XXX It may be more correct to check tstate->_status.finalizing.
 | 
					
						
							|  |  |  |     // XXX assert(!tstate->_status.cleared);
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 17:27:03 +02:00
										 |  |  |     if (_PyThreadState_MustExit(tstate)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         /* bpo-39877: If Py_Finalize() has been called and tstate is not the
 | 
					
						
							|  |  |  |            thread which called Py_Finalize(), exit immediately the thread. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            This code path can be reached by a daemon thread after Py_Finalize() | 
					
						
							|  |  |  |            completes. In this case, tstate is a dangling pointer: points to | 
					
						
							|  |  |  |            PyThreadState freed memory. */ | 
					
						
							|  |  |  |         PyThread_exit_thread(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |     assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     struct _gil_runtime_state *gil = interp->ceval.gil; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Check that _PyEval_InitThreads() was called to create the lock */ | 
					
						
							|  |  |  |     assert(gil_created(gil)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MUTEX_LOCK(gil->mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     if (!_Py_atomic_load_int_relaxed(&gil->locked)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         goto _ready; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 00:13:56 +02:00
										 |  |  |     int drop_requested = 0; | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     while (_Py_atomic_load_int_relaxed(&gil->locked)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         unsigned long saved_switchnum = gil->switch_number; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         unsigned long interval = (gil->interval >= 1 ? gil->interval : 1); | 
					
						
							|  |  |  |         int timed_out = 0; | 
					
						
							|  |  |  |         COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* If we timed out and no switch occurred in the meantime, it is time
 | 
					
						
							|  |  |  |            to ask the GIL-holding thread to drop it. */ | 
					
						
							|  |  |  |         if (timed_out && | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |             _Py_atomic_load_int_relaxed(&gil->locked) && | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |             gil->switch_number == saved_switchnum) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2023-09-11 17:27:03 +02:00
										 |  |  |             if (_PyThreadState_MustExit(tstate)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |                 MUTEX_UNLOCK(gil->mutex); | 
					
						
							| 
									
										
										
										
											2022-09-20 00:13:56 +02:00
										 |  |  |                 // gh-96387: If the loop requested a drop request in a previous
 | 
					
						
							|  |  |  |                 // iteration, reset the request. Otherwise, drop_gil() can
 | 
					
						
							|  |  |  |                 // block forever waiting for the thread which exited. Drop
 | 
					
						
							|  |  |  |                 // requests made by other threads are also reset: these threads
 | 
					
						
							|  |  |  |                 // may have to request again a drop request (iterate one more
 | 
					
						
							|  |  |  |                 // time).
 | 
					
						
							|  |  |  |                 if (drop_requested) { | 
					
						
							|  |  |  |                     RESET_GIL_DROP_REQUEST(interp); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |                 PyThread_exit_thread(); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |             assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             SET_GIL_DROP_REQUEST(interp); | 
					
						
							| 
									
										
										
										
											2022-09-20 00:13:56 +02:00
										 |  |  |             drop_requested = 1; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _ready: | 
					
						
							|  |  |  | #ifdef FORCE_SWITCHING
 | 
					
						
							|  |  |  |     /* This mutex must be taken before modifying gil->last_holder:
 | 
					
						
							|  |  |  |        see drop_gil(). */ | 
					
						
							|  |  |  |     MUTEX_LOCK(gil->switch_mutex); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     /* We now hold the GIL */ | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     _Py_atomic_store_int_relaxed(&gil->locked, 1); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil->locked, /*is_write=*/1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-13 10:07:27 +09:00
										 |  |  |     if (tstate != (PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder)) { | 
					
						
							|  |  |  |         _Py_atomic_store_ptr_relaxed(&gil->last_holder, tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         ++gil->switch_number; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef FORCE_SWITCHING
 | 
					
						
							|  |  |  |     COND_SIGNAL(gil->switch_cond); | 
					
						
							|  |  |  |     MUTEX_UNLOCK(gil->switch_mutex); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 17:27:03 +02:00
										 |  |  |     if (_PyThreadState_MustExit(tstate)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         /* bpo-36475: If Py_Finalize() has been called and tstate is not
 | 
					
						
							|  |  |  |            the thread which called Py_Finalize(), exit immediately the | 
					
						
							|  |  |  |            thread. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            This code path can be reached by a daemon thread which was waiting | 
					
						
							|  |  |  |            in take_gil() while the main thread called | 
					
						
							|  |  |  |            wait_for_thread_shutdown() from Py_Finalize(). */ | 
					
						
							|  |  |  |         MUTEX_UNLOCK(gil->mutex); | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |         drop_gil(interp, tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         PyThread_exit_thread(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |     assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     RESET_GIL_DROP_REQUEST(interp); | 
					
						
							|  |  |  |     update_eval_breaker_from_thread(interp, tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     MUTEX_UNLOCK(gil->mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     errno = err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void _PyEval_SetSwitchInterval(unsigned long microseconds) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     struct _gil_runtime_state *gil = interp->ceval.gil; | 
					
						
							|  |  |  |     assert(gil != NULL); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     gil->interval = microseconds; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-05 10:22:33 +03:00
										 |  |  | unsigned long _PyEval_GetSwitchInterval(void) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     struct _gil_runtime_state *gil = interp->ceval.gil; | 
					
						
							|  |  |  |     assert(gil != NULL); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     return gil->interval; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  | _PyEval_ThreadsInitialized(void) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  |     /* XXX This is only needed for an assert in PyGILState_Ensure(),
 | 
					
						
							|  |  |  |      * which currently does not work with subinterpreters. | 
					
						
							|  |  |  |      * Thus we only use the main interpreter. */ | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_Main(); | 
					
						
							|  |  |  |     if (interp == NULL) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     struct _gil_runtime_state *gil = interp->ceval.gil; | 
					
						
							|  |  |  |     return gil_created(gil); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 13:41:56 +02:00
										 |  |  | // Function removed in the Python 3.13 API but kept in the stable ABI.
 | 
					
						
							|  |  |  | PyAPI_FUNC(int) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | PyEval_ThreadsInitialized(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     return _PyEval_ThreadsInitialized(); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 15:59:30 -06:00
										 |  |  | static inline int | 
					
						
							|  |  |  | current_thread_holds_gil(struct _gil_runtime_state *gil, PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-13 10:07:27 +09:00
										 |  |  |     if (((PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder)) != tstate) { | 
					
						
							| 
									
										
										
										
											2023-05-06 15:59:30 -06:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-17 07:32:50 +09:00
										 |  |  |     return _Py_atomic_load_int_relaxed(&gil->locked); | 
					
						
							| 
									
										
										
										
											2023-05-06 15:59:30 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | init_shared_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(gil_created(gil)); | 
					
						
							|  |  |  |     interp->ceval.gil = gil; | 
					
						
							|  |  |  |     interp->ceval.own_gil = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | init_own_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(!gil_created(gil)); | 
					
						
							|  |  |  |     create_gil(gil); | 
					
						
							|  |  |  |     assert(gil_created(gil)); | 
					
						
							|  |  |  |     interp->ceval.gil = gil; | 
					
						
							|  |  |  |     interp->ceval.own_gil = 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | PyStatus | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  | _PyEval_InitGIL(PyThreadState *tstate, int own_gil) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     assert(tstate->interp->ceval.gil == NULL); | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  |     if (!own_gil) { | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  |         /* The interpreter will share the main interpreter's instead. */ | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  |         PyInterpreterState *main_interp = _PyInterpreterState_Main(); | 
					
						
							|  |  |  |         assert(tstate->interp != main_interp); | 
					
						
							|  |  |  |         struct _gil_runtime_state *gil = main_interp->ceval.gil; | 
					
						
							| 
									
										
										
										
											2023-05-06 15:59:30 -06:00
										 |  |  |         init_shared_gil(tstate->interp, gil); | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |         assert(!current_thread_holds_gil(gil, tstate)); | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-06 15:59:30 -06:00
										 |  |  |     else { | 
					
						
							|  |  |  |         PyThread_init_thread(); | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  |         init_own_gil(tstate->interp, &tstate->interp->_gil); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |     // Lock the GIL and mark the current thread as attached.
 | 
					
						
							|  |  |  |     _PyThreadState_Attach(tstate); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     return _PyStatus_OK(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _PyEval_FiniGIL(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  |     struct _gil_runtime_state *gil = interp->ceval.gil; | 
					
						
							|  |  |  |     if (gil == NULL) { | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |         /* It was already finalized (or hasn't been initialized yet). */ | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  |         assert(!interp->ceval.own_gil); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!interp->ceval.own_gil) { | 
					
						
							| 
									
										
										
										
											2023-05-06 17:58:32 +03:00
										 |  |  | #ifdef Py_DEBUG
 | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  |         PyInterpreterState *main_interp = _PyInterpreterState_Main(); | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  |         assert(main_interp != NULL && interp != main_interp); | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  |         assert(interp->ceval.gil == main_interp->ceval.gil); | 
					
						
							| 
									
										
										
										
											2023-05-06 17:58:32 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-05-05 15:59:20 -06:00
										 |  |  |         interp->ceval.gil = NULL; | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     if (!gil_created(gil)) { | 
					
						
							|  |  |  |         /* First Py_InitializeFromConfig() call: the GIL doesn't exist
 | 
					
						
							|  |  |  |            yet: do nothing. */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     destroy_gil(gil); | 
					
						
							|  |  |  |     assert(!gil_created(gil)); | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     interp->ceval.gil = NULL; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 13:41:56 +02:00
										 |  |  | // Function removed in the Python 3.13 API but kept in the stable ABI.
 | 
					
						
							|  |  |  | PyAPI_FUNC(void) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | PyEval_InitThreads(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* Do nothing: kept for backward compatibility */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _PyEval_Fini(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef Py_STATS
 | 
					
						
							|  |  |  |     _Py_PrintSpecializationStats(1); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-06-01 13:41:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Function removed in the Python 3.13 API but kept in the stable ABI.
 | 
					
						
							|  |  |  | PyAPI_FUNC(void) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | PyEval_AcquireLock(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-04 16:21:01 +02:00
										 |  |  |     PyThreadState *tstate = _PyThreadState_GET(); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     _Py_EnsureTstateNotNULL(tstate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     take_gil(tstate); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 13:41:56 +02:00
										 |  |  | // Function removed in the Python 3.13 API but kept in the stable ABI.
 | 
					
						
							|  |  |  | PyAPI_FUNC(void) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | PyEval_ReleaseLock(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-04 16:21:01 +02:00
										 |  |  |     PyThreadState *tstate = _PyThreadState_GET(); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     /* This function must succeed when the current thread state is NULL.
 | 
					
						
							|  |  |  |        We therefore avoid PyThreadState_Get() which dumps a fatal error | 
					
						
							|  |  |  |        in debug mode. */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     drop_gil(tstate->interp, tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 15:59:30 -06:00
										 |  |  | void | 
					
						
							|  |  |  | _PyEval_AcquireLock(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_EnsureTstateNotNULL(tstate); | 
					
						
							|  |  |  |     take_gil(tstate); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2023-06-01 16:24:10 -06:00
										 |  |  | _PyEval_ReleaseLock(PyInterpreterState *interp, PyThreadState *tstate) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-06-01 16:24:10 -06:00
										 |  |  |     /* If tstate is NULL then we do not expect the current thread
 | 
					
						
							|  |  |  |        to acquire the GIL ever again. */ | 
					
						
							|  |  |  |     assert(tstate == NULL || tstate->interp == interp); | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     drop_gil(interp, tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | PyEval_AcquireThread(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_EnsureTstateNotNULL(tstate); | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |     _PyThreadState_Attach(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | PyEval_ReleaseThread(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |     assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |     _PyThreadState_Detach(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_FORK
 | 
					
						
							|  |  |  | /* This function is called from PyOS_AfterFork_Child to destroy all threads
 | 
					
						
							|  |  |  |    which are not running in the child process, and clear internal locks | 
					
						
							|  |  |  |    which might be held by those threads. */ | 
					
						
							|  |  |  | PyStatus | 
					
						
							|  |  |  | _PyEval_ReInitThreads(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     assert(tstate->interp == _PyInterpreterState_Main()); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-05 13:23:00 -06:00
										 |  |  |     struct _gil_runtime_state *gil = tstate->interp->ceval.gil; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     if (!gil_created(gil)) { | 
					
						
							|  |  |  |         return _PyStatus_OK(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     recreate_gil(gil); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     take_gil(tstate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     struct _pending_calls *pending = &tstate->interp->ceval.pending; | 
					
						
							|  |  |  |     if (_PyThread_at_fork_reinit(&pending->lock) < 0) { | 
					
						
							|  |  |  |         return _PyStatus_ERR("Can't reinitialize pending calls lock"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Destroy all threads except the current one */ | 
					
						
							| 
									
										
										
										
											2023-01-30 12:07:48 -07:00
										 |  |  |     _PyThreadState_DeleteExcept(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     return _PyStatus_OK(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This function is used to signal that async exceptions are waiting to be
 | 
					
						
							|  |  |  |    raised. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _PyEval_SignalAsyncExc(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     _Py_set_eval_breaker_bit(interp, _PY_ASYNC_EXCEPTION_BIT, 1); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyThreadState * | 
					
						
							|  |  |  | PyEval_SaveThread(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |     PyThreadState *tstate = _PyThreadState_GET(); | 
					
						
							|  |  |  |     _PyThreadState_Detach(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     return tstate; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | PyEval_RestoreThread(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_EnsureTstateNotNULL(tstate); | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |     _PyThreadState_Attach(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Mechanism whereby asynchronously executing callbacks (e.g. UNIX
 | 
					
						
							|  |  |  |    signal handlers or Mac I/O completion routines) can schedule calls | 
					
						
							|  |  |  |    to a function to be called synchronously. | 
					
						
							|  |  |  |    The synchronous function is called with one void* argument. | 
					
						
							|  |  |  |    It should return 0 for success or -1 for failure -- failure should | 
					
						
							|  |  |  |    be accompanied by an exception. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    If registry succeeds, the registry function returns 0; if it fails | 
					
						
							|  |  |  |    (e.g. due to too many pending calls) it returns -1 (without setting | 
					
						
							|  |  |  |    an exception condition). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Note that because registry may occur from within signal handlers, | 
					
						
							|  |  |  |    or other asynchronous events, calling malloc() is unsafe! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Any thread can schedule pending calls, but only the main thread | 
					
						
							|  |  |  |    will execute them. | 
					
						
							|  |  |  |    There is no facility to schedule calls to a particular thread, but | 
					
						
							|  |  |  |    that should be easy to change, should that ever be required.  In | 
					
						
							|  |  |  |    that case, the static variables here should go into the python | 
					
						
							|  |  |  |    threadstate. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _PyEval_SignalReceived(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (_Py_ThreadCanHandleSignals(interp)) { | 
					
						
							|  |  |  |         _Py_set_eval_breaker_bit(interp, _PY_SIGNALS_PENDING_BIT, 1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Push one item onto the queue while holding the lock. */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _push_pending_call(struct _pending_calls *pending, | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |                    _Py_pending_call_func func, void *arg, int flags) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     int i = pending->last; | 
					
						
							|  |  |  |     int j = (i + 1) % NPENDINGCALLS; | 
					
						
							|  |  |  |     if (j == pending->first) { | 
					
						
							|  |  |  |         return -1; /* Queue full */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     pending->calls[i].func = func; | 
					
						
							|  |  |  |     pending->calls[i].arg = arg; | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |     pending->calls[i].flags = flags; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     pending->last = j; | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     assert(pending->calls_to_do < NPENDINGCALLS); | 
					
						
							|  |  |  |     pending->calls_to_do++; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  | static int | 
					
						
							|  |  |  | _next_pending_call(struct _pending_calls *pending, | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |                    int (**func)(void *), void **arg, int *flags) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     int i = pending->first; | 
					
						
							|  |  |  |     if (i == pending->last) { | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |         /* Queue empty */ | 
					
						
							|  |  |  |         assert(pending->calls[i].func == NULL); | 
					
						
							|  |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     *func = pending->calls[i].func; | 
					
						
							|  |  |  |     *arg = pending->calls[i].arg; | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |     *flags = pending->calls[i].flags; | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     return i; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Pop one item off the queue while holding the lock. */ | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | _pop_pending_call(struct _pending_calls *pending, | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |                   int (**func)(void *), void **arg, int *flags) | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |     int i = _next_pending_call(pending, func, arg, flags); | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     if (i >= 0) { | 
					
						
							|  |  |  |         pending->calls[i] = (struct _pending_call){0}; | 
					
						
							|  |  |  |         pending->first = (i + 1) % NPENDINGCALLS; | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |         assert(pending->calls_to_do > 0); | 
					
						
							|  |  |  |         pending->calls_to_do--; | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This implementation is thread-safe.  It allows
 | 
					
						
							|  |  |  |    scheduling to be made from any thread, and even from an executing | 
					
						
							|  |  |  |    callback. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | _PyEval_AddPendingCall(PyInterpreterState *interp, | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |                        _Py_pending_call_func func, void *arg, int flags) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |     assert(!(flags & _Py_PENDING_MAINTHREADONLY) | 
					
						
							|  |  |  |            || _Py_IsMainInterpreter(interp)); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     struct _pending_calls *pending = &interp->ceval.pending; | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |     if (flags & _Py_PENDING_MAINTHREADONLY) { | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |         /* The main thread only exists in the main interpreter. */ | 
					
						
							|  |  |  |         assert(_Py_IsMainInterpreter(interp)); | 
					
						
							|  |  |  |         pending = &_PyRuntime.ceval.pending_mainthread; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     /* Ensure that _PyEval_InitState() was called
 | 
					
						
							|  |  |  |        and that _PyEval_FiniState() is not called yet. */ | 
					
						
							|  |  |  |     assert(pending->lock != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyThread_acquire_lock(pending->lock, WAIT_LOCK); | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |     int result = _push_pending_call(pending, func, arg, flags); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     PyThread_release_lock(pending->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* signal main loop */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     SIGNAL_PENDING_CALLS(interp); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2023-09-19 15:01:34 -06:00
										 |  |  | Py_AddPendingCall(_Py_pending_call_func func, void *arg) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     /* Legacy users of this API will continue to target the main thread
 | 
					
						
							|  |  |  |        (of the main interpreter). */ | 
					
						
							|  |  |  |     PyInterpreterState *interp = _PyInterpreterState_Main(); | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |     return _PyEval_AddPendingCall(interp, func, arg, _Py_PENDING_MAINTHREADONLY); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | handle_signals(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |     assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     _Py_set_eval_breaker_bit(tstate->interp, _PY_SIGNALS_PENDING_BIT, 0); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     if (!_Py_ThreadCanHandleSignals(tstate->interp)) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (_PyErr_CheckSignalsTstate(tstate) < 0) { | 
					
						
							|  |  |  |         /* On failure, re-schedule a call to handle_signals(). */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |         _Py_set_eval_breaker_bit(tstate->interp, _PY_SIGNALS_PENDING_BIT, 1); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  | static int | 
					
						
							|  |  |  | _make_pending_calls(struct _pending_calls *pending) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     /* perform a bounded number of calls, in case of recursion */ | 
					
						
							|  |  |  |     for (int i=0; i<NPENDINGCALLS; i++) { | 
					
						
							| 
									
										
										
										
											2023-09-19 15:01:34 -06:00
										 |  |  |         _Py_pending_call_func func = NULL; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         void *arg = NULL; | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |         int flags = 0; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* pop one item off the queue while holding the lock */ | 
					
						
							|  |  |  |         PyThread_acquire_lock(pending->lock, WAIT_LOCK); | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |         _pop_pending_call(pending, &func, &arg, &flags); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         PyThread_release_lock(pending->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* having released the lock, perform the callback */ | 
					
						
							|  |  |  |         if (func == NULL) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |         int res = func(arg); | 
					
						
							|  |  |  |         if ((flags & _Py_PENDING_RAWFREE) && arg != NULL) { | 
					
						
							|  |  |  |             PyMem_RawFree(arg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (res != 0) { | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | make_pending_calls(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct _pending_calls *pending = &interp->ceval.pending; | 
					
						
							|  |  |  |     struct _pending_calls *pending_main = &_PyRuntime.ceval.pending_mainthread; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Only one thread (per interpreter) may run the pending calls
 | 
					
						
							|  |  |  |        at once.  In the same way, we don't do recursive pending calls. */ | 
					
						
							|  |  |  |     PyThread_acquire_lock(pending->lock, WAIT_LOCK); | 
					
						
							|  |  |  |     if (pending->busy) { | 
					
						
							|  |  |  |         /* A pending call was added after another thread was already
 | 
					
						
							|  |  |  |            handling the pending calls (and had already "unsignaled"). | 
					
						
							|  |  |  |            Once that thread is done, it may have taken care of all the | 
					
						
							|  |  |  |            pending calls, or there might be some still waiting. | 
					
						
							|  |  |  |            Regardless, this interpreter's pending calls will stay | 
					
						
							|  |  |  |            "signaled" until that first thread has finished.  At that | 
					
						
							|  |  |  |            point the next thread to trip the eval breaker will take | 
					
						
							|  |  |  |            care of any remaining pending calls.  Until then, though, | 
					
						
							|  |  |  |            all the interpreter's threads will be tripping the eval | 
					
						
							|  |  |  |            breaker every time it's checked. */ | 
					
						
							|  |  |  |         PyThread_release_lock(pending->lock); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     pending->busy = 1; | 
					
						
							|  |  |  |     PyThread_release_lock(pending->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* unsignal before starting to call callbacks, so that any callback
 | 
					
						
							|  |  |  |        added in-between re-signals */ | 
					
						
							|  |  |  |     UNSIGNAL_PENDING_CALLS(interp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (_make_pending_calls(pending) != 0) { | 
					
						
							|  |  |  |         pending->busy = 0; | 
					
						
							|  |  |  |         /* There might not be more calls to make, but we play it safe. */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |         SIGNAL_PENDING_CALLS(interp); | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) { | 
					
						
							|  |  |  |         if (_make_pending_calls(pending_main) != 0) { | 
					
						
							|  |  |  |             pending->busy = 0; | 
					
						
							|  |  |  |             /* There might not be more calls to make, but we play it safe. */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |             SIGNAL_PENDING_CALLS(interp); | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     pending->busy = 0; | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _Py_FinishPendingCalls(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(PyGILState_Check()); | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |     assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (make_pending_calls(tstate->interp) < 0) { | 
					
						
							| 
									
										
										
										
											2023-02-28 11:50:52 +00:00
										 |  |  |         PyObject *exc = _PyErr_GetRaisedException(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         PyErr_BadInternalCall(); | 
					
						
							| 
									
										
										
										
											2023-02-28 11:50:52 +00:00
										 |  |  |         _PyErr_ChainExceptions1(exc); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         _PyErr_Print(tstate); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  | int | 
					
						
							|  |  |  | _PyEval_MakePendingCalls(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (_Py_IsMainThread() && _Py_IsMainInterpreter(tstate->interp)) { | 
					
						
							|  |  |  |         /* Python signal handler doesn't really queue a callback:
 | 
					
						
							|  |  |  |            it only signals that a signal was received, | 
					
						
							|  |  |  |            see _PyEval_SignalReceived(). */ | 
					
						
							|  |  |  |         res = handle_signals(tstate); | 
					
						
							|  |  |  |         if (res != 0) { | 
					
						
							|  |  |  |             return res; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res = make_pending_calls(tstate->interp); | 
					
						
							|  |  |  |     if (res != 0) { | 
					
						
							|  |  |  |         return res; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | /* Py_MakePendingCalls() is a simple wrapper for the sake
 | 
					
						
							|  |  |  |    of backward-compatibility. */ | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | Py_MakePendingCalls(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(PyGILState_Check()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyThreadState *tstate = _PyThreadState_GET(); | 
					
						
							| 
									
										
										
										
											2023-09-08 11:50:46 +02:00
										 |  |  |     assert(_PyThreadState_CheckConsistency(tstate)); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     /* Only execute pending calls on the main thread. */ | 
					
						
							|  |  |  |     if (!_Py_IsMainThread() || !_Py_IsMainInterpreter(tstate->interp)) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-13 15:02:19 -06:00
										 |  |  |     return _PyEval_MakePendingCalls(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  | _PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  |     _gil_initialize(&interp->_gil); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-08 13:15:09 -06:00
										 |  |  |     struct _pending_calls *pending = &interp->ceval.pending; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     assert(pending->lock == NULL); | 
					
						
							|  |  |  |     pending->lock = pending_lock; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _PyEval_FiniState(struct _ceval_state *ceval) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct _pending_calls *pending = &ceval->pending; | 
					
						
							|  |  |  |     if (pending->lock != NULL) { | 
					
						
							|  |  |  |         PyThread_free_lock(pending->lock); | 
					
						
							|  |  |  |         pending->lock = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-03 21:28:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Do periodic things, like check for signals and async I/0.
 | 
					
						
							|  |  |  | * We need to do reasonably frequently, but not too frequently. | 
					
						
							|  |  |  | * All loops should include a check of the eval breaker. | 
					
						
							|  |  |  | * We also check on return from any builtin function. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * ## More Details ### | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * The eval loop (this function) normally executes the instructions | 
					
						
							|  |  |  | * of a code object sequentially.  However, the runtime supports a | 
					
						
							|  |  |  | * number of out-of-band execution scenarios that may pause that | 
					
						
							|  |  |  | * sequential execution long enough to do that out-of-band work | 
					
						
							|  |  |  | * in the current thread using the current PyThreadState. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * The scenarios include: | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | *  - cyclic garbage collection | 
					
						
							|  |  |  | *  - GIL drop requests | 
					
						
							|  |  |  | *  - "async" exceptions | 
					
						
							|  |  |  | *  - "pending calls"  (some only in the main thread) | 
					
						
							|  |  |  | *  - signal handling (only in the main thread) | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * When the need for one of the above is detected, the eval loop | 
					
						
							|  |  |  | * pauses long enough to handle the detected case.  Then, if doing | 
					
						
							|  |  |  | * so didn't trigger an exception, the eval loop resumes executing | 
					
						
							|  |  |  | * the sequential instructions. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * To make this work, the eval loop periodically checks if any | 
					
						
							|  |  |  | * of the above needs to happen.  The individual checks can be | 
					
						
							|  |  |  | * expensive if computed each time, so a while back we switched | 
					
						
							|  |  |  | * to using pre-computed, per-interpreter variables for the checks, | 
					
						
							|  |  |  | * and later consolidated that to a single "eval breaker" variable | 
					
						
							|  |  |  | * (now a PyInterpreterState field). | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * For the longest time, the eval breaker check would happen | 
					
						
							|  |  |  | * frequently, every 5 or so times through the loop, regardless | 
					
						
							|  |  |  | * of what instruction ran last or what would run next.  Then, in | 
					
						
							|  |  |  | * early 2021 (gh-18334, commit 4958f5d), we switched to checking | 
					
						
							|  |  |  | * the eval breaker less frequently, by hard-coding the check to | 
					
						
							|  |  |  | * specific places in the eval loop (e.g. certain instructions). | 
					
						
							|  |  |  | * The intent then was to check after returning from calls | 
					
						
							|  |  |  | * and on the back edges of loops. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * In addition to being more efficient, that approach keeps | 
					
						
							|  |  |  | * the eval loop from running arbitrary code between instructions | 
					
						
							|  |  |  | * that don't handle that well.  (See gh-74174.) | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * Currently, the eval breaker check happens on back edges in | 
					
						
							|  |  |  | * the control flow graph, which pretty much applies to all loops, | 
					
						
							|  |  |  | * and most calls. | 
					
						
							|  |  |  | * (See bytecodes.c for exact information.) | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * One consequence of this approach is that it might not be obvious | 
					
						
							|  |  |  | * how to force any specific thread to pick up the eval breaker, | 
					
						
							|  |  |  | * or for any specific thread to not pick it up.  Mostly this | 
					
						
							|  |  |  | * involves judicious uses of locks and careful ordering of code, | 
					
						
							|  |  |  | * while avoiding code that might trigger the eval breaker | 
					
						
							|  |  |  | * until so desired. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | int | 
					
						
							|  |  |  | _Py_HandlePending(PyThreadState *tstate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Pending signals */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (_Py_eval_breaker_bit_is_set(interp, _PY_SIGNALS_PENDING_BIT)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         if (handle_signals(tstate) != 0) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Pending calls */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (_Py_eval_breaker_bit_is_set(interp, _PY_CALLS_TO_DO_BIT)) { | 
					
						
							|  |  |  |         if (make_pending_calls(interp) != 0) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-08 07:57:09 -07:00
										 |  |  |     /* GC scheduled to run */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (_Py_eval_breaker_bit_is_set(interp, _PY_GC_SCHEDULED_BIT)) { | 
					
						
							|  |  |  |         _Py_set_eval_breaker_bit(interp, _PY_GC_SCHEDULED_BIT, 0); | 
					
						
							| 
									
										
										
										
											2022-10-08 07:57:09 -07:00
										 |  |  |         _Py_RunGC(tstate); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     /* GIL drop request */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (_Py_eval_breaker_bit_is_set(interp, _PY_GIL_DROP_REQUEST_BIT)) { | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |         /* Give another thread a chance */ | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |         _PyThreadState_Detach(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* Other threads may run now */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-05 15:46:33 +00:00
										 |  |  |         _PyThreadState_Attach(tstate); | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Check for asynchronous exception. */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     if (_Py_eval_breaker_bit_is_set(interp, _PY_ASYNC_EXCEPTION_BIT)) { | 
					
						
							|  |  |  |         _Py_set_eval_breaker_bit(interp, _PY_ASYNC_EXCEPTION_BIT, 0); | 
					
						
							|  |  |  |         if (tstate->async_exc != NULL) { | 
					
						
							|  |  |  |             PyObject *exc = tstate->async_exc; | 
					
						
							|  |  |  |             tstate->async_exc = NULL; | 
					
						
							|  |  |  |             _PyErr_SetNone(tstate, exc); | 
					
						
							|  |  |  |             Py_DECREF(exc); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-08-24 14:21:01 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |