static int pysleep(_PyTime_t secs) { _PyTime_t deadline, monotonic; #ifndef MS_WINDOWS struct timeval timeout; int err = 0; #else _PyTime_t millisecs; unsigned long ul_millis; DWORD rc; HANDLE hInterruptEvent; #endif deadline = _PyTime_GetMonotonicClock() + secs; do { #ifndef MS_WINDOWS if (_PyTime_AsTimeval(secs, &timeout, _PyTime_ROUND_CEILING) < 0) return -1; 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; } #else millisecs = _PyTime_AsMilliseconds(secs, _PyTime_ROUND_CEILING); if (millisecs > (double)ULONG_MAX) { PyErr_SetString(PyExc_OverflowError, "sleep length is too large"); return -1; } /* 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()) { Py_BEGIN_ALLOW_THREADS Sleep(ul_millis); Py_END_ALLOW_THREADS break; } hInterruptEvent = _PyOS_SigintEvent(); ResetEvent(hInterruptEvent); Py_BEGIN_ALLOW_THREADS rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE); Py_END_ALLOW_THREADS if (rc != WAIT_OBJECT_0) break; #endif /* sleep was interrupted by SIGINT */ if (PyErr_CheckSignals()) return -1; monotonic = _PyTime_GetMonotonicClock(); secs = deadline - monotonic; if (secs < 0) break; /* retry with the recomputed delay */ } while (1);
static int floatsleep(double secs) { /* XXX Should test for MS_WINDOWS first! */ #if defined(HAVE_SELECT) && !defined(__EMX__) struct timeval t; 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 #endif { PyErr_SetFromErrno(PyExc_IOError); 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; 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_IOError); return -1; } } Py_END_ALLOW_THREADS } #else /* XXX Can't interrupt this sleep */ Py_BEGIN_ALLOW_THREADS sleep((int)secs); Py_END_ALLOW_THREADS #endif return 0; }
static PyObject * semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds) { int blocking = 1; double timeout; PyObject *timeout_obj = Py_None; DWORD res, full_msecs, nhandles; HANDLE handles[2], sigint_event; static char *kwlist[] = {"block", "timeout", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, &blocking, &timeout_obj)) return NULL; /* calculate timeout */ if (!blocking) { full_msecs = 0; } else if (timeout_obj == Py_None) { full_msecs = INFINITE; } else { timeout = PyFloat_AsDouble(timeout_obj); if (PyErr_Occurred()) return NULL; timeout *= 1000.0; /* convert to millisecs */ if (timeout < 0.0) { timeout = 0.0; } else if (timeout >= 0.5 * INFINITE) { /* 25 days */ PyErr_SetString(PyExc_OverflowError, "timeout is too large"); return NULL; } full_msecs = (DWORD)(timeout + 0.5); } /* check whether we already own the lock */ if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) { ++self->count; Py_RETURN_TRUE; } /* check whether we can acquire without releasing the GIL and blocking */ if (WaitForSingleObjectEx(self->handle, 0, FALSE) == WAIT_OBJECT_0) { self->last_tid = GetCurrentThreadId(); ++self->count; Py_RETURN_TRUE; } /* prepare list of handles */ nhandles = 0; handles[nhandles++] = self->handle; if (_PyOS_IsMainThread()) { sigint_event = _PyOS_SigintEvent(); assert(sigint_event != NULL); handles[nhandles++] = sigint_event; } /* do the wait */ Py_BEGIN_ALLOW_THREADS if (sigint_event != NULL) ResetEvent(sigint_event); res = WaitForMultipleObjectsEx(nhandles, handles, FALSE, full_msecs, FALSE); Py_END_ALLOW_THREADS /* handle result */ switch (res) { case WAIT_TIMEOUT: Py_RETURN_FALSE; case WAIT_OBJECT_0 + 0: self->last_tid = GetCurrentThreadId(); ++self->count; Py_RETURN_TRUE; case WAIT_OBJECT_0 + 1: errno = EINTR; return PyErr_SetFromErrno(PyExc_IOError); case WAIT_FAILED: return PyErr_SetFromWindowsErr(0); default: PyErr_Format(PyExc_RuntimeError, "WaitForSingleObject() or " "WaitForMultipleObjects() gave unrecognized " "value %d", res); return NULL; } }