summaryrefslogtreecommitdiffstats
path: root/Modules/_testcapimodule.c
diff options
context:
space:
mode:
authorGregory P. Smith <greg@krypto.org>2022-12-29 22:41:39 (GMT)
committerGitHub <noreply@github.com>2022-12-29 22:41:39 (GMT)
commit894f2c3c161933bd820ad322b3b678d89bc2377c (patch)
tree9c41c6fe2ce16ab42d7fc35223eeca1c061ea269 /Modules/_testcapimodule.c
parent2df82db48506e5a2044a28f147fdb42f662d37b9 (diff)
downloadcpython-894f2c3c161933bd820ad322b3b678d89bc2377c.zip
cpython-894f2c3c161933bd820ad322b3b678d89bc2377c.tar.gz
cpython-894f2c3c161933bd820ad322b3b678d89bc2377c.tar.bz2
gh-100228: Warn from os.fork() if other threads exist. (#100229)
Not comprehensive, best effort warning. There are cases when threads exist on some platforms that this code cannot detect. macOS when API permissions allow and Linux with a readable /proc procfs present are the currently supported cases where a warning should show up reliably. Starting with a DeprecationWarning for now, it is less disruptive than something like RuntimeWarning and most likely to only be seen in people's CI tests - a good place to start with this messaging.
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r--Modules/_testcapimodule.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index c32fdb5..c777c3e 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -25,6 +25,9 @@
#include "structmember.h" // for offsetof(), T_OBJECT
#include <float.h> // FLT_MAX
#include <signal.h>
+#ifndef MS_WINDOWS
+#include <unistd.h>
+#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h> // W_STOPCODE
@@ -871,6 +874,46 @@ test_thread_state(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
+#ifndef MS_WINDOWS
+static PyThread_type_lock wait_done = NULL;
+
+static void wait_for_lock(void *unused) {
+ PyThread_acquire_lock(wait_done, 1);
+ PyThread_release_lock(wait_done);
+ PyThread_free_lock(wait_done);
+ wait_done = NULL;
+}
+
+// These can be used to test things that care about the existence of another
+// thread that the threading module doesn't know about.
+
+static PyObject *
+spawn_pthread_waiter(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ if (wait_done) {
+ PyErr_SetString(PyExc_RuntimeError, "thread already running");
+ return NULL;
+ }
+ wait_done = PyThread_allocate_lock();
+ if (wait_done == NULL)
+ return PyErr_NoMemory();
+ PyThread_acquire_lock(wait_done, 1);
+ PyThread_start_new_thread(wait_for_lock, NULL);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+end_spawned_pthread(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ if (!wait_done) {
+ PyErr_SetString(PyExc_RuntimeError, "call _spawn_pthread_waiter 1st");
+ return NULL;
+ }
+ PyThread_release_lock(wait_done);
+ Py_RETURN_NONE;
+}
+#endif // not MS_WINDOWS
+
/* test Py_AddPendingCalls using threads */
static int _pending_callback(void *arg)
{
@@ -3207,6 +3250,10 @@ static PyMethodDef TestMethods[] = {
{"test_get_type_name", test_get_type_name, METH_NOARGS},
{"test_get_type_qualname", test_get_type_qualname, METH_NOARGS},
{"_test_thread_state", test_thread_state, METH_VARARGS},
+#ifndef MS_WINDOWS
+ {"_spawn_pthread_waiter", spawn_pthread_waiter, METH_NOARGS},
+ {"_end_spawned_pthread", end_spawned_pthread, METH_NOARGS},
+#endif
{"_pending_threadfunc", pending_threadfunc, METH_VARARGS},
#ifdef HAVE_GETTIMEOFDAY
{"profile_int", profile_int, METH_NOARGS},