diff options
Diffstat (limited to 'Modules/_threadmodule.c')
-rw-r--r-- | Modules/_threadmodule.c | 155 |
1 files changed, 77 insertions, 78 deletions
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 9925b0e..812c8a3 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -49,21 +49,18 @@ lock_dealloc(lockobject *self) * timeout. */ static PyLockStatus -acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) +acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) { PyLockStatus r; - _PyTime_timeval curtime; - _PyTime_timeval endtime; - - - if (microseconds > 0) { - _PyTime_gettimeofday(&endtime); - endtime.tv_sec += microseconds / (1000 * 1000); - endtime.tv_usec += microseconds % (1000 * 1000); - } + _PyTime_t endtime = 0; + _PyTime_t microseconds; + if (timeout > 0) + endtime = _PyTime_GetMonotonicClock() + timeout; do { + microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING); + /* first a simple non-blocking try without releasing the GIL */ r = PyThread_acquire_lock_timed(lock, 0, 0); if (r == PY_LOCK_FAILURE && microseconds != 0) { @@ -82,14 +79,12 @@ acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) /* If we're using a timeout, recompute the timeout after processing * signals, since those can take time. */ - if (microseconds > 0) { - _PyTime_gettimeofday(&curtime); - microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 + - (endtime.tv_usec - curtime.tv_usec)); + if (timeout > 0) { + timeout = endtime - _PyTime_GetMonotonicClock(); /* Check for negative values, since those mean block forever. */ - if (microseconds <= 0) { + if (timeout < 0) { r = PY_LOCK_FAILURE; } } @@ -99,44 +94,61 @@ acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) return r; } -static PyObject * -lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds) +static int +lock_acquire_parse_args(PyObject *args, PyObject *kwds, + _PyTime_t *timeout) { char *kwlist[] = {"blocking", "timeout", NULL}; int blocking = 1; - double timeout = -1; - PY_TIMEOUT_T microseconds; - PyLockStatus r; + PyObject *timeout_obj = NULL; + const _PyTime_t unset_timeout = _PyTime_FromSeconds(-1); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|id:acquire", kwlist, - &blocking, &timeout)) - return NULL; + *timeout = unset_timeout ; - if (!blocking && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "can't specify a timeout " - "for a non-blocking call"); - return NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO:acquire", kwlist, + &blocking, &timeout_obj)) + return -1; + + if (timeout_obj + && _PyTime_FromSecondsObject(timeout, + timeout_obj, _PyTime_ROUND_CEILING) < 0) + return -1; + + if (!blocking && *timeout != unset_timeout ) { + PyErr_SetString(PyExc_ValueError, + "can't specify a timeout for a non-blocking call"); + return -1; } - if (timeout < 0 && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "timeout value must be " - "strictly positive"); - return NULL; + if (*timeout < 0 && *timeout != unset_timeout) { + PyErr_SetString(PyExc_ValueError, + "timeout value must be positive"); + return -1; } if (!blocking) - microseconds = 0; - else if (timeout == -1) - microseconds = -1; - else { - timeout *= 1e6; - if (timeout >= (double) PY_TIMEOUT_MAX) { + *timeout = 0; + else if (*timeout != unset_timeout) { + _PyTime_t microseconds; + + microseconds = _PyTime_AsMicroseconds(*timeout, _PyTime_ROUND_CEILING); + if (microseconds >= PY_TIMEOUT_MAX) { PyErr_SetString(PyExc_OverflowError, "timeout value is too large"); - return NULL; + return -1; } - microseconds = (PY_TIMEOUT_T) timeout; } + return 0; +} + +static PyObject * +lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds) +{ + _PyTime_t timeout; + PyLockStatus r; - r = acquire_timed(self->lock_lock, microseconds); + if (lock_acquire_parse_args(args, kwds, &timeout) < 0) + return NULL; + + r = acquire_timed(self->lock_lock, timeout); if (r == PY_LOCK_INTR) { return NULL; } @@ -192,6 +204,13 @@ PyDoc_STRVAR(locked_doc, \n\ Return whether the lock is in the locked state."); +static PyObject * +lock_repr(lockobject *self) +{ + return PyUnicode_FromFormat("<%s %s object at %p>", + self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self); +} + static PyMethodDef lock_methods[] = { {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock, METH_VARARGS | METH_KEYWORDS, acquire_doc}, @@ -223,7 +242,7 @@ static PyTypeObject Locktype = { 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_reserved*/ - 0, /*tp_repr*/ + (reprfunc)lock_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ @@ -274,41 +293,13 @@ rlock_dealloc(rlockobject *self) static PyObject * rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds) { - char *kwlist[] = {"blocking", "timeout", NULL}; - int blocking = 1; - double timeout = -1; - PY_TIMEOUT_T microseconds; + _PyTime_t timeout; long tid; PyLockStatus r = PY_LOCK_ACQUIRED; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|id:acquire", kwlist, - &blocking, &timeout)) + if (lock_acquire_parse_args(args, kwds, &timeout) < 0) return NULL; - if (!blocking && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "can't specify a timeout " - "for a non-blocking call"); - return NULL; - } - if (timeout < 0 && timeout != -1) { - PyErr_SetString(PyExc_ValueError, "timeout value must be " - "strictly positive"); - return NULL; - } - if (!blocking) - microseconds = 0; - else if (timeout == -1) - microseconds = -1; - else { - timeout *= 1e6; - if (timeout >= (double) PY_TIMEOUT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout value is too large"); - return NULL; - } - microseconds = (PY_TIMEOUT_T) timeout; - } - tid = PyThread_get_thread_ident(); if (self->rlock_count > 0 && tid == self->rlock_owner) { unsigned long count = self->rlock_count + 1; @@ -320,7 +311,7 @@ rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds) self->rlock_count = count; Py_RETURN_TRUE; } - r = acquire_timed(self->rlock_lock, microseconds); + r = acquire_timed(self->rlock_lock, timeout); if (r == PY_LOCK_ACQUIRED) { assert(self->rlock_count == 0); self->rlock_owner = tid; @@ -475,8 +466,10 @@ rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static PyObject * rlock_repr(rlockobject *self) { - return PyUnicode_FromFormat("<%s owner=%ld count=%lu>", - Py_TYPE(self)->tp_name, self->rlock_owner, self->rlock_count); + return PyUnicode_FromFormat("<%s %s object owner=%ld count=%lu at %p>", + self->rlock_count ? "locked" : "unlocked", + Py_TYPE(self)->tp_name, self->rlock_owner, + self->rlock_count, self); } @@ -1353,7 +1346,9 @@ static struct PyModuleDef threadmodule = { PyMODINIT_FUNC PyInit__thread(void) { - PyObject *m, *d, *timeout_max; + PyObject *m, *d, *v; + double time_max; + double timeout_max; /* Initialize types: */ if (PyType_Ready(&localdummytype) < 0) @@ -1370,10 +1365,14 @@ PyInit__thread(void) if (m == NULL) return NULL; - timeout_max = PyFloat_FromDouble(PY_TIMEOUT_MAX / 1000000); - if (!timeout_max) + timeout_max = PY_TIMEOUT_MAX / 1000000; + time_max = floor(_PyTime_AsSecondsDouble(_PyTime_MAX)); + timeout_max = Py_MIN(timeout_max, time_max); + + v = PyFloat_FromDouble(timeout_max); + if (!v) return NULL; - if (PyModule_AddObject(m, "TIMEOUT_MAX", timeout_max) < 0) + if (PyModule_AddObject(m, "TIMEOUT_MAX", v) < 0) return NULL; /* Add a symbolic constant */ |