diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2015-03-19 20:54:09 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2015-03-19 20:54:09 (GMT) |
commit | 79d68f929d8def878766965f513b628023f809b5 (patch) | |
tree | 943c927ae839eb2b115f88d997cd29094ddd23ab /Modules/timemodule.c | |
parent | 0ed56a0b421e02da3ed3626a5b9e0ad076f68ce0 (diff) | |
download | cpython-79d68f929d8def878766965f513b628023f809b5.zip cpython-79d68f929d8def878766965f513b628023f809b5.tar.gz cpython-79d68f929d8def878766965f513b628023f809b5.tar.bz2 |
Issue #23646: If time.sleep() is interrupted by a signal, the sleep is now
retried with the recomputed delay, except if the signal handler raises an
exception (PEP 475).
Modify also test_signal to use a monotonic clock instead of the system clock.
Diffstat (limited to 'Modules/timemodule.c')
-rw-r--r-- | Modules/timemodule.c | 107 |
1 files changed, 56 insertions, 51 deletions
diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 7f5f314..179c33f 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1386,74 +1386,79 @@ floattime(_Py_clock_info_t *info) static int floatsleep(double secs) { -/* XXX Should test for MS_WINDOWS first! */ -#if defined(HAVE_SELECT) && !defined(__EMX__) - struct timeval t; + _PyTime_timeval deadline, monotonic; +#ifndef MS_WINDOWS + struct timeval timeout; double frac; - int err; - - frac = fmod(secs, 1.0); - secs = floor(secs); - t.tv_sec = (long)secs; - t.tv_usec = (long)(frac*1000000.0); - Py_BEGIN_ALLOW_THREADS - err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); - Py_END_ALLOW_THREADS - if (err != 0) { -#ifdef EINTR - if (errno == EINTR) { - if (PyErr_CheckSignals()) - return -1; - } - else + int err = 0; +#else + double millisecs; + unsigned long ul_millis; + DWORD rc; + HANDLE hInterruptEvent; #endif - { + + _PyTime_monotonic(&deadline); + _PyTime_ADD_SECONDS(deadline, secs); + + do { +#ifndef MS_WINDOWS + frac = fmod(secs, 1.0); + secs = floor(secs); + timeout.tv_sec = (long)secs; + timeout.tv_usec = (long)(frac*1000000.0); + + Py_BEGIN_ALLOW_THREADS + err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout); + Py_END_ALLOW_THREADS + + if (err == 0) + break; + + if (errno != EINTR) { PyErr_SetFromErrno(PyExc_OSError); return -1; } - } -#elif defined(__WATCOMC__) && !defined(__QNX__) - /* XXX Can't interrupt this sleep */ - Py_BEGIN_ALLOW_THREADS - delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */ - Py_END_ALLOW_THREADS -#elif defined(MS_WINDOWS) - { - double millisecs = secs * 1000.0; - unsigned long ul_millis; - +#else + millisecs = secs * 1000.0; if (millisecs > (double)ULONG_MAX) { PyErr_SetString(PyExc_OverflowError, "sleep length is too large"); return -1; } - Py_BEGIN_ALLOW_THREADS + /* Allow sleep(0) to maintain win32 semantics, and as decreed * by Guido, only the main thread can be interrupted. */ ul_millis = (unsigned long)millisecs; - if (ul_millis == 0 || !_PyOS_IsMainThread()) - Sleep(ul_millis); - else { - DWORD rc; - HANDLE hInterruptEvent = _PyOS_SigintEvent(); - ResetEvent(hInterruptEvent); - rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE); - if (rc == WAIT_OBJECT_0) { - Py_BLOCK_THREADS - errno = EINTR; - PyErr_SetFromErrno(PyExc_OSError); - return -1; - } + if (ul_millis == 0 || !_PyOS_IsMainThread()) { + Py_BEGIN_ALLOW_THREADS + Sleep(0); + Py_END_ALLOW_THREADS + break; } + + hInterruptEvent = _PyOS_SigintEvent(); + ResetEvent(hInterruptEvent); + + Py_BEGIN_ALLOW_THREADS + rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE); Py_END_ALLOW_THREADS - } -#else - /* XXX Can't interrupt this sleep */ - Py_BEGIN_ALLOW_THREADS - sleep((int)secs); - Py_END_ALLOW_THREADS + + if (rc != WAIT_OBJECT_0) + break; #endif + /* sleep was interrupted by SIGINT */ + if (PyErr_CheckSignals()) + return -1; + + _PyTime_monotonic(&monotonic); + secs = _PyTime_INTERVAL(monotonic, deadline); + if (secs <= 0.0) + break; + /* retry with the recomputed delay */ + } while (1); + return 0; } |