https://github.com/python/cpython/commit/a5b03fa1d71925576892a82f1f12a86f11f69f35
commit: a5b03fa1d71925576892a82f1f12a86f11f69f35
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-09-24T18:17:25Z
summary:

gh-155496: Use Argument Clinic for more functions of the _thread module 
(GH-155514)

files:
M Include/internal/pycore_global_objects_fini_generated.h
M Include/internal/pycore_global_strings.h
M Include/internal/pycore_runtime_init_generated.h
M Include/internal/pycore_unicodeobject_generated.h
M Modules/_threadmodule.c
M Modules/clinic/_threadmodule.c.h

diff --git a/Include/internal/pycore_global_objects_fini_generated.h 
b/Include/internal/pycore_global_objects_fini_generated.h
index 8c8a2d9ea51aef..f3b1fd3ac52680 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -404,6 +404,7 @@ _PyStaticObjects_CheckAll(PyInterpreterState *interp) {
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(ctx), "ctx", 3);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(cwd), "cwd", 3);
     _PyStaticObject_CheckUnicodeSingleton((PyObject 
*)&_Py_ID(d_parameter_type), "d_parameter_type", 16);
+    _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(daemon), 
"daemon", 6);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(data), "data", 
4);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(database), 
"database", 8);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(date), "date", 
4);
@@ -504,6 +505,7 @@ _PyStaticObjects_CheckAll(PyInterpreterState *interp) {
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(fset), "fset", 
4);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(fullerror), 
"fullerror", 9);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(func), "func", 
4);
+    _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(function), 
"function", 8);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(future), 
"future", 6);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(gc), "gc", 2);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(generation), 
"generation", 10);
diff --git a/Include/internal/pycore_global_strings.h 
b/Include/internal/pycore_global_strings.h
index 5b35c53e0aa03b..f6cf449ecc35d8 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -416,6 +416,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(ctx)
         STRUCT_FOR_ID(cwd)
         STRUCT_FOR_ID(d_parameter_type)
+        STRUCT_FOR_ID(daemon)
         STRUCT_FOR_ID(data)
         STRUCT_FOR_ID(database)
         STRUCT_FOR_ID(date)
@@ -516,6 +517,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(fset)
         STRUCT_FOR_ID(fullerror)
         STRUCT_FOR_ID(func)
+        STRUCT_FOR_ID(function)
         STRUCT_FOR_ID(future)
         STRUCT_FOR_ID(gc)
         STRUCT_FOR_ID(generation)
diff --git a/Include/internal/pycore_runtime_init_generated.h 
b/Include/internal/pycore_runtime_init_generated.h
index c80925f020186b..e54c9bf97a9476 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -1691,6 +1691,7 @@ extern "C" {
     INIT_ID(ctx), \
     INIT_ID(cwd), \
     INIT_ID(d_parameter_type), \
+    INIT_ID(daemon), \
     INIT_ID(data), \
     INIT_ID(database), \
     INIT_ID(date), \
@@ -1791,6 +1792,7 @@ extern "C" {
     INIT_ID(fset), \
     INIT_ID(fullerror), \
     INIT_ID(func), \
+    INIT_ID(function), \
     INIT_ID(future), \
     INIT_ID(gc), \
     INIT_ID(generation), \
diff --git a/Include/internal/pycore_unicodeobject_generated.h 
b/Include/internal/pycore_unicodeobject_generated.h
index a9db3b828d1ef8..e692bd945ac139 100644
--- a/Include/internal/pycore_unicodeobject_generated.h
+++ b/Include/internal/pycore_unicodeobject_generated.h
@@ -371,6 +371,7 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
         offsetof(struct _Py_global_strings, 
identifiers._py_ctx._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_cwd._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_d_parameter_type._ascii.ob_base),
+        offsetof(struct _Py_global_strings, 
identifiers._py_daemon._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_data._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_database._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_date._ascii.ob_base),
@@ -471,6 +472,7 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
         offsetof(struct _Py_global_strings, 
identifiers._py_fset._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_fullerror._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_func._ascii.ob_base),
+        offsetof(struct _Py_global_strings, 
identifiers._py_function._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_future._ascii.ob_base),
         offsetof(struct _Py_global_strings, identifiers._py_gc._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py_generation._ascii.ob_base),
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index a79ea5728e72d6..058d16f14f290e 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -85,8 +85,9 @@ static PF_SET_THREAD_DESCRIPTION pSetThreadDescription = NULL;
 module _thread
 class _thread.lock "lockobject *" "clinic_state()->lock_type"
 class _thread.RLock "rlockobject *" "clinic_state()->rlock_type"
+class _thread._ThreadHandle "PyObject *" "clinic_state()->thread_handle_type"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c5a0f8c492a0c263]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bd4eae07ae18bc2c]*/
 
 #define clinic_state() get_thread_state_by_cls(type)
 #include "clinic/_threadmodule.c.h"
@@ -678,43 +679,57 @@ PyThreadHandleObject_repr(PyObject *op)
                                 Py_TYPE(self)->tp_name, ident);
 }
 
+/*[clinic input]
+@getter
+_thread._ThreadHandle.ident
+[clinic start generated code]*/
+
 static PyObject *
-PyThreadHandleObject_get_ident(PyObject *op, void *Py_UNUSED(closure))
+_thread__ThreadHandle_ident_get_impl(PyObject *self)
+/*[clinic end generated code: output=66d40aa1a624ac23 input=2b3361e34a6ca79d]*/
 {
-    PyThreadHandleObject *self = PyThreadHandleObject_CAST(op);
-    return PyLong_FromUnsignedLongLong(ThreadHandle_ident(self->handle));
+    PyThreadHandleObject *handle = PyThreadHandleObject_CAST(self);
+    return PyLong_FromUnsignedLongLong(ThreadHandle_ident(handle->handle));
 }
 
+/*[clinic input]
+_thread._ThreadHandle.join
+    timeout as timeout_obj: object = None
+    /
+[clinic start generated code]*/
+
 static PyObject *
