static void faulthandler_thread(void *unused) { PyLockStatus st; const char* errmsg; PyThreadState *current; int ok; do { st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_ms, 0); if (st == PY_LOCK_ACQUIRED) { /* Cancelled by user */ break; } /* Timeout => dump traceback */ assert(st == PY_LOCK_FAILURE); /* get the thread holding the GIL, NULL if no thread hold the GIL */ current = _Py_atomic_load_relaxed(&_PyThreadState_Current); errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current); ok = (errmsg == NULL); if (thread.exit) _exit(1); } while (ok && thread.repeat); /* The only way out */ PyThread_release_lock(thread.cancel_event); PyThread_release_lock(thread.join_event); }
/* Helper to acquire an interruptible lock with a timeout. If the lock acquire * is interrupted, signal handlers are run, and if they raise an exception, * PY_LOCK_INTR is returned. Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE * are returned, depending on whether the lock can be acquired withing the * timeout. */ static PyLockStatus acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) { PyLockStatus r; _PyTime_timeval curtime; _PyTime_timeval endtime; if (microseconds > 0) { _PyTime_monotonic(&endtime); endtime.tv_sec += microseconds / (1000 * 1000); endtime.tv_usec += microseconds % (1000 * 1000); } do { /* first a simple non-blocking try without releasing the GIL */ r = PyThread_acquire_lock_timed(lock, 0, 0); if (r == PY_LOCK_FAILURE && microseconds != 0) { Py_BEGIN_ALLOW_THREADS r = PyThread_acquire_lock_timed(lock, microseconds, 1); Py_END_ALLOW_THREADS } if (r == PY_LOCK_INTR) { /* Run signal handlers if we were interrupted. Propagate * exceptions from signal handlers, such as KeyboardInterrupt, by * passing up PY_LOCK_INTR. */ if (Py_MakePendingCalls() < 0) { return PY_LOCK_INTR; } /* If we're using a timeout, recompute the timeout after processing * signals, since those can take time. */ if (microseconds > 0) { _PyTime_monotonic(&curtime); microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 + (endtime.tv_usec - curtime.tv_usec)); /* Check for negative values, since those mean block forever. */ if (microseconds <= 0) { r = PY_LOCK_FAILURE; } } } } while (r == PY_LOCK_INTR); /* Retry if we were interrupted. */
/* Helper to acquire an interruptible lock with a timeout. If the lock acquire * is interrupted, signal handlers are run, and if they raise an exception, * PY_LOCK_INTR is returned. Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE * are returned, depending on whether the lock can be acquired within the * timeout. */ static PyLockStatus acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) { PyLockStatus r; _PyTime_t endtime = 0; _PyTime_t microseconds; if (timeout > 0) endtime = _PyTime_GetMonotonicClock() + timeout; do { microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING); /* first a simple non-blocking try without releasing the GIL */ r = PyThread_acquire_lock_timed(lock, 0, 0); if (r == PY_LOCK_FAILURE && microseconds != 0) { Py_BEGIN_ALLOW_THREADS r = PyThread_acquire_lock_timed(lock, microseconds, 1); Py_END_ALLOW_THREADS } if (r == PY_LOCK_INTR) { /* Run signal handlers if we were interrupted. Propagate * exceptions from signal handlers, such as KeyboardInterrupt, by * passing up PY_LOCK_INTR. */ if (Py_MakePendingCalls() < 0) { return PY_LOCK_INTR; } /* If we're using a timeout, recompute the timeout after processing * signals, since those can take time. */ if (timeout > 0) { timeout = endtime - _PyTime_GetMonotonicClock(); /* Check for negative values, since those mean block forever. */ if (timeout < 0) { r = PY_LOCK_FAILURE; } } } } while (r == PY_LOCK_INTR); /* Retry if we were interrupted. */
static void faulthandler_thread(void *unused) { PyLockStatus st; const char* errmsg; PyThreadState *current; int ok; #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) sigset_t set; /* we don't want to receive any signal */ sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); #endif do { st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_us, 0); if (st == PY_LOCK_ACQUIRED) { PyThread_release_lock(thread.cancel_event); break; } /* Timeout => dump traceback */ assert(st == PY_LOCK_FAILURE); /* get the thread holding the GIL, NULL if no thread hold the GIL */ current = _Py_atomic_load_relaxed(&_PyThreadState_Current); write(thread.fd, thread.header, thread.header_len); errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current); ok = (errmsg == NULL); if (thread.exit) _exit(1); } while (ok && thread.repeat); /* The only way out */ PyThread_release_lock(thread.running); }
static PyObject * _queue_SimpleQueue_get_impl(simplequeueobject *self, int block, PyObject *timeout) /*[clinic end generated code: output=ec82a7157dcccd1a input=4bf691f9f01fa297]*/ { _PyTime_t endtime = 0; _PyTime_t timeout_val; PyObject *item; PyLockStatus r; PY_TIMEOUT_T microseconds; if (block == 0) { /* Non-blocking */ microseconds = 0; } else if (timeout != Py_None) { /* With timeout */ if (_PyTime_FromSecondsObject(&timeout_val, timeout, _PyTime_ROUND_CEILING) < 0) return NULL; if (timeout_val < 0) { PyErr_SetString(PyExc_ValueError, "'timeout' must be a non-negative number"); return NULL; } microseconds = _PyTime_AsMicroseconds(timeout_val, _PyTime_ROUND_CEILING); if (microseconds >= PY_TIMEOUT_MAX) { PyErr_SetString(PyExc_OverflowError, "timeout value is too large"); return NULL; } endtime = _PyTime_GetMonotonicClock() + timeout_val; } else { /* Infinitely blocking */ microseconds = -1; } /* put() signals the queue to be non-empty by releasing the lock. * So we simply try to acquire the lock in a loop, until the condition * (queue non-empty) becomes true. */ while (self->lst_pos == PyList_GET_SIZE(self->lst)) { /* First a simple non-blocking try without releasing the GIL */ r = PyThread_acquire_lock_timed(self->lock, 0, 0); if (r == PY_LOCK_FAILURE && microseconds != 0) { Py_BEGIN_ALLOW_THREADS r = PyThread_acquire_lock_timed(self->lock, microseconds, 1); Py_END_ALLOW_THREADS } if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) { return NULL; } if (r == PY_LOCK_FAILURE) { /* Timed out */ PyErr_SetNone(EmptyError); return NULL; } self->locked = 1; /* Adjust timeout for next iteration (if any) */ if (endtime > 0) { timeout_val = endtime - _PyTime_GetMonotonicClock(); microseconds = _PyTime_AsMicroseconds(timeout_val, _PyTime_ROUND_CEILING); } }