summaryrefslogtreecommitdiffstats
path: root/Modules/_threadmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_threadmodule.c')
-rw-r--r--Modules/_threadmodule.c155
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 */