gh-134745: Change PyThread_allocate_lock() implementation to PyMutex (#134747)
Co-authored-by: Sam Gross <colesbury@gmail.com>
This commit is contained in:
parent
45c6c48afc
commit
ebf6d13567
@ -48,6 +48,9 @@ typedef enum _PyLockFlags {
|
||||
|
||||
// Handle signals if interrupted while waiting on the lock.
|
||||
_PY_LOCK_HANDLE_SIGNALS = 2,
|
||||
|
||||
// Fail if interrupted by a signal while waiting on the lock.
|
||||
_PY_FAIL_IF_INTERRUPTED = 4,
|
||||
} _PyLockFlags;
|
||||
|
||||
// Lock a mutex with an optional timeout and additional options. See
|
||||
|
@ -729,7 +729,7 @@ class SysModuleTest(unittest.TestCase):
|
||||
info = sys.thread_info
|
||||
self.assertEqual(len(info), 3)
|
||||
self.assertIn(info.name, ('nt', 'pthread', 'pthread-stubs', 'solaris', None))
|
||||
self.assertIn(info.lock, ('semaphore', 'mutex+cond', None))
|
||||
self.assertIn(info.lock, ('pymutex', None))
|
||||
if sys.platform.startswith(("linux", "android", "freebsd")):
|
||||
self.assertEqual(info.name, "pthread")
|
||||
elif sys.platform == "win32":
|
||||
|
@ -0,0 +1,3 @@
|
||||
Change :c:func:`!PyThread_allocate_lock` implementation to ``PyMutex``.
|
||||
On Windows, :c:func:`!PyThread_acquire_lock_timed` now supports the *intr_flag*
|
||||
parameter: it can be interrupted. Patch by Victor Stinner.
|
@ -119,6 +119,9 @@ _PyMutex_LockTimed(PyMutex *m, PyTime_t timeout, _PyLockFlags flags)
|
||||
return PY_LOCK_INTR;
|
||||
}
|
||||
}
|
||||
else if (ret == Py_PARK_INTR && (flags & _PY_FAIL_IF_INTERRUPTED)) {
|
||||
return PY_LOCK_INTR;
|
||||
}
|
||||
else if (ret == Py_PARK_TIMEOUT) {
|
||||
assert(timeout >= 0);
|
||||
return PY_LOCK_FAILURE;
|
||||
|
@ -39,7 +39,8 @@
|
||||
const long long PY_TIMEOUT_MAX = PY_TIMEOUT_MAX_VALUE;
|
||||
|
||||
|
||||
static void PyThread__init_thread(void); /* Forward */
|
||||
/* Forward declaration */
|
||||
static void PyThread__init_thread(void);
|
||||
|
||||
#define initialized _PyRuntime.threads.initialized
|
||||
|
||||
@ -71,6 +72,79 @@ PyThread_init_thread(void)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Lock support.
|
||||
*/
|
||||
|
||||
PyThread_type_lock
|
||||
PyThread_allocate_lock(void)
|
||||
{
|
||||
if (!initialized) {
|
||||
PyThread_init_thread();
|
||||
}
|
||||
|
||||
PyMutex *lock = (PyMutex *)PyMem_RawMalloc(sizeof(PyMutex));
|
||||
if (lock) {
|
||||
*lock = (PyMutex){0};
|
||||
}
|
||||
|
||||
return (PyThread_type_lock)lock;
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_free_lock(PyThread_type_lock lock)
|
||||
{
|
||||
PyMem_RawFree(lock);
|
||||
}
|
||||
|
||||
PyLockStatus
|
||||
PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
|
||||
int intr_flag)
|
||||
{
|
||||
PyTime_t timeout; // relative timeout
|
||||
if (microseconds >= 0) {
|
||||
// bpo-41710: PyThread_acquire_lock_timed() cannot report timeout
|
||||
// overflow to the caller, so clamp the timeout to
|
||||
// [PyTime_MIN, PyTime_MAX].
|
||||
//
|
||||
// PyTime_MAX nanoseconds is around 292.3 years.
|
||||
//
|
||||
// _thread.Lock.acquire() and _thread.RLock.acquire() raise an
|
||||
// OverflowError if microseconds is greater than PY_TIMEOUT_MAX.
|
||||
timeout = _PyTime_FromMicrosecondsClamp(microseconds);
|
||||
}
|
||||
else {
|
||||
timeout = -1;
|
||||
}
|
||||
|
||||
_PyLockFlags flags = _Py_LOCK_DONT_DETACH;
|
||||
if (intr_flag) {
|
||||
flags |= _PY_FAIL_IF_INTERRUPTED;
|
||||
}
|
||||
|
||||
return _PyMutex_LockTimed((PyMutex *)lock, timeout, flags);
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_release_lock(PyThread_type_lock lock)
|
||||
{
|
||||
PyMutex_Unlock((PyMutex *)lock);
|
||||
}
|
||||
|
||||
int
|
||||
_PyThread_at_fork_reinit(PyThread_type_lock *lock)
|
||||
{
|
||||
_PyMutex_at_fork_reinit((PyMutex *)lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
|
||||
{
|
||||
return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0);
|
||||
}
|
||||
|
||||
|
||||
/* return the current thread stack size */
|
||||
size_t
|
||||
PyThread_get_stacksize(void)
|
||||
@ -261,11 +335,7 @@ PyThread_GetInfo(void)
|
||||
#ifdef HAVE_PTHREAD_STUBS
|
||||
value = Py_NewRef(Py_None);
|
||||
#elif defined(_POSIX_THREADS)
|
||||
#ifdef USE_SEMAPHORES
|
||||
value = PyUnicode_FromString("semaphore");
|
||||
#else
|
||||
value = PyUnicode_FromString("mutex+cond");
|
||||
#endif
|
||||
value = PyUnicode_FromString("pymutex");
|
||||
if (value == NULL) {
|
||||
Py_DECREF(threadinfo);
|
||||
return NULL;
|
||||
|
@ -300,98 +300,6 @@ PyThread_hang_thread(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock support. It has to be implemented as semaphores.
|
||||
* I [Dag] tried to implement it with mutex but I could find a way to
|
||||
* tell whether a thread already own the lock or not.
|
||||
*/
|
||||
PyThread_type_lock
|
||||
PyThread_allocate_lock(void)
|
||||
{
|
||||
PNRMUTEX mutex;
|
||||
|
||||
if (!initialized)
|
||||
PyThread_init_thread();
|
||||
|
||||
mutex = AllocNonRecursiveMutex() ;
|
||||
|
||||
PyThread_type_lock aLock = (PyThread_type_lock) mutex;
|
||||
assert(aLock);
|
||||
|
||||
return aLock;
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_free_lock(PyThread_type_lock aLock)
|
||||
{
|
||||
FreeNonRecursiveMutex(aLock) ;
|
||||
}
|
||||
|
||||
// WaitForSingleObject() accepts timeout in milliseconds in the range
|
||||
// [0; 0xFFFFFFFE] (DWORD type). INFINITE value (0xFFFFFFFF) means no
|
||||
// timeout. 0xFFFFFFFE milliseconds is around 49.7 days.
|
||||
const DWORD TIMEOUT_MS_MAX = 0xFFFFFFFE;
|
||||
|
||||
/*
|
||||
* Return 1 on success if the lock was acquired
|
||||
*
|
||||
* and 0 if the lock was not acquired. This means a 0 is returned
|
||||
* if the lock has already been acquired by this thread!
|
||||
*/
|
||||
PyLockStatus
|
||||
PyThread_acquire_lock_timed(PyThread_type_lock aLock,
|
||||
PY_TIMEOUT_T microseconds, int intr_flag)
|
||||
{
|
||||
assert(aLock);
|
||||
|
||||
/* Fow now, intr_flag does nothing on Windows, and lock acquires are
|
||||
* uninterruptible. */
|
||||
PyLockStatus success;
|
||||
PY_TIMEOUT_T milliseconds;
|
||||
|
||||
if (microseconds >= 0) {
|
||||
milliseconds = microseconds / 1000;
|
||||
// Round milliseconds away from zero
|
||||
if (microseconds % 1000 > 0) {
|
||||
milliseconds++;
|
||||
}
|
||||
if (milliseconds > (PY_TIMEOUT_T)TIMEOUT_MS_MAX) {
|
||||
// bpo-41710: PyThread_acquire_lock_timed() cannot report timeout
|
||||
// overflow to the caller, so clamp the timeout to
|
||||
// [0, TIMEOUT_MS_MAX] milliseconds.
|
||||
//
|
||||
// _thread.Lock.acquire() and _thread.RLock.acquire() raise an
|
||||
// OverflowError if microseconds is greater than PY_TIMEOUT_MAX.
|
||||
milliseconds = TIMEOUT_MS_MAX;
|
||||
}
|
||||
assert(milliseconds != INFINITE);
|
||||
}
|
||||
else {
|
||||
milliseconds = INFINITE;
|
||||
}
|
||||
|
||||
if (EnterNonRecursiveMutex((PNRMUTEX)aLock,
|
||||
(DWORD)milliseconds) == WAIT_OBJECT_0) {
|
||||
success = PY_LOCK_ACQUIRED;
|
||||
}
|
||||
else {
|
||||
success = PY_LOCK_FAILURE;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
int
|
||||
PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
|
||||
{
|
||||
return PyThread_acquire_lock_timed(aLock, waitflag ? -1 : 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_release_lock(PyThread_type_lock aLock)
|
||||
{
|
||||
assert(aLock);
|
||||
(void)LeaveNonRecursiveMutex((PNRMUTEX) aLock);
|
||||
}
|
||||
|
||||
/* minimum/maximum thread stack sizes supported */
|
||||
#define THREAD_MIN_STACKSIZE 0x8000 /* 32 KiB */
|
||||
|
@ -99,16 +99,6 @@
|
||||
#undef HAVE_SEM_CLOCKWAIT
|
||||
#endif
|
||||
|
||||
/* Whether or not to use semaphores directly rather than emulating them with
|
||||
* mutexes and condition variables:
|
||||
*/
|
||||
#if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \
|
||||
(defined(HAVE_SEM_TIMEDWAIT) || defined(HAVE_SEM_CLOCKWAIT)))
|
||||
# define USE_SEMAPHORES
|
||||
#else
|
||||
# undef USE_SEMAPHORES
|
||||
#endif
|
||||
|
||||
|
||||
/* On platforms that don't use standard POSIX threads pthread_sigmask()
|
||||
* isn't present. DEC threads uses sigprocmask() instead as do most
|
||||
@ -442,388 +432,6 @@ PyThread_hang_thread(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_SEMAPHORES
|
||||
|
||||
/*
|
||||
* Lock support.
|
||||
*/
|
||||
|
||||
PyThread_type_lock
|
||||
PyThread_allocate_lock(void)
|
||||
{
|
||||
sem_t *lock;
|
||||
int status, error = 0;
|
||||
|
||||
if (!initialized)
|
||||
PyThread_init_thread();
|
||||
|
||||
lock = (sem_t *)PyMem_RawMalloc(sizeof(sem_t));
|
||||
|
||||
if (lock) {
|
||||
status = sem_init(lock,0,1);
|
||||
CHECK_STATUS("sem_init");
|
||||
|
||||
if (error) {
|
||||
PyMem_RawFree((void *)lock);
|
||||
lock = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (PyThread_type_lock)lock;
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_free_lock(PyThread_type_lock lock)
|
||||
{
|
||||
sem_t *thelock = (sem_t *)lock;
|
||||
int status, error = 0;
|
||||
|
||||
(void) error; /* silence unused-but-set-variable warning */
|
||||
|
||||
if (!thelock)
|
||||
return;
|
||||
|
||||
status = sem_destroy(thelock);
|
||||
CHECK_STATUS("sem_destroy");
|
||||
|
||||
PyMem_RawFree((void *)thelock);
|
||||
}
|
||||
|
||||
/*
|
||||
* As of February 2002, Cygwin thread implementations mistakenly report error
|
||||
* codes in the return value of the sem_ calls (like the pthread_ functions).
|
||||
* Correct implementations return -1 and put the code in errno. This supports
|
||||
* either.
|
||||
*/
|
||||
static int
|
||||
fix_status(int status)
|
||||
{
|
||||
return (status == -1) ? errno : status;
|
||||
}
|
||||
|
||||
PyLockStatus
|
||||
PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
|
||||
int intr_flag)
|
||||
{
|
||||
PyLockStatus success;
|
||||
sem_t *thelock = (sem_t *)lock;
|
||||
int status, error = 0;
|
||||
|
||||
(void) error; /* silence unused-but-set-variable warning */
|
||||
|
||||
PyTime_t timeout; // relative timeout
|
||||
if (microseconds >= 0) {
|
||||
// bpo-41710: PyThread_acquire_lock_timed() cannot report timeout
|
||||
// overflow to the caller, so clamp the timeout to
|
||||
// [PyTime_MIN, PyTime_MAX].
|
||||
//
|
||||
// PyTime_MAX nanoseconds is around 292.3 years.
|
||||
//
|
||||
// _thread.Lock.acquire() and _thread.RLock.acquire() raise an
|
||||
// OverflowError if microseconds is greater than PY_TIMEOUT_MAX.
|
||||
timeout = _PyTime_FromMicrosecondsClamp(microseconds);
|
||||
}
|
||||
else {
|
||||
timeout = -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SEM_CLOCKWAIT
|
||||
struct timespec abs_timeout;
|
||||
// Local scope for deadline
|
||||
{
|
||||
PyTime_t now;
|
||||
// silently ignore error: cannot report error to the caller
|
||||
(void)PyTime_MonotonicRaw(&now);
|
||||
PyTime_t deadline = _PyTime_Add(now, timeout);
|
||||
_PyTime_AsTimespec_clamp(deadline, &abs_timeout);
|
||||
}
|
||||
#else
|
||||
PyTime_t deadline = 0;
|
||||
if (timeout > 0 && !intr_flag) {
|
||||
deadline = _PyDeadline_Init(timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
if (timeout > 0) {
|
||||
#ifdef HAVE_SEM_CLOCKWAIT
|
||||
status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC,
|
||||
&abs_timeout));
|
||||
#else
|
||||
PyTime_t now;
|
||||
// silently ignore error: cannot report error to the caller
|
||||
(void)PyTime_TimeRaw(&now);
|
||||
PyTime_t abs_time = _PyTime_Add(now, timeout);
|
||||
|
||||
struct timespec ts;
|
||||
_PyTime_AsTimespec_clamp(abs_time, &ts);
|
||||
status = fix_status(sem_timedwait(thelock, &ts));
|
||||
#endif
|
||||
}
|
||||
else if (timeout == 0) {
|
||||
status = fix_status(sem_trywait(thelock));
|
||||
}
|
||||
else {
|
||||
status = fix_status(sem_wait(thelock));
|
||||
}
|
||||
|
||||
/* Retry if interrupted by a signal, unless the caller wants to be
|
||||
notified. */
|
||||
if (intr_flag || status != EINTR) {
|
||||
break;
|
||||
}
|
||||
|
||||
// sem_clockwait() uses an absolute timeout, there is no need
|
||||
// to recompute the relative timeout.
|
||||
#ifndef HAVE_SEM_CLOCKWAIT
|
||||
if (timeout > 0) {
|
||||
/* wait interrupted by a signal (EINTR): recompute the timeout */
|
||||
timeout = _PyDeadline_Get(deadline);
|
||||
if (timeout < 0) {
|
||||
status = ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Don't check the status if we're stopping because of an interrupt. */
|
||||
if (!(intr_flag && status == EINTR)) {
|
||||
if (timeout > 0) {
|
||||
if (status != ETIMEDOUT) {
|
||||
#ifdef HAVE_SEM_CLOCKWAIT
|
||||
CHECK_STATUS("sem_clockwait");
|
||||
#else
|
||||
CHECK_STATUS("sem_timedwait");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (timeout == 0) {
|
||||
if (status != EAGAIN) {
|
||||
CHECK_STATUS("sem_trywait");
|
||||
}
|
||||
}
|
||||
else {
|
||||
CHECK_STATUS("sem_wait");
|
||||
}
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
success = PY_LOCK_ACQUIRED;
|
||||
} else if (intr_flag && status == EINTR) {
|
||||
success = PY_LOCK_INTR;
|
||||
} else {
|
||||
success = PY_LOCK_FAILURE;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_release_lock(PyThread_type_lock lock)
|
||||
{
|
||||
sem_t *thelock = (sem_t *)lock;
|
||||
int status, error = 0;
|
||||
|
||||
(void) error; /* silence unused-but-set-variable warning */
|
||||
|
||||
status = sem_post(thelock);
|
||||
CHECK_STATUS("sem_post");
|
||||
}
|
||||
|
||||
#else /* USE_SEMAPHORES */
|
||||
|
||||
/*
|
||||
* Lock support.
|
||||
*/
|
||||
PyThread_type_lock
|
||||
PyThread_allocate_lock(void)
|
||||
{
|
||||
pthread_lock *lock;
|
||||
int status, error = 0;
|
||||
|
||||
if (!initialized)
|
||||
PyThread_init_thread();
|
||||
|
||||
lock = (pthread_lock *) PyMem_RawCalloc(1, sizeof(pthread_lock));
|
||||
if (lock) {
|
||||
lock->locked = 0;
|
||||
|
||||
status = pthread_mutex_init(&lock->mut, NULL);
|
||||
CHECK_STATUS_PTHREAD("pthread_mutex_init");
|
||||
/* Mark the pthread mutex underlying a Python mutex as
|
||||
pure happens-before. We can't simply mark the
|
||||
Python-level mutex as a mutex because it can be
|
||||
acquired and released in different threads, which
|
||||
will cause errors. */
|
||||
_Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut);
|
||||
|
||||
status = _PyThread_cond_init(&lock->lock_released);
|
||||
CHECK_STATUS_PTHREAD("pthread_cond_init");
|
||||
|
||||
if (error) {
|
||||
PyMem_RawFree((void *)lock);
|
||||
lock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (PyThread_type_lock) lock;
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_free_lock(PyThread_type_lock lock)
|
||||
{
|
||||
pthread_lock *thelock = (pthread_lock *)lock;
|
||||
int status, error = 0;
|
||||
|
||||
(void) error; /* silence unused-but-set-variable warning */
|
||||
|
||||
/* some pthread-like implementations tie the mutex to the cond
|
||||
* and must have the cond destroyed first.
|
||||
*/
|
||||
status = pthread_cond_destroy( &thelock->lock_released );
|
||||
CHECK_STATUS_PTHREAD("pthread_cond_destroy");
|
||||
|
||||
status = pthread_mutex_destroy( &thelock->mut );
|
||||
CHECK_STATUS_PTHREAD("pthread_mutex_destroy");
|
||||
|
||||
PyMem_RawFree((void *)thelock);
|
||||
}
|
||||
|
||||
PyLockStatus
|
||||
PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
|
||||
int intr_flag)
|
||||
{
|
||||
PyLockStatus success = PY_LOCK_FAILURE;
|
||||
pthread_lock *thelock = (pthread_lock *)lock;
|
||||
int status, error = 0;
|
||||
|
||||
if (microseconds == 0) {
|
||||
status = pthread_mutex_trylock( &thelock->mut );
|
||||
if (status != EBUSY) {
|
||||
CHECK_STATUS_PTHREAD("pthread_mutex_trylock[1]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = pthread_mutex_lock( &thelock->mut );
|
||||
CHECK_STATUS_PTHREAD("pthread_mutex_lock[1]");
|
||||
}
|
||||
if (status != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (thelock->locked == 0) {
|
||||
success = PY_LOCK_ACQUIRED;
|
||||
goto unlock;
|
||||
}
|
||||
if (microseconds == 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
struct timespec abs_timeout;
|
||||
if (microseconds > 0) {
|
||||
_PyThread_cond_after(microseconds, &abs_timeout);
|
||||
}
|
||||
// Continue trying until we get the lock
|
||||
|
||||
// mut must be locked by me -- part of the condition protocol
|
||||
while (1) {
|
||||
if (microseconds > 0) {
|
||||
status = pthread_cond_timedwait(&thelock->lock_released,
|
||||
&thelock->mut, &abs_timeout);
|
||||
if (status == 1) {
|
||||
break;
|
||||
}
|
||||
if (status == ETIMEDOUT) {
|
||||
break;
|
||||
}
|
||||
CHECK_STATUS_PTHREAD("pthread_cond_timedwait");
|
||||
}
|
||||
else {
|
||||
status = pthread_cond_wait(
|
||||
&thelock->lock_released,
|
||||
&thelock->mut);
|
||||
CHECK_STATUS_PTHREAD("pthread_cond_wait");
|
||||
}
|
||||
|
||||
if (intr_flag && status == 0 && thelock->locked) {
|
||||
// We were woken up, but didn't get the lock. We probably received
|
||||
// a signal. Return PY_LOCK_INTR to allow the caller to handle
|
||||
// it and retry.
|
||||
success = PY_LOCK_INTR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == 0 && !thelock->locked) {
|
||||
success = PY_LOCK_ACQUIRED;
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait got interrupted by a signal: retry
|
||||
}
|
||||
|
||||
unlock:
|
||||
if (success == PY_LOCK_ACQUIRED) {
|
||||
thelock->locked = 1;
|
||||
}
|
||||
status = pthread_mutex_unlock( &thelock->mut );
|
||||
CHECK_STATUS_PTHREAD("pthread_mutex_unlock[1]");
|
||||
|
||||
done:
|
||||
if (error) {
|
||||
success = PY_LOCK_FAILURE;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
PyThread_release_lock(PyThread_type_lock lock)
|
||||
{
|
||||
pthread_lock *thelock = (pthread_lock *)lock;
|
||||
int status, error = 0;
|
||||
|
||||
(void) error; /* silence unused-but-set-variable warning */
|
||||
|
||||
status = pthread_mutex_lock( &thelock->mut );
|
||||
CHECK_STATUS_PTHREAD("pthread_mutex_lock[3]");
|
||||
|
||||
thelock->locked = 0;
|
||||
|
||||
/* wake up someone (anyone, if any) waiting on the lock */
|
||||
status = pthread_cond_signal( &thelock->lock_released );
|
||||
CHECK_STATUS_PTHREAD("pthread_cond_signal");
|
||||
|
||||
status = pthread_mutex_unlock( &thelock->mut );
|
||||
CHECK_STATUS_PTHREAD("pthread_mutex_unlock[3]");
|
||||
}
|
||||
|
||||
#endif /* USE_SEMAPHORES */
|
||||
|
||||
int
|
||||
_PyThread_at_fork_reinit(PyThread_type_lock *lock)
|
||||
{
|
||||
PyThread_type_lock new_lock = PyThread_allocate_lock();
|
||||
if (new_lock == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* bpo-6721, bpo-40089: The old lock can be in an inconsistent state.
|
||||
fork() can be called in the middle of an operation on the lock done by
|
||||
another thread. So don't call PyThread_free_lock(*lock).
|
||||
|
||||
Leak memory on purpose. Don't release the memory either since the
|
||||
address of a mutex is relevant. Putting two mutexes at the same address
|
||||
can lead to problems. */
|
||||
|
||||
*lock = new_lock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
|
||||
{
|
||||
return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0);
|
||||
}
|
||||
|
||||
/* set the thread stack size.
|
||||
* Return 0 if size is valid, -1 if size is invalid,
|
||||
|
Loading…
x
Reference in New Issue
Block a user