Commit 9f17a06b authored by Victor Stinner's avatar Victor Stinner

test

parent 2a3a4bbd
...@@ -350,6 +350,10 @@ The module defines the following functions and data items: ...@@ -350,6 +350,10 @@ The module defines the following functions and data items:
requested by an arbitrary amount because of the scheduling of other activity requested by an arbitrary amount because of the scheduling of other activity
in the system. in the system.
.. versionchanged:: 3.5
The function now sleeps at least *secs* even if the sleep is interrupted
by a signal (see :pep:`475` for the rationale).
.. function:: strftime(format[, t]) .. function:: strftime(format[, t])
......
...@@ -252,8 +252,23 @@ class SocketEINTRTest(EINTRBaseTest): ...@@ -252,8 +252,23 @@ class SocketEINTRTest(EINTRBaseTest):
lambda path: os.close(os.open(path, os.O_WRONLY))) lambda path: os.close(os.open(path, os.O_WRONLY)))
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
class TimeEINTRTest(EINTRBaseTest):
""" EINTR tests for the time module. """
def test_sleep(self):
t0 = time.monotonic()
time.sleep(2)
signal.alarm(0)
dt = time.monotonic() - t0
self.assertGreaterEqual(dt, 1.9)
def test_main(): def test_main():
support.run_unittest(OSEINTRTest, SocketEINTRTest) support.run_unittest(
OSEINTRTest,
SocketEINTRTest,
TimeEINTRTest)
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -419,17 +419,20 @@ class WakeupSignalTests(unittest.TestCase): ...@@ -419,17 +419,20 @@ class WakeupSignalTests(unittest.TestCase):
TIMEOUT_HALF = 5 TIMEOUT_HALF = 5
signal.alarm(1) signal.alarm(1)
before_time = time.time()
# We attempt to get a signal during the sleep, # We attempt to get a signal during the sleep,
# before select is called # before select is called
time.sleep(TIMEOUT_FULL) try:
mid_time = time.time() select.select([], [], [], TIMEOUT_FULL)
dt = mid_time - before_time except InterruptedError:
if dt >= TIMEOUT_HALF: pass
raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) else:
raise Exception("select() was not interrupted")
before_time = time.time()
select.select([read], [], [], TIMEOUT_FULL) select.select([read], [], [], TIMEOUT_FULL)
after_time = time.time() after_time = time.time()
dt = after_time - mid_time dt = after_time - before_time
if dt >= TIMEOUT_HALF: if dt >= TIMEOUT_HALF:
raise Exception("%s >= %s" % (dt, TIMEOUT_HALF)) raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
""", signal.SIGALRM) """, signal.SIGALRM)
......
...@@ -1386,74 +1386,94 @@ floattime(_Py_clock_info_t *info) ...@@ -1386,74 +1386,94 @@ floattime(_Py_clock_info_t *info)
static int static int
floatsleep(double secs) floatsleep(double secs)
{ {
/* XXX Should test for MS_WINDOWS first! */ _PyTime_timeval deadline, monotonic;
#if defined(HAVE_SELECT) && !defined(__EMX__) #ifndef MS_WINDOWS
struct timeval t; struct timeval timeout;
double frac; double frac;
int err; int err = 0;
frac = fmod(secs, 1.0); _PyTime_monotonic(&deadline);
secs = floor(secs); _PyTime_ADD_SECONDS(deadline, secs);
t.tv_sec = (long)secs;
t.tv_usec = (long)(frac*1000000.0); while (1) {
Py_BEGIN_ALLOW_THREADS frac = fmod(secs, 1.0);
err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); secs = floor(secs);
Py_END_ALLOW_THREADS timeout.tv_sec = (long)secs;
if (err != 0) { timeout.tv_usec = (long)(frac*1000000.0);
#ifdef EINTR
if (errno == EINTR) { Py_BEGIN_ALLOW_THREADS
if (PyErr_CheckSignals()) err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &timeout);
return -1; Py_END_ALLOW_THREADS
}
else if (!(err != 0 && errno == EINTR))
#endif break;
{
PyErr_SetFromErrno(PyExc_OSError); /* select() was interrupted by a signal */
if (PyErr_CheckSignals())
return -1; return -1;
_PyTime_monotonic(&monotonic);
secs = _PyTime_INTERVAL(monotonic, deadline);
if (secs <= 0.0) {
err = 0;
errno = 0;
break;
} }
} }
#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;
if (err != 0) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
#else
double millisecs;
unsigned long ul_millis;
DWORD rc;
HANDLE hInterruptEvent;
_PyTime_monotonic(&deadline);
_PyTime_ADD_SECONDS(deadline, secs);
do {
millisecs = secs * 1000.0;
if (millisecs > (double)ULONG_MAX) { if (millisecs > (double)ULONG_MAX) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"sleep length is too large"); "sleep length is too large");
return -1; return -1;
} }
Py_BEGIN_ALLOW_THREADS
/* Allow sleep(0) to maintain win32 semantics, and as decreed /* Allow sleep(0) to maintain win32 semantics, and as decreed
* by Guido, only the main thread can be interrupted. * by Guido, only the main thread can be interrupted.
*/ */
ul_millis = (unsigned long)millisecs; ul_millis = (unsigned long)millisecs;
if (ul_millis == 0 || !_PyOS_IsMainThread()) if (ul_millis == 0 || !_PyOS_IsMainThread()) {
Sleep(ul_millis); Py_BEGIN_ALLOW_THREADS
Sleep(0);
Py_END_ALLOW_THREADS
break;
}
else { else {
DWORD rc; hInterruptEvent = _PyOS_SigintEvent();
HANDLE hInterruptEvent = _PyOS_SigintEvent();
ResetEvent(hInterruptEvent); ResetEvent(hInterruptEvent);
Py_BEGIN_ALLOW_THREADS
rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE); rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE);
if (rc == WAIT_OBJECT_0) { Py_END_ALLOW_THREADS
Py_BLOCK_THREADS
errno = EINTR; if (rc != WAIT_OBJECT_0)
PyErr_SetFromErrno(PyExc_OSError); break;
/* WaitForSingleObjectEx() was interrupted by SIGINT */
if (PyErr_CheckSignals())
return -1; return -1;
}
_PyTime_monotonic(&monotonic);
secs = _PyTime_INTERVAL(monotonic, deadline);
if (secs <= 0.0)
break;
} }
Py_END_ALLOW_THREADS } while (1);
}
#else
/* XXX Can't interrupt this sleep */
Py_BEGIN_ALLOW_THREADS
sleep((int)secs);
Py_END_ALLOW_THREADS
#endif #endif
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment