Skip to content

Commit 45bdd27

Browse files
committed
threading: make _thread.lock thread-safe
1 parent 31ec6f0 commit 45bdd27

File tree

1 file changed

+21
-37
lines changed

1 file changed

+21
-37
lines changed

Modules/_threadmodule.c

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@ get_thread_state(PyObject *module)
4343

4444
typedef struct {
4545
PyObject_HEAD
46-
PyThread_type_lock lock_lock;
46+
_PyMutex mutex;
4747
PyObject *in_weakreflist;
48-
char locked; /* for sanity checking */
4948
} lockobject;
5049

5150
static int
@@ -62,12 +61,6 @@ lock_dealloc(lockobject *self)
6261
if (self->in_weakreflist != NULL) {
6362
PyObject_ClearWeakRefs((PyObject *) self);
6463
}
65-
if (self->lock_lock != NULL) {
66-
/* Unlock the lock so it's safe to free it */
67-
if (self->locked)
68-
PyThread_release_lock(self->lock_lock);
69-
PyThread_free_lock(self->lock_lock);
70-
}
7164
PyTypeObject *tp = Py_TYPE(self);
7265
tp->tp_free((PyObject*)self);
7366
Py_DECREF(tp);
@@ -177,14 +170,19 @@ lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds)
177170
if (lock_acquire_parse_args(args, kwds, &timeout) < 0)
178171
return NULL;
179172

180-
PyLockStatus r = acquire_timed(self->lock_lock, timeout);
181-
if (r == PY_LOCK_INTR) {
173+
_PyLockFlags flags = _PY_LOCK_DETACH | _PY_LOCK_MAKE_PENDING_CALLS;
174+
PyLockStatus status = _PyMutex_TimedLockEx(&self->mutex, timeout, flags);
175+
if (status == PY_LOCK_ACQUIRED) {
176+
assert((self->mutex.v & LOCKED) == LOCKED);
177+
Py_RETURN_TRUE;
178+
}
179+
else if (status == PY_LOCK_FAILURE) {
180+
Py_RETURN_FALSE;
181+
}
182+
else {
183+
assert(status == PY_LOCK_INTR);
182184
return NULL;
183185
}
184-
185-
if (r == PY_LOCK_ACQUIRED)
186-
self->locked = 1;
187-
return PyBool_FromLong(r == PY_LOCK_ACQUIRED);
188186
}
189187

190188
PyDoc_STRVAR(acquire_doc,
@@ -201,14 +199,10 @@ The blocking operation is interruptible.");
201199
static PyObject *
202200
lock_PyThread_release_lock(lockobject *self, PyObject *Py_UNUSED(ignored))
203201
{
204-
/* Sanity check: the lock must be locked */
205-
if (!self->locked) {
202+
if (_PyMutex_TryUnlock(&self->mutex) < 0) {
206203
PyErr_SetString(ThreadError, "release unlocked lock");
207204
return NULL;
208205
}
209-
210-
self->locked = 0;
211-
PyThread_release_lock(self->lock_lock);
212206
Py_RETURN_NONE;
213207
}
214208

@@ -223,7 +217,10 @@ but it needn't be locked by the same thread that unlocks it.");
223217
static PyObject *
224218
lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored))
225219
{
226-
return PyBool_FromLong((long)self->locked);
220+
if (_PyMutex_is_locked(&self->mutex))
221+
Py_RETURN_TRUE;
222+
else
223+
Py_RETURN_FALSE;
227224
}
228225

229226
PyDoc_STRVAR(locked_doc,
@@ -235,21 +232,16 @@ Return whether the lock is in the locked state.");
235232
static PyObject *
236233
lock_repr(lockobject *self)
237234
{
235+
int locked = _PyMutex_is_locked(&self->mutex);
238236
return PyUnicode_FromFormat("<%s %s object at %p>",
239-
self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self);
237+
locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self);
240238
}
241239

242240
#ifdef HAVE_FORK
243241
static PyObject *
244242
lock__at_fork_reinit(lockobject *self, PyObject *Py_UNUSED(args))
245243
{
246-
if (_PyThread_at_fork_reinit(&self->lock_lock) < 0) {
247-
PyErr_SetString(ThreadError, "failed to reinitialize lock at fork");
248-
return NULL;
249-
}
250-
251-
self->locked = 0;
252-
244+
memset(&self->mutex, 0, sizeof(self->mutex));
253245
Py_RETURN_NONE;
254246
}
255247
#endif /* HAVE_FORK */
@@ -804,16 +796,8 @@ newlockobject(PyObject *module)
804796
if (self == NULL) {
805797
return NULL;
806798
}
807-
808-
self->lock_lock = PyThread_allocate_lock();
809-
self->locked = 0;
799+
memset(&self->mutex, 0, sizeof(self->mutex));
810800
self->in_weakreflist = NULL;
811-
812-
if (self->lock_lock == NULL) {
813-
Py_DECREF(self);
814-
PyErr_SetString(ThreadError, "can't allocate lock");
815-
return NULL;
816-
}
817801
return self;
818802
}
819803

0 commit comments

Comments
 (0)