-PyThreadHandleObject_join(PyObject *op, PyObject *args)
+_thread__ThreadHandle_join_impl(PyObject *self, PyObject *timeout_obj)
+/*[clinic end generated code: output=d3a4f0b20c21442e input=b66d17a0f77d6e9c]*/
 {
-    PyThreadHandleObject *self = PyThreadHandleObject_CAST(op);
-
-    PyObject *timeout_obj = NULL;
-    if (!PyArg_ParseTuple(args, "|O:join", &timeout_obj)) {
-        return NULL;
-    }
+    PyThreadHandleObject *handle = PyThreadHandleObject_CAST(self);
 
     PyTime_t timeout_ns = -1;
-    if (timeout_obj != NULL && timeout_obj != Py_None) {
+    if (timeout_obj != Py_None) {
         if (_PyTime_FromSecondsObject(&timeout_ns, timeout_obj,
                                       _PyTime_ROUND_TIMEOUT) < 0) {
             return NULL;
         }
     }
 
-    if (ThreadHandle_join(self->handle, timeout_ns) < 0) {
+    if (ThreadHandle_join(handle->handle, timeout_ns) < 0) {
         return NULL;
     }
     Py_RETURN_NONE;
 }
 
+/*[clinic input]
+_thread._ThreadHandle.is_done
+[clinic start generated code]*/
+
 static PyObject *
-PyThreadHandleObject_is_done(PyObject *op, PyObject *Py_UNUSED(dummy))
+_thread__ThreadHandle_is_done_impl(PyObject *self)
+/*[clinic end generated code: output=f5c00923fb61967b input=dd905a1ac7fc2e7c]*/
 {
-    PyThreadHandleObject *self = PyThreadHandleObject_CAST(op);
-    if (_PyEvent_IsSet(&self->handle->thread_is_exiting)) {
-        if (_PyOnceFlag_CallOnce(&self->handle->once, join_thread, 
self->handle) == -1) {
+    PyThreadHandleObject *handle = PyThreadHandleObject_CAST(self);
+    if (_PyEvent_IsSet(&handle->handle->thread_is_exiting)) {
+        if (_PyOnceFlag_CallOnce(&handle->handle->once, join_thread,
+                                 handle->handle) == -1) {
             return NULL;
         }
         Py_RETURN_TRUE;
@@ -724,25 +739,30 @@ PyThreadHandleObject_is_done(PyObject *op, PyObject 
*Py_UNUSED(dummy))
     }
 }
 
+/*[clinic input]
+_thread._ThreadHandle._set_done
+[clinic start generated code]*/
+
 static PyObject *
-PyThreadHandleObject_set_done(PyObject *op, PyObject *Py_UNUSED(dummy))
+_thread__ThreadHandle__set_done_impl(PyObject *self)
+/*[clinic end generated code: output=709b4d7ca318bb6d input=9f0115db8d84806b]*/
 {
-    PyThreadHandleObject *self = PyThreadHandleObject_CAST(op);
-    if (ThreadHandle_set_done(self->handle) < 0) {
+    PyThreadHandleObject *handle = PyThreadHandleObject_CAST(self);
+    if (ThreadHandle_set_done(handle->handle) < 0) {
         return NULL;
     }
     Py_RETURN_NONE;
 }
 
 static PyGetSetDef ThreadHandle_getsetlist[] = {
-    {"ident", PyThreadHandleObject_get_ident, NULL, NULL},
+    _THREAD__THREADHANDLE_IDENT_GETSETDEF
     {0},
 };
 
 static PyMethodDef ThreadHandle_methods[] = {
-    {"join", PyThreadHandleObject_join, METH_VARARGS, NULL},
-    {"_set_done", PyThreadHandleObject_set_done, METH_NOARGS, NULL},
-    {"is_done", PyThreadHandleObject_is_done, METH_NOARGS, NULL},
+    _THREAD__THREADHANDLE_JOIN_METHODDEF
+    _THREAD__THREADHANDLE__SET_DONE_METHODDEF
+    _THREAD__THREADHANDLE_IS_DONE_METHODDEF
     {0, 0}
 };
 
@@ -1875,8 +1895,17 @@ clear_locals(PyObject *locals_and_key, PyObject 
*dummyweakref)
 
 /* Module functions */
 
+/*[clinic input]
+_thread.daemon_threads_allowed
+
+Return True if daemon threads are allowed in the current interpreter.
+
+Return False otherwise.
+[clinic start generated code]*/
+
 static PyObject *
-thread_daemon_threads_allowed(PyObject *module, PyObject *Py_UNUSED(ignored))
+_thread_daemon_threads_allowed_impl(PyObject *module)
+/*[clinic end generated code: output=c82b3b9490c7e11e input=f94150f9e14b7d0c]*/
 {
     PyInterpreterState *interp = _PyInterpreterState_GET();
     if (interp->feature_flags & Py_RTFLAGS_DAEMON_THREADS) {
@@ -1887,13 +1916,6 @@ thread_daemon_threads_allowed(PyObject *module, PyObject 
*Py_UNUSED(ignored))
     }
 }
 
-PyDoc_STRVAR(daemon_threads_allowed_doc,
-"daemon_threads_allowed($module, /)\n\
---\n\
-\n\
-Return True if daemon threads are allowed in the current interpreter,\n\
-and False otherwise.\n");
-
 static int
 do_start_new_thread(thread_module_state *state, PyObject *func, PyObject *args,
                     PyObject *kwargs, ThreadHandle *handle, int daemon)
@@ -1927,31 +1949,36 @@ do_start_new_thread(thread_module_state *state, 
PyObject *func, PyObject *args,
     return 0;
 }
 
+/*[clinic input]
+_thread.start_new_thread
+
+    function as func: object
+    args: object(subclass_of='&PyTuple_Type')
+    kwargs: object(subclass_of='&PyDict_Type', c_default="NULL") = {}
+    /
+
+Start a new thread and return its identifier.
+
+The thread will call the function with positional arguments from the
+tuple args and keyword arguments taken from the optional dictionary
+kwargs.  The thread exits when the function returns; the return value
+is ignored.  The thread will also exit when the function raises an
+unhandled exception; a stack trace will be printed unless the exception
+is SystemExit.
+[clinic start generated code]*/
+
 static PyObject *
-thread_PyThread_start_new_thread(PyObject *module, PyObject *fargs)
+_thread_start_new_thread_impl(PyObject *module, PyObject *func,
+                              PyObject *args, PyObject *kwargs)
+/*[clinic end generated code: output=0c27eb61b7a7152b input=b85f6b3301d30719]*/
 {
-    PyObject *func, *args, *kwargs = NULL;
     thread_module_state *state = get_thread_state(module);
 
-    if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
-                           &func, &args, &kwargs))
-        return NULL;
     if (!PyCallable_Check(func)) {
         PyErr_SetString(PyExc_TypeError,
                         "first arg must be callable");
         return NULL;
     }
-    if (!PyTuple_Check(args)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "2nd arg must be a tuple");
-        return NULL;
-    }
-    if (kwargs != NULL && !PyDict_Check(kwargs)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "optional 3rd arg must be a dictionary");
-        return NULL;
-    }
-
     if (PySys_Audit("_thread.start_new_thread", "OOO",
                     func, args, kwargs ? kwargs : Py_None) < 0) {
         return NULL;
@@ -1973,39 +2000,36 @@ thread_PyThread_start_new_thread(PyObject *module, 
PyObject *fargs)
     return PyLong_FromUnsignedLongLong(ident);
 }
 
-PyDoc_STRVAR(start_new_thread_doc,
-"start_new_thread($module, function, args, kwargs={}, /)\n\
---\n\
-\n\
-Start a new thread and return its identifier.\n\
-\n\
-The thread will call the function with positional arguments from the\n\
-tuple args and keyword arguments taken from the optional dictionary\n\
-kwargs.  The thread exits when the function returns; the return value\n\
-is ignored.  The thread will also exit when the function raises an\n\
-unhandled exception; a stack trace will be printed unless the exception\n\
-is SystemExit.");
-
 PyDoc_STRVAR(start_new_doc,
 "start_new($module, function, args, kwargs={}, /)\n\
 --\n\
 \n\
 An obsolete synonym of start_new_thread().");
 
+/*[clinic input]
+_thread.start_joinable_thread
+
+    function as func: object
+    handle as hobj: object = None
+    daemon: bool = True
+
+*For internal use only*: start a new thread.
+
+Like start_new_thread(), this starts a new thread calling the given
+function.  Unlike start_new_thread(), this returns a handle object with
+methods to join or detach the given thread.
+This function is not for third-party code, please use the `threading`
+module instead.  During finalization the runtime will not wait for the
+thread to exit if daemon is True.  If handle is provided it must be a
+newly created thread._ThreadHandle instance.
+[clinic start generated code]*/
+
 static PyObject *
-thread_PyThread_start_joinable_thread(PyObject *module, PyObject *fargs,
-                                      PyObject *fkwargs)
+_thread_start_joinable_thread_impl(PyObject *module, PyObject *func,
+                                   PyObject *hobj, int daemon)
+/*[clinic end generated code: output=58691769e60620cf input=e17b3aebc087952a]*/
 {
-    static char *keywords[] = {"function", "handle", "daemon", NULL};
-    PyObject *func = NULL;
-    int daemon = 1;
     thread_module_state *state = get_thread_state(module);
-    PyObject *hobj = NULL;
-    if (!PyArg_ParseTupleAndKeywords(fargs, fkwargs,
-                                     "O|Op:start_joinable_thread", keywords,
-                                     &func, &hobj, &daemon)) {
-        return NULL;
-    }
 
     if (!PyCallable_Check(func)) {
         PyErr_SetString(PyExc_TypeError,
@@ -2013,10 +2037,7 @@ thread_PyThread_start_joinable_thread(PyObject *module, 
PyObject *fargs,
         return NULL;
     }
 
-    if (hobj == NULL) {
-        hobj = Py_None;
-    }
-    else if (hobj != Py_None && !Py_IS_TYPE(hobj, state->thread_handle_type)) {
+    if (hobj != Py_None && !Py_IS_TYPE(hobj, state->thread_handle_type)) {
         PyErr_SetString(PyExc_TypeError, "'handle' must be a _ThreadHandle");
         return NULL;
     }
@@ -2050,48 +2071,49 @@ thread_PyThread_start_joinable_thread(PyObject *module, 
PyObject *fargs,
     return (PyObject *) hobj;
 }
 
-PyDoc_STRVAR(start_joinable_doc,
-"start_joinable_thread($module, /, function, handle=None, daemon=True)\n\
---\n\
-\n\
-*For internal use only*: start a new thread.\n\
-\n\
-Like start_new_thread(), this starts a new thread calling the given 
function.\n\
-Unlike start_new_thread(), this returns a handle object with methods to join\n\
-or detach the given thread.\n\
-This function is not for third-party code, please use the\n\
-`threading` module instead. During finalization the runtime will not wait 
for\n\
-the thread to exit if daemon is True. If handle is provided it must be a\n\
-newly created thread._ThreadHandle instance.");
+/*[clinic input]
+_thread.exit
+
+Raise SystemExit.
+
+It will cause the current thread to exit silently unless the exception
+is caught.
+[clinic start generated code]*/
 
 static PyObject *
-thread_PyThread_exit_thread(PyObject *self, PyObject *Py_UNUSED(ignored))
+_thread_exit_impl(PyObject *module)
+/*[clinic end generated code: output=b03924346e743f4c input=1f3dc5da8ad48c70]*/
 {
     PyErr_SetNone(PyExc_SystemExit);
     return NULL;
 }
 
-PyDoc_STRVAR(exit_doc,
-"exit($module, /)\n\
---\n\
-\n\
-This is synonymous to ``raise SystemExit''.  It will cause the current\n\
-thread to exit silently unless the exception is caught.");
-
 PyDoc_STRVAR(exit_thread_doc,
 "exit_thread($module, /)\n\
 --\n\
 \n\
 An obsolete synonym of exit().");
 
+/*[clinic input]
+_thread.interrupt_main
+
+    signum: int(c_default="SIGINT") = signal.SIGINT
+    /
+
+Simulate the arrival of the given signal in the main thread.
+
+The corresponding signal handler will be executed.
+If *signum* is omitted, SIGINT is assumed.
+A subthread can use this function to interrupt the main thread.
+
+Note: the default signal handler for SIGINT raises
+``KeyboardInterrupt``.
+[clinic start generated code]*/
+
 static PyObject *
-thread_PyThread_interrupt_main(PyObject *self, PyObject *args)
+_thread_interrupt_main_impl(PyObject *module, int signum)
+/*[clinic end generated code: output=fdafa7261ceb26e9 input=a8cf392f3a7f2a84]*/
 {
-    int signum = SIGINT;
-    if (!PyArg_ParseTuple(args, "|i:signum", &signum)) {
-        return NULL;
-    }
-
     if (PyErr_SetInterruptEx(signum)) {
         PyErr_SetString(PyExc_ValueError, "signal number out of range");
         return NULL;
@@ -2099,40 +2121,44 @@ thread_PyThread_interrupt_main(PyObject *self, PyObject 
*args)
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(interrupt_doc,
-"interrupt_main($module, signum=signal.SIGINT, /)\n\
---\n\
-\n\
-Simulate the arrival of the given signal in the main thread,\n\
-where the corresponding signal handler will be executed.\n\
-If *signum* is omitted, SIGINT is assumed.\n\
-A subthread can use this function to interrupt the main thread.\n\
-\n\
-Note: the default signal handler for SIGINT raises ``KeyboardInterrupt``."
-);
+/*[clinic input]
+_thread.allocate_lock
+
+Create a new lock object.
+
+See help(type(threading.Lock())) for information about locks.
+[clinic start generated code]*/
 
 static PyObject *
-thread_PyThread_allocate_lock(PyObject *module, PyObject *Py_UNUSED(ignored))
+_thread_allocate_lock_impl(PyObject *module)
+/*[clinic end generated code: output=884a4be6cb9ca731 input=49f5b1f966361bb6]*/
 {
     thread_module_state *state = get_thread_state(module);
     return lock_new_impl(state->lock_type);
 }
 
-PyDoc_STRVAR(allocate_lock_doc,
-"allocate_lock($module, /)\n\
---\n\
-\n\
-Create a new lock object. See help(type(threading.Lock())) for\n\
-information about locks.");
-
 PyDoc_STRVAR(allocate_doc,
 "allocate($module, /)\n\
 --\n\
 \n\
 An obsolete synonym of allocate_lock().");
 
+/*[clinic input]
+_thread.get_ident
+
+Return a non-zero integer that uniquely identifies the current thread.
+
+It is unique amongst other threads that exist simultaneously.
+This may be used to identify per-thread resources.
+Even though on some platforms threads identities may appear to be
+allocated consecutive numbers starting at 1, this behavior should not
+be relied upon, and the number should be seen purely as a magic cookie.
+A thread's identity may be reused for another thread after it exits.
+[clinic start generated code]*/
+
 static PyObject *
-thread_get_ident(PyObject *self, PyObject *Py_UNUSED(ignored))
+_thread_get_ident_impl(PyObject *module)
+/*[clinic end generated code: output=8c3f9d8aa938b332 input=08faef37d1fd9e67]*/
 {
     PyThread_ident_t ident = PyThread_get_thread_ident_ex();
     if (ident == PYTHREAD_INVALID_THREAD_ID) {
@@ -2142,64 +2168,79 @@ thread_get_ident(PyObject *self, PyObject 
*Py_UNUSED(ignored))
     return PyLong_FromUnsignedLongLong(ident);
 }
 
-PyDoc_STRVAR(get_ident_doc,
-"get_ident($module, /)\n\
---\n\
-\n\
-Return a non-zero integer that uniquely identifies the current thread\n\
-amongst other threads that exist simultaneously.\n\
-This may be used to identify per-thread resources.\n\
-Even though on some platforms threads identities may appear to be\n\
-allocated consecutive numbers starting at 1, this behavior should not\n\
-be relied upon, and the number should be seen purely as a magic cookie.\n\
-A thread's identity may be reused for another thread after it exits.");
-
 #ifdef PY_HAVE_THREAD_NATIVE_ID
+/*[clinic input]
+_thread.get_native_id
+
+Return a non-negative integer identifying the thread.
+
+It is reported by the OS (kernel).  This may be used to uniquely
+identify a particular thread within a system.
+[clinic start generated code]*/
+
 static PyObject *
-thread_get_native_id(PyObject *self, PyObject *Py_UNUSED(ignored))
+_thread_get_native_id_impl(PyObject *module)
+/*[clinic end generated code: output=d69767224b4ba922 input=454af91013e4f747]*/
 {
     unsigned long native_id = PyThread_get_thread_native_id();
     return PyLong_FromUnsignedLong(native_id);
 }
 
-PyDoc_STRVAR(get_native_id_doc,
-"get_native_id($module, /)\n\
---\n\
-\n\
-Return a non-negative integer identifying the thread as reported\n\
-by the OS (kernel). This may be used to uniquely identify a\n\
-particular thread within a system.");
 #endif
 
+/*[clinic input]
+_thread._count
+
+Return the number of currently running Python threads.
+
+The main thread is excluded.  The returned number comprises all threads
+created through `start_new_thread()` as well as `threading.Thread`, and
+not yet finished.
+
+This function is meant for internal and specialized purposes only.
+In most applications `threading.enumerate()` should be used instead.
+[clinic start generated code]*/
+
 static PyObject *
-thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
+_thread__count_impl(PyObject *module)
+/*[clinic end generated code: output=4cd03377c3e8521d input=bbd340043d174d48]*/
 {
     PyInterpreterState *interp = _PyInterpreterState_GET();
     return PyLong_FromSsize_t(_Py_atomic_load_ssize(&interp->threads.count));
 }
 
-PyDoc_STRVAR(_count_doc,
-"_count($module, /)\n\
---\n\
-\n\
-Return the number of currently running Python threads, excluding\n\
-the main thread. The returned number comprises all threads created\n\
-through `start_new_thread()` as well as `threading.Thread`, and not\n\
-yet finished.\n\
-\n\
-This function is meant for internal and specialized purposes only.\n\
-In most applications `threading.enumerate()` should be used instead.");
+/*[clinic input]
+_thread.stack_size
+
+    size as new_size: Py_ssize_t = 0
+    /
+
+Return the thread stack size used when creating new threads.
+
+The optional size argument specifies the stack size (in bytes) to be
+used for subsequently created threads, and must be 0 (use platform or
+configured default) or a positive integer value of at least 32,768 (32
+KiB).  If changing the thread stack size is unsupported, a ThreadError
+exception is raised.  If the specified size is invalid, a ValueError
+exception is raised, and the stack size is unmodified.  32 KiB
+currently is the minimum supported stack size value to guarantee
+sufficient stack space for the interpreter itself.
+
+Note that some systems may have particular restrictions on values for
+the stack size, such as requiring a minimum stack size larger than 32
+KiB or requiring allocation in multiples of the system memory page size
+- platform documentation should be referred to for more information
+(4 KiB pages are common; using multiples of 4096 for the stack size is
+the suggested approach in the absence of more specific information).
+[clinic start generated code]*/
 
 static PyObject *
-thread_stack_size(PyObject *self, PyObject *args)
+_thread_stack_size_impl(PyObject *module, Py_ssize_t new_size)
+/*[clinic end generated code: output=cc7ba71bd35afc30 input=3249feb8ed2350f8]*/
 {
     size_t old_size;
-    Py_ssize_t new_size = 0;
     int rc;
 
-    if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
-        return NULL;
-
     Py_ssize_t min_size = _PyOS_MIN_STACK_SIZE + SYSTEM_PAGE_SIZE;
     if (new_size != 0 && new_size < min_size) {
         PyErr_Format(PyExc_ValueError,
@@ -2225,27 +2266,6 @@ thread_stack_size(PyObject *self, PyObject *args)
     return PyLong_FromSsize_t((Py_ssize_t) old_size);
 }
 
-PyDoc_STRVAR(stack_size_doc,
-"stack_size($module, size=0, /)\n\
---\n\
-\n\
-Return the thread stack size used when creating new threads.  The\n\
-optional size argument specifies the stack size (in bytes) to be used\n\
-for subsequently created threads, and must be 0 (use platform or\n\
-configured default) or a positive integer value of at least 32,768 (32k).\n\
-If changing the thread stack size is unsupported, a ThreadError\n\
-exception is raised.  If the specified size is invalid, a ValueError\n\
-exception is raised, and the stack size is unmodified.  32k bytes\n\
- currently the minimum supported stack size value to guarantee\n\
-sufficient stack space for the interpreter itself.\n\
-\n\
-Note that some platforms may have particular restrictions on values for\n\
-the stack size, such as requiring a minimum stack size larger than 32 KiB or\n\
-requiring allocation in multiples of the system memory page size\n\
-- platform documentation should be referred to for more information\n\
-(4 KiB pages are common; using multiples of 4096 for the stack size is\n\
-the suggested approach in the absence of more specific information).");
-
 static int
 thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value,
                        PyObject *exc_traceback, PyObject *thread)
@@ -2324,8 +2344,18 @@ static PyStructSequence_Desc ExceptHookArgs_desc = {
 };
 
 
+/*[clinic input]
+_thread._excepthook
+
+    args: object
+    /
+
+Handle uncaught Thread.run() exception.
+[clinic start generated code]*/
+
 static PyObject *
-thread_excepthook(PyObject *module, PyObject *args)
+_thread__excepthook(PyObject *module, PyObject *args)
+/*[clinic end generated code: output=cadc54a3be0e6007 input=5ae2316c400a3497]*/
 {
     thread_module_state *state = get_thread_state(module);
 
@@ -2381,30 +2411,32 @@ thread_excepthook(PyObject *module, PyObject *args)
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(excepthook_doc,
-"_excepthook($module, args, /)\n\
---\n\
-\n\
-Handle uncaught Thread.run() exception.");
+/*[clinic input]
+_thread._is_main_interpreter
+
+Return True if the current interpreter is the main Python interpreter.
+[clinic start generated code]*/
 
 static PyObject *
-thread__is_main_interpreter(PyObject *module, PyObject *Py_UNUSED(ignored))
+_thread__is_main_interpreter_impl(PyObject *module)
+/*[clinic end generated code: output=7dd82e1728339adc input=cc1eb00fd4598915]*/
 {
     PyInterpreterState *interp = _PyInterpreterState_GET();
     return PyBool_FromLong(_Py_IsMainInterpreter(interp));
 }
 
-PyDoc_STRVAR(thread__is_main_interpreter_doc,
-"_is_main_interpreter($module, /)\n\
---\n\
-\n\
-Return True if the current interpreter is the main Python interpreter.");
+/*[clinic input]
+_thread._shutdown
+
+Wait for all non-daemon threads (other than the calling thread) to stop.
+[clinic start generated code]*/
 
 static PyObject *
-thread_shutdown(PyObject *self, PyObject *args)
+_thread__shutdown_impl(PyObject *module)
+/*[clinic end generated code: output=a19afe92bddc1824 input=bcaeaceb3a6fa590]*/
 {
     PyThread_ident_t ident = PyThread_get_thread_ident_ex();
-    thread_module_state *state = get_thread_state(self);
+    thread_module_state *state = get_thread_state(module);
 
     for (;;) {
         ThreadHandle *handle = NULL;
@@ -2440,14 +2472,21 @@ thread_shutdown(PyObject *self, PyObject *args)
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(shutdown_doc,
-"_shutdown($module, /)\n\
---\n\
-\n\
-Wait for all non-daemon threads (other than the calling thread) to stop.");
+/*[clinic input]
+_thread._make_thread_handle
+
+    ident as identobj: object
+    /
+
+Internal only.
+
+Make a thread handle for threads not spawned by the _thread or
+threading module.
+[clinic start generated code]*/
 
 static PyObject *
-thread__make_thread_handle(PyObject *module, PyObject *identobj)
+_thread__make_thread_handle(PyObject *module, PyObject *identobj)
+/*[clinic end generated code: output=afa56c40a7e1c394 input=57bb20ebf5825dd1]*/
 {
     thread_module_state *state = get_thread_state(module);
     if (!PyLong_Check(identobj)) {
@@ -2470,26 +2509,22 @@ thread__make_thread_handle(PyObject *module, PyObject 
*identobj)
     return (PyObject*) hobj;
 }
 
-PyDoc_STRVAR(thread__make_thread_handle_doc,
-"_make_thread_handle($module, ident, /)\n\
---\n\
-\n\
-Internal only. Make a thread handle for threads not spawned\n\
-by the _thread or threading module.");
+/*[clinic input]
+_thread._get_main_thread_ident
+
+Internal only.
+
+Return a non-zero integer that uniquely identifies the main thread of
+the main interpreter.
+[clinic start generated code]*/
 
 static PyObject *
-thread__get_main_thread_ident(PyObject *module, PyObject *Py_UNUSED(ignored))
+_thread__get_main_thread_ident_impl(PyObject *module)
+/*[clinic end generated code: output=01aa07c5553458bf input=feea25c7039ba4b5]*/
 {
     return PyLong_FromUnsignedLongLong(_PyRuntime.main_thread);
 }
 
-PyDoc_STRVAR(thread__get_main_thread_ident_doc,
-"_get_main_thread_ident($module, /)\n\
---\n\
-\n\
-Internal only. Return a non-zero integer that uniquely identifies the main 
thread\n\
-of the main interpreter.");
-
 #if defined(__OpenBSD__)
     /* pthread_*_np functions, especially pthread_{get,set}_name_np().
        pthread_np.h exists on both OpenBSD and FreeBSD but the latter declares
@@ -2649,44 +2684,29 @@ _thread_set_name_impl(PyObject *module, PyObject 
*name_obj)
 
 
 static PyMethodDef thread_methods[] = {
-    {"start_new_thread",        thread_PyThread_start_new_thread,
-     METH_VARARGS, start_new_thread_doc},
-    {"start_new",               thread_PyThread_start_new_thread,
-     METH_VARARGS, start_new_doc},
-    {"start_joinable_thread",   
_PyCFunction_CAST(thread_PyThread_start_joinable_thread),
-     METH_VARARGS | METH_KEYWORDS, start_joinable_doc},
-    {"daemon_threads_allowed",  thread_daemon_threads_allowed,
-     METH_NOARGS, daemon_threads_allowed_doc},
-    {"allocate_lock",           thread_PyThread_allocate_lock,
-     METH_NOARGS, allocate_lock_doc},
-    {"allocate",                thread_PyThread_allocate_lock,
+    _THREAD_START_NEW_THREAD_METHODDEF
+    {"start_new",               _PyCFunction_CAST(_thread_start_new_thread),
+     METH_FASTCALL, start_new_doc},
+    _THREAD_START_JOINABLE_THREAD_METHODDEF
+    _THREAD_DAEMON_THREADS_ALLOWED_METHODDEF
+    _THREAD_ALLOCATE_LOCK_METHODDEF
+    {"allocate",                _thread_allocate_lock,
      METH_NOARGS, allocate_doc},
-    {"exit_thread",             thread_PyThread_exit_thread,
+    {"exit_thread",             _thread_exit,
      METH_NOARGS, exit_thread_doc},
-    {"exit",                    thread_PyThread_exit_thread,
-     METH_NOARGS, exit_doc},
-    {"interrupt_main",          thread_PyThread_interrupt_main,
-     METH_VARARGS, interrupt_doc},
-    {"get_ident",               thread_get_ident,
-     METH_NOARGS, get_ident_doc},
+    _THREAD_EXIT_METHODDEF
+    _THREAD_INTERRUPT_MAIN_METHODDEF
+    _THREAD_GET_IDENT_METHODDEF
 #ifdef PY_HAVE_THREAD_NATIVE_ID
-    {"get_native_id",           thread_get_native_id,
-     METH_NOARGS, get_native_id_doc},
+    _THREAD_GET_NATIVE_ID_METHODDEF
 #endif
-    {"_count",                  thread__count,
-     METH_NOARGS, _count_doc},
-    {"stack_size",              thread_stack_size,
-     METH_VARARGS, stack_size_doc},
-    {"_excepthook",             thread_excepthook,
-     METH_O, excepthook_doc},
-    {"_is_main_interpreter",    thread__is_main_interpreter,
-     METH_NOARGS, thread__is_main_interpreter_doc},
-    {"_shutdown",               thread_shutdown,
-     METH_NOARGS, shutdown_doc},
-    {"_make_thread_handle", thread__make_thread_handle,
-     METH_O, thread__make_thread_handle_doc},
-    {"_get_main_thread_ident", thread__get_main_thread_ident,
-     METH_NOARGS, thread__get_main_thread_ident_doc},
+    _THREAD__COUNT_METHODDEF
+    _THREAD_STACK_SIZE_METHODDEF
+    _THREAD__EXCEPTHOOK_METHODDEF
+    _THREAD__IS_MAIN_INTERPRETER_METHODDEF
+    _THREAD__SHUTDOWN_METHODDEF
+    _THREAD__MAKE_THREAD_HANDLE_METHODDEF
+    _THREAD__GET_MAIN_THREAD_IDENT_METHODDEF
     _THREAD_SET_NAME_METHODDEF
     _THREAD__GET_NAME_METHODDEF
     {NULL,                      NULL}           /* sentinel */
diff --git a/Modules/clinic/_threadmodule.c.h b/Modules/clinic/_threadmodule.c.h
index 926bea8e1e419a..090fdee8f6593e 100644
--- a/Modules/clinic/_threadmodule.c.h
+++ b/Modules/clinic/_threadmodule.c.h
@@ -6,7 +6,82 @@ preserve
 #  include "pycore_gc.h"          // PyGC_Head
 #  include "pycore_runtime.h"     // _Py_ID()
 #endif
-#include "pycore_modsupport.h"    // _PyArg_UnpackKeywords()
+#include "pycore_abstract.h"      // _PyNumber_Index()
+#include "pycore_modsupport.h"    // _PyArg_CheckPositional()
+
+static PyObject *
+_thread__ThreadHandle_ident_get_impl(PyObject *self);
+
+static PyObject *
+_thread__ThreadHandle_ident_get(PyObject *self, void *Py_UNUSED(context))
+{
+    return _thread__ThreadHandle_ident_get_impl(self);
+}
+
+PyDoc_STRVAR(_thread__ThreadHandle_join__doc__,
+"join($self, timeout=None, /)\n"
+"--\n"
+"\n");
+
+#define _THREAD__THREADHANDLE_JOIN_METHODDEF    \
+    {"join", _PyCFunction_CAST(_thread__ThreadHandle_join), METH_FASTCALL, 
_thread__ThreadHandle_join__doc__},
+
+static PyObject *
+_thread__ThreadHandle_join_impl(PyObject *self, PyObject *timeout_obj);
+
+static PyObject *
+_thread__ThreadHandle_join(PyObject *self, PyObject *const *args, Py_ssize_t 
nargs)
+{
+    PyObject *return_value = NULL;
+    PyObject *timeout_obj = Py_None;
+
+    if (!_PyArg_CheckPositional("join", nargs, 0, 1)) {
+        goto exit;
+    }
+    if (nargs < 1) {
+        goto skip_optional;
+    }
+    timeout_obj = args[0];
+skip_optional:
+    return_value = _thread__ThreadHandle_join_impl(self, timeout_obj);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_thread__ThreadHandle_is_done__doc__,
+"is_done($self, /)\n"
+"--\n"
+"\n");
+
+#define _THREAD__THREADHANDLE_IS_DONE_METHODDEF    \
+    {"is_done", (PyCFunction)_thread__ThreadHandle_is_done, METH_NOARGS, 
_thread__ThreadHandle_is_done__doc__},
+
+static PyObject *
+_thread__ThreadHandle_is_done_impl(PyObject *self);
+
+static PyObject *
+_thread__ThreadHandle_is_done(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    return _thread__ThreadHandle_is_done_impl(self);
+}
+
+PyDoc_STRVAR(_thread__ThreadHandle__set_done__doc__,
+"_set_done($self, /)\n"
+"--\n"
+"\n");
+
+#define _THREAD__THREADHANDLE__SET_DONE_METHODDEF    \
+    {"_set_done", (PyCFunction)_thread__ThreadHandle__set_done, METH_NOARGS, 
_thread__ThreadHandle__set_done__doc__},
+
+static PyObject *
+_thread__ThreadHandle__set_done_impl(PyObject *self);
+
+static PyObject *
+_thread__ThreadHandle__set_done(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    return _thread__ThreadHandle__set_done_impl(self);
+}
 
 PyDoc_STRVAR(_thread_lock_acquire__doc__,
 "acquire($self, /, blocking=True, timeout=-1)\n"
@@ -637,6 +712,457 @@ _thread_RLock__at_fork_reinit(PyObject *self, PyObject 
*Py_UNUSED(ignored))
 
 #endif /* defined(HAVE_FORK) */
 
+PyDoc_STRVAR(_thread_daemon_threads_allowed__doc__,
+"daemon_threads_allowed($module, /)\n"
+"--\n"
+"\n"
+"Return True if daemon threads are allowed in the current interpreter.\n"
+"\n"
+"Return False otherwise.");
+
+#define _THREAD_DAEMON_THREADS_ALLOWED_METHODDEF    \
+    {"daemon_threads_allowed", (PyCFunction)_thread_daemon_threads_allowed, 
METH_NOARGS, _thread_daemon_threads_allowed__doc__},
+
+static PyObject *
+_thread_daemon_threads_allowed_impl(PyObject *module);
+
+static PyObject *
+_thread_daemon_threads_allowed(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread_daemon_threads_allowed_impl(module);
+}
+
+PyDoc_STRVAR(_thread_start_new_thread__doc__,
+"start_new_thread($module, function, args, kwargs={}, /)\n"
+"--\n"
+"\n"
+"Start a new thread and return its identifier.\n"
+"\n"
+"The thread will call the function with positional arguments from the\n"
+"tuple args and keyword arguments taken from the optional dictionary\n"
+"kwargs.  The thread exits when the function returns; the return value\n"
+"is ignored.  The thread will also exit when the function raises an\n"
+"unhandled exception; a stack trace will be printed unless the exception\n"
+"is SystemExit.");
+
+#define _THREAD_START_NEW_THREAD_METHODDEF    \
+    {"start_new_thread", _PyCFunction_CAST(_thread_start_new_thread), 
METH_FASTCALL, _thread_start_new_thread__doc__},
+
+static PyObject *
+_thread_start_new_thread_impl(PyObject *module, PyObject *func,
+                              PyObject *args, PyObject *kwargs);
+
+static PyObject *
+_thread_start_new_thread(PyObject *module, PyObject *const *args, Py_ssize_t 
nargs)
+{
+    PyObject *return_value = NULL;
+    PyObject *func;
+    PyObject *__clinic_args;
+    PyObject *__clinic_kwargs = NULL;
+
+    if (!_PyArg_CheckPositional("start_new_thread", nargs, 2, 3)) {
+        goto exit;
+    }
+    func = args[0];
+    if (!PyTuple_Check(args[1])) {
+        _PyArg_BadArgument("start_new_thread", "argument 2", "tuple", args[1]);
+        goto exit;
+    }
+    __clinic_args = args[1];
+    if (nargs < 3) {
+        goto skip_optional;
+    }
+    if (!PyDict_Check(args[2])) {
+        _PyArg_BadArgument("start_new_thread", "argument 3", "dict", args[2]);
+        goto exit;
+    }
+    __clinic_kwargs = args[2];
+skip_optional:
+    return_value = _thread_start_new_thread_impl(module, func, __clinic_args, 
__clinic_kwargs);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_thread_start_joinable_thread__doc__,
+"start_joinable_thread($module, /, function, handle=None, daemon=True)\n"
+"--\n"
+"\n"
+"*For internal use only*: start a new thread.\n"
+"\n"
+"Like start_new_thread(), this starts a new thread calling the given\n"
+"function.  Unlike start_new_thread(), this returns a handle object with\n"
+"methods to join or detach the given thread.\n"
+"This function is not for third-party code, please use the `threading`\n"
+"module instead.  During finalization the runtime will not wait for the\n"
+"thread to exit if daemon is True.  If handle is provided it must be a\n"
+"newly created thread._ThreadHandle instance.");
+
+#define _THREAD_START_JOINABLE_THREAD_METHODDEF    \
+    {"start_joinable_thread", 
_PyCFunction_CAST(_thread_start_joinable_thread), METH_FASTCALL|METH_KEYWORDS, 
_thread_start_joinable_thread__doc__},
+
+static PyObject *
+_thread_start_joinable_thread_impl(PyObject *module, PyObject *func,
+                                   PyObject *hobj, int daemon);
+
+static PyObject *
+_thread_start_joinable_thread(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 3
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(function), &_Py_ID(handle), &_Py_ID(daemon), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"function", "handle", "daemon", 
NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "start_joinable_thread",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[3];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 
1;
+    PyObject *func;
+    PyObject *hobj = Py_None;
+    int daemon = 1;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 1, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    func = args[0];
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    if (args[1]) {
+        hobj = args[1];
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    daemon = PyObject_IsTrue(args[2]);
+    if (daemon < 0) {
+        goto exit;
+    }
+skip_optional_pos:
+    return_value = _thread_start_joinable_thread_impl(module, func, hobj, 
daemon);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_thread_exit__doc__,
+"exit($module, /)\n"
+"--\n"
+"\n"
+"Raise SystemExit.\n"
+"\n"
+"It will cause the current thread to exit silently unless the exception\n"
+"is caught.");
+
+#define _THREAD_EXIT_METHODDEF    \
+    {"exit", (PyCFunction)_thread_exit, METH_NOARGS, _thread_exit__doc__},
+
+static PyObject *
+_thread_exit_impl(PyObject *module);
+
+static PyObject *
+_thread_exit(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread_exit_impl(module);
+}
+
+PyDoc_STRVAR(_thread_interrupt_main__doc__,
+"interrupt_main($module, signum=signal.SIGINT, /)\n"
+"--\n"
+"\n"
+"Simulate the arrival of the given signal in the main thread.\n"
+"\n"
+"The corresponding signal handler will be executed.\n"
+"If *signum* is omitted, SIGINT is assumed.\n"
+"A subthread can use this function to interrupt the main thread.\n"
+"\n"
+"Note: the default signal handler for SIGINT raises\n"
+"``KeyboardInterrupt``.");
+
+#define _THREAD_INTERRUPT_MAIN_METHODDEF    \
+    {"interrupt_main", _PyCFunction_CAST(_thread_interrupt_main), 
METH_FASTCALL, _thread_interrupt_main__doc__},
+
+static PyObject *
+_thread_interrupt_main_impl(PyObject *module, int signum);
+
+static PyObject *
+_thread_interrupt_main(PyObject *module, PyObject *const *args, Py_ssize_t 
nargs)
+{
+    PyObject *return_value = NULL;
+    int signum = SIGINT;
+
+    if (!_PyArg_CheckPositional("interrupt_main", nargs, 0, 1)) {
+        goto exit;
+    }
+    if (nargs < 1) {
+        goto skip_optional;
+    }
+    signum = PyLong_AsInt(args[0]);
+    if (signum == -1 && PyErr_Occurred()) {
+        goto exit;
+    }
+skip_optional:
+    return_value = _thread_interrupt_main_impl(module, signum);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_thread_allocate_lock__doc__,
+"allocate_lock($module, /)\n"
+"--\n"
+"\n"
+"Create a new lock object.\n"
+"\n"
+"See help(type(threading.Lock())) for information about locks.");
+
+#define _THREAD_ALLOCATE_LOCK_METHODDEF    \
+    {"allocate_lock", (PyCFunction)_thread_allocate_lock, METH_NOARGS, 
_thread_allocate_lock__doc__},
+
+static PyObject *
+_thread_allocate_lock_impl(PyObject *module);
+
+static PyObject *
+_thread_allocate_lock(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread_allocate_lock_impl(module);
+}
+
+PyDoc_STRVAR(_thread_get_ident__doc__,
+"get_ident($module, /)\n"
+"--\n"
+"\n"
+"Return a non-zero integer that uniquely identifies the current thread.\n"
+"\n"
+"It is unique amongst other threads that exist simultaneously.\n"
+"This may be used to identify per-thread resources.\n"
+"Even though on some platforms threads identities may appear to be\n"
+"allocated consecutive numbers starting at 1, this behavior should not\n"
+"be relied upon, and the number should be seen purely as a magic cookie.\n"
+"A thread\'s identity may be reused for another thread after it exits.");
+
+#define _THREAD_GET_IDENT_METHODDEF    \
+    {"get_ident", (PyCFunction)_thread_get_ident, METH_NOARGS, 
_thread_get_ident__doc__},
+
+static PyObject *
+_thread_get_ident_impl(PyObject *module);
+
+static PyObject *
+_thread_get_ident(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread_get_ident_impl(module);
+}
+
+#if defined(PY_HAVE_THREAD_NATIVE_ID)
+
+PyDoc_STRVAR(_thread_get_native_id__doc__,
+"get_native_id($module, /)\n"
+"--\n"
+"\n"
+"Return a non-negative integer identifying the thread.\n"
+"\n"
+"It is reported by the OS (kernel).  This may be used to uniquely\n"
+"identify a particular thread within a system.");
+
+#define _THREAD_GET_NATIVE_ID_METHODDEF    \
+    {"get_native_id", (PyCFunction)_thread_get_native_id, METH_NOARGS, 
_thread_get_native_id__doc__},
+
+static PyObject *
+_thread_get_native_id_impl(PyObject *module);
+
+static PyObject *
+_thread_get_native_id(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread_get_native_id_impl(module);
+}
+
+#endif /* defined(PY_HAVE_THREAD_NATIVE_ID) */
+
+PyDoc_STRVAR(_thread__count__doc__,
+"_count($module, /)\n"
+"--\n"
+"\n"
+"Return the number of currently running Python threads.\n"
+"\n"
+"The main thread is excluded.  The returned number comprises all threads\n"
+"created through `start_new_thread()` as well as `threading.Thread`, and\n"
+"not yet finished.\n"
+"\n"
+"This function is meant for internal and specialized purposes only.\n"
+"In most applications `threading.enumerate()` should be used instead.");
+
+#define _THREAD__COUNT_METHODDEF    \
+    {"_count", (PyCFunction)_thread__count, METH_NOARGS, 
_thread__count__doc__},
+
+static PyObject *
+_thread__count_impl(PyObject *module);
+
+static PyObject *
+_thread__count(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread__count_impl(module);
+}
+
+PyDoc_STRVAR(_thread_stack_size__doc__,
+"stack_size($module, size=0, /)\n"
+"--\n"
+"\n"
+"Return the thread stack size used when creating new threads.\n"
+"\n"
+"The optional size argument specifies the stack size (in bytes) to be\n"
+"used for subsequently created threads, and must be 0 (use platform or\n"
+"configured default) or a positive integer value of at least 32,768 (32\n"
+"KiB).  If changing the thread stack size is unsupported, a ThreadError\n"
+"exception is raised.  If the specified size is invalid, a ValueError\n"
+"exception is raised, and the stack size is unmodified.  32 KiB\n"
+"currently is the minimum supported stack size value to guarantee\n"
+"sufficient stack space for the interpreter itself.\n"
+"\n"
+"Note that some systems may have particular restrictions on values for\n"
+"the stack size, such as requiring a minimum stack size larger than 32\n"
+"KiB or requiring allocation in multiples of the system memory page size\n"
+"- platform documentation should be referred to for more information\n"
+"(4 KiB pages are common; using multiples of 4096 for the stack size is\n"
+"the suggested approach in the absence of more specific information).");
+
+#define _THREAD_STACK_SIZE_METHODDEF    \
+    {"stack_size", _PyCFunction_CAST(_thread_stack_size), METH_FASTCALL, 
_thread_stack_size__doc__},
+
+static PyObject *
+_thread_stack_size_impl(PyObject *module, Py_ssize_t new_size);
+
+static PyObject *
+_thread_stack_size(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+    PyObject *return_value = NULL;
+    Py_ssize_t new_size = 0;
+
+    if (!_PyArg_CheckPositional("stack_size", nargs, 0, 1)) {
+        goto exit;
+    }
+    if (nargs < 1) {
+        goto skip_optional;
+    }
+    {
+        Py_ssize_t ival = -1;
+        PyObject *iobj = _PyNumber_Index(args[0]);
+        if (iobj != NULL) {
+            ival = PyLong_AsSsize_t(iobj);
+            Py_DECREF(iobj);
+        }
+        if (ival == -1 && PyErr_Occurred()) {
+            goto exit;
+        }
+        new_size = ival;
+    }
+skip_optional:
+    return_value = _thread_stack_size_impl(module, new_size);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_thread__excepthook__doc__,
+"_excepthook($module, args, /)\n"
+"--\n"
+"\n"
+"Handle uncaught Thread.run() exception.");
+
+#define _THREAD__EXCEPTHOOK_METHODDEF    \
+    {"_excepthook", (PyCFunction)_thread__excepthook, METH_O, 
_thread__excepthook__doc__},
+
+PyDoc_STRVAR(_thread__is_main_interpreter__doc__,
+"_is_main_interpreter($module, /)\n"
+"--\n"
+"\n"
+"Return True if the current interpreter is the main Python interpreter.");
+
+#define _THREAD__IS_MAIN_INTERPRETER_METHODDEF    \
+    {"_is_main_interpreter", (PyCFunction)_thread__is_main_interpreter, 
METH_NOARGS, _thread__is_main_interpreter__doc__},
+
+static PyObject *
+_thread__is_main_interpreter_impl(PyObject *module);
+
+static PyObject *
+_thread__is_main_interpreter(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread__is_main_interpreter_impl(module);
+}
+
+PyDoc_STRVAR(_thread__shutdown__doc__,
+"_shutdown($module, /)\n"
+"--\n"
+"\n"
+"Wait for all non-daemon threads (other than the calling thread) to stop.");
+
+#define _THREAD__SHUTDOWN_METHODDEF    \
+    {"_shutdown", (PyCFunction)_thread__shutdown, METH_NOARGS, 
_thread__shutdown__doc__},
+
+static PyObject *
+_thread__shutdown_impl(PyObject *module);
+
+static PyObject *
+_thread__shutdown(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread__shutdown_impl(module);
+}
+
+PyDoc_STRVAR(_thread__make_thread_handle__doc__,
+"_make_thread_handle($module, ident, /)\n"
+"--\n"
+"\n"
+"Internal only.\n"
+"\n"
+"Make a thread handle for threads not spawned by the _thread or\n"
+"threading module.");
+
+#define _THREAD__MAKE_THREAD_HANDLE_METHODDEF    \
+    {"_make_thread_handle", (PyCFunction)_thread__make_thread_handle, METH_O, 
_thread__make_thread_handle__doc__},
+
+PyDoc_STRVAR(_thread__get_main_thread_ident__doc__,
+"_get_main_thread_ident($module, /)\n"
+"--\n"
+"\n"
+"Internal only.\n"
+"\n"
+"Return a non-zero integer that uniquely identifies the main thread of\n"
+"the main interpreter.");
+
+#define _THREAD__GET_MAIN_THREAD_IDENT_METHODDEF    \
+    {"_get_main_thread_ident", (PyCFunction)_thread__get_main_thread_ident, 
METH_NOARGS, _thread__get_main_thread_ident__doc__},
+
+static PyObject *
+_thread__get_main_thread_ident_impl(PyObject *module);
+
+static PyObject *
+_thread__get_main_thread_ident(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _thread__get_main_thread_ident_impl(module);
+}
+
 #if (defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP) || 
defined(MS_WINDOWS))
 
 PyDoc_STRVAR(_thread__get_name__doc__,
@@ -733,6 +1259,10 @@ _thread_set_name(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyOb
     #define _THREAD_RLOCK__AT_FORK_REINIT_METHODDEF
 #endif /* !defined(_THREAD_RLOCK__AT_FORK_REINIT_METHODDEF) */
 
+#ifndef _THREAD_GET_NATIVE_ID_METHODDEF
+    #define _THREAD_GET_NATIVE_ID_METHODDEF
+#endif /* !defined(_THREAD_GET_NATIVE_ID_METHODDEF) */
+
 #ifndef _THREAD__GET_NAME_METHODDEF
     #define _THREAD__GET_NAME_METHODDEF
 #endif /* !defined(_THREAD__GET_NAME_METHODDEF) */
@@ -740,4 +1270,6 @@ _thread_set_name(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyOb
 #ifndef _THREAD_SET_NAME_METHODDEF
     #define _THREAD_SET_NAME_METHODDEF
 #endif /* !defined(_THREAD_SET_NAME_METHODDEF) */
-/*[clinic end generated code: output=0f1707cbafc0e8f2 input=a9049054013a1b77]*/
+#define _THREAD__THREADHANDLE_IDENT_GETSETDEF {"ident", 
(getter)_thread__ThreadHandle_ident_get, (setter)NULL, NULL},
+
+/*[clinic end generated code: output=3bfc76a318c6579d input=a9049054013a1b77]*/

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to