|
release_sentinel(void *wr_raw) |
|
{ |
|
PyObject *wr = _PyObject_CAST(wr_raw); |
|
/* Tricky: this function is called when the current thread state |
|
is being deleted. Therefore, only simple C code can safely |
|
execute here. */ |
|
PyObject *obj = PyWeakref_GET_OBJECT(wr); |
|
lockobject *lock; |
|
if (obj != Py_None) { |
|
lock = (lockobject *) obj; |
|
if (lock->locked) { |
|
PyThread_release_lock(lock->lock_lock); |
|
lock->locked = 0; |
|
} |
|
} |
|
/* Deallocating a weakref with a NULL callback only calls |
|
PyObject_GC_Del(), which can't call any Python code. */ |
|
Py_DECREF(wr); |
|
} |
|
|
|
static PyObject * |
|
thread__set_sentinel(PyObject *module, PyObject *Py_UNUSED(ignored)) |
|
{ |
|
PyObject *wr; |
|
PyThreadState *tstate = PyThreadState_Get(); |
|
lockobject *lock; |
|
|
|
if (tstate->on_delete_data != NULL) { |
|
/* We must support the re-creation of the lock from a |
|
fork()ed child. */ |
|
assert(tstate->on_delete == &release_sentinel); |
|
wr = (PyObject *) tstate->on_delete_data; |
|
tstate->on_delete = NULL; |
|
tstate->on_delete_data = NULL; |
|
Py_DECREF(wr); |
|
} |
|
lock = newlockobject(module); |
|
if (lock == NULL) |
|
return NULL; |
|
/* The lock is owned by whoever called _set_sentinel(), but the weakref |
|
hangs to the thread state. */ |
|
wr = PyWeakref_NewRef((PyObject *) lock, NULL); |
|
if (wr == NULL) { |
|
Py_DECREF(lock); |
|
return NULL; |
|
} |
|
tstate->on_delete_data = (void *) wr; |
|
tstate->on_delete = &release_sentinel; |
|
return (PyObject *) lock; |
|
} |