summaryrefslogtreecommitdiffstats
path: root/Modules/_testcapimodule.c
diff options
context:
space:
mode:
authorKumar Aditya <59607654+kumaraditya303@users.noreply.github.com>2023-01-11 10:33:31 (GMT)
committerGitHub <noreply@github.com>2023-01-11 10:33:31 (GMT)
commit762745a124cbc297cf2fe6f3ec9ca1840bb2e873 (patch)
treeafda022491baf91db77ddd5909833e91cb166aee /Modules/_testcapimodule.c
parent847d7708ba8739a5d5d31f22d71497527a7d8241 (diff)
downloadcpython-762745a124cbc297cf2fe6f3ec9ca1840bb2e873.zip
cpython-762745a124cbc297cf2fe6f3ec9ca1840bb2e873.tar.gz
cpython-762745a124cbc297cf2fe6f3ec9ca1840bb2e873.tar.bz2
GH-100892: Fix race in clearing `threading.local` (#100922)
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r--Modules/_testcapimodule.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index c777c3e..486988b 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -1879,12 +1879,19 @@ temporary_c_thread(void *data)
PyThread_release_lock(test_c_thread->exit_event);
}
+static test_c_thread_t test_c_thread;
+
static PyObject *
-call_in_temporary_c_thread(PyObject *self, PyObject *callback)
+call_in_temporary_c_thread(PyObject *self, PyObject *args)
{
PyObject *res = NULL;
- test_c_thread_t test_c_thread;
+ PyObject *callback = NULL;
long thread;
+ int wait = 1;
+ if (!PyArg_ParseTuple(args, "O|i", &callback, &wait))
+ {
+ return NULL;
+ }
test_c_thread.start_event = PyThread_allocate_lock();
test_c_thread.exit_event = PyThread_allocate_lock();
@@ -1910,6 +1917,10 @@ call_in_temporary_c_thread(PyObject *self, PyObject *callback)
PyThread_acquire_lock(test_c_thread.start_event, 1);
PyThread_release_lock(test_c_thread.start_event);
+ if (!wait) {
+ Py_RETURN_NONE;
+ }
+
Py_BEGIN_ALLOW_THREADS
PyThread_acquire_lock(test_c_thread.exit_event, 1);
PyThread_release_lock(test_c_thread.exit_event);
@@ -1919,13 +1930,32 @@ call_in_temporary_c_thread(PyObject *self, PyObject *callback)
exit:
Py_CLEAR(test_c_thread.callback);
- if (test_c_thread.start_event)
+ if (test_c_thread.start_event) {
PyThread_free_lock(test_c_thread.start_event);
- if (test_c_thread.exit_event)
+ test_c_thread.start_event = NULL;
+ }
+ if (test_c_thread.exit_event) {
PyThread_free_lock(test_c_thread.exit_event);
+ test_c_thread.exit_event = NULL;
+ }
return res;
}
+static PyObject *
+join_temporary_c_thread(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(test_c_thread.exit_event, 1);
+ PyThread_release_lock(test_c_thread.exit_event);
+ Py_END_ALLOW_THREADS
+ Py_CLEAR(test_c_thread.callback);
+ PyThread_free_lock(test_c_thread.start_event);
+ test_c_thread.start_event = NULL;
+ PyThread_free_lock(test_c_thread.exit_event);
+ test_c_thread.exit_event = NULL;
+ Py_RETURN_NONE;
+}
+
/* marshal */
static PyObject*
@@ -3275,8 +3305,9 @@ static PyMethodDef TestMethods[] = {
METH_VARARGS | METH_KEYWORDS},
{"with_tp_del", with_tp_del, METH_VARARGS},
{"create_cfunction", create_cfunction, METH_NOARGS},
- {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O,
+ {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_VARARGS,
PyDoc_STR("set_error_class(error_class) -> None")},
+ {"join_temporary_c_thread", join_temporary_c_thread, METH_NOARGS},
{"pymarshal_write_long_to_file",
pymarshal_write_long_to_file, METH_VARARGS},
{"pymarshal_write_object_to_file",