-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-30768: Recompute timeout on interrupted lock #4103
Changes from 1 commit
3551353
764d0cd
17aba7c
7c428b7
68e3f02
1fb576c
7232c61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Fix the pthread+semaphore implementation of PyThread_acquire_lock_timed() when | ||
called with timeout > 0 and intr_flag=0: recompute the timeout if | ||
sem_timedwait() is interrupted by a signal (EINTR). See also the :pep:`475`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -318,23 +318,59 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, | |
sem_t *thelock = (sem_t *)lock; | ||
int status, error = 0; | ||
struct timespec ts; | ||
_PyTime_t deadline = 0; | ||
|
||
(void) error; /* silence unused-but-set-variable warning */ | ||
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", | ||
lock, microseconds, intr_flag)); | ||
|
||
if (microseconds > 0) | ||
if (microseconds > 0) { | ||
MICROSECONDS_TO_TIMESPEC(microseconds, ts); | ||
do { | ||
if (microseconds > 0) | ||
|
||
if (!intr_flag) { | ||
_PyTime_t timeout = _PyTime_FromNanoseconds(microseconds * 1000); | ||
deadline = _PyTime_GetMonotonicClock() + timeout; | ||
} | ||
} | ||
|
||
while (1) { | ||
if (microseconds > 0) { | ||
status = fix_status(sem_timedwait(thelock, &ts)); | ||
else if (microseconds == 0) | ||
} | ||
else if (microseconds == 0) { | ||
status = fix_status(sem_trywait(thelock)); | ||
else | ||
} | ||
else { | ||
status = fix_status(sem_wait(thelock)); | ||
} | ||
|
||
/* Retry if interrupted by a signal, unless the caller wants to be | ||
notified. */ | ||
} while (!intr_flag && status == EINTR); | ||
if (intr_flag || status != EINTR) { | ||
break; | ||
} | ||
|
||
if (microseconds > 0) { | ||
/* wait interrupted by a signal (EINTR): recompute the timeout */ | ||
_PyTime_t dt = deadline - _PyTime_GetMonotonicClock(); | ||
if (dt < 0) { | ||
status = ETIMEDOUT; | ||
break; | ||
} | ||
else if (dt > 0) { | ||
_PyTime_t realtime_deadline = _PyTime_GetSystemClock() + dt; | ||
if (_PyTime_AsTimespec(realtime_deadline, &ts) < 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, this function raises an exception on overflow. This bug is now fixed in the new commit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which new commit? :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4th commit of this PR, commit 7c428b7 which added the following code at the top of the function:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, thank you for adding the comments :-) |
||
success = PY_LOCK_FAILURE; | ||
goto exit; | ||
} | ||
/* no need to update microseconds value, the code only care | ||
if (microseconds > 0 or (microseconds == 0). */ | ||
} | ||
else { | ||
microseconds = 0; | ||
} | ||
} | ||
} | ||
|
||
/* Don't check the status if we're stopping because of an interrupt. */ | ||
if (!(intr_flag && status == EINTR)) { | ||
|
@@ -359,6 +395,7 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, | |
success = PY_LOCK_FAILURE; | ||
} | ||
|
||
exit: | ||
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", | ||
lock, microseconds, intr_flag, success)); | ||
return success; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if
microseconds * 1000
overflows?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added _PyTime_FromMicroseconds() to detect overflow on "us * 1000". But I chose to not detect overflow on "_PyTime_GetMonotonicClock() + timeout".