mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
gh-59705: Add _thread.set_name() function (#127338)
On Linux, threading.Thread now sets the thread name to the operating system. * configure now checks if pthread_getname_np() and pthread_setname_np() functions are available. * Add PYTHREAD_NAME_MAXLEN macro. * Add _thread._NAME_MAXLEN constant for test_threading. Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
12680ec5bd
commit
67b18a18b6
8 changed files with 342 additions and 2 deletions
|
@ -17,6 +17,8 @@
|
|||
# include <signal.h> // SIGINT
|
||||
#endif
|
||||
|
||||
#include "clinic/_threadmodule.c.h"
|
||||
|
||||
// ThreadError is just an alias to PyExc_RuntimeError
|
||||
#define ThreadError PyExc_RuntimeError
|
||||
|
||||
|
@ -44,6 +46,13 @@ get_thread_state(PyObject *module)
|
|||
return (thread_module_state *)state;
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
module _thread
|
||||
[clinic start generated code]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=be8dbe5cc4b16df7]*/
|
||||
|
||||
|
||||
// _ThreadHandle type
|
||||
|
||||
// Handles state transitions according to the following diagram:
|
||||
|
@ -2354,6 +2363,96 @@ PyDoc_STRVAR(thread__get_main_thread_ident_doc,
|
|||
Internal only. Return a non-zero integer that uniquely identifies the main thread\n\
|
||||
of the main interpreter.");
|
||||
|
||||
|
||||
#ifdef HAVE_PTHREAD_GETNAME_NP
|
||||
/*[clinic input]
|
||||
_thread._get_name
|
||||
|
||||
Get the name of the current thread.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_thread__get_name_impl(PyObject *module)
|
||||
/*[clinic end generated code: output=20026e7ee3da3dd7 input=35cec676833d04c8]*/
|
||||
{
|
||||
// Linux and macOS are limited to respectively 16 and 64 bytes
|
||||
char name[100];
|
||||
pthread_t thread = pthread_self();
|
||||
int rc = pthread_getname_np(thread, name, Py_ARRAY_LENGTH(name));
|
||||
if (rc) {
|
||||
errno = rc;
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
|
||||
#ifdef __sun
|
||||
return PyUnicode_DecodeUTF8(name, strlen(name), "surrogateescape");
|
||||
#else
|
||||
return PyUnicode_DecodeFSDefault(name);
|
||||
#endif
|
||||
}
|
||||
#endif // HAVE_PTHREAD_GETNAME_NP
|
||||
|
||||
|
||||
#ifdef HAVE_PTHREAD_SETNAME_NP
|
||||
/*[clinic input]
|
||||
_thread.set_name
|
||||
|
||||
name as name_obj: unicode
|
||||
|
||||
Set the name of the current thread.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_thread_set_name_impl(PyObject *module, PyObject *name_obj)
|
||||
/*[clinic end generated code: output=402b0c68e0c0daed input=7e7acd98261be82f]*/
|
||||
{
|
||||
#ifdef __sun
|
||||
// Solaris always uses UTF-8
|
||||
const char *encoding = "utf-8";
|
||||
#else
|
||||
// Encode the thread name to the filesystem encoding using the "replace"
|
||||
// error handler
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
const char *encoding = interp->unicode.fs_codec.encoding;
|
||||
#endif
|
||||
PyObject *name_encoded;
|
||||
name_encoded = PyUnicode_AsEncodedString(name_obj, encoding, "replace");
|
||||
if (name_encoded == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef PYTHREAD_NAME_MAXLEN
|
||||
// Truncate to PYTHREAD_NAME_MAXLEN bytes + the NUL byte if needed
|
||||
size_t len = PyBytes_GET_SIZE(name_encoded);
|
||||
if (len > PYTHREAD_NAME_MAXLEN) {
|
||||
PyObject *truncated;
|
||||
truncated = PyBytes_FromStringAndSize(PyBytes_AS_STRING(name_encoded),
|
||||
PYTHREAD_NAME_MAXLEN);
|
||||
if (truncated == NULL) {
|
||||
Py_DECREF(name_encoded);
|
||||
return NULL;
|
||||
}
|
||||
Py_SETREF(name_encoded, truncated);
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *name = PyBytes_AS_STRING(name_encoded);
|
||||
#ifdef __APPLE__
|
||||
int rc = pthread_setname_np(name);
|
||||
#else
|
||||
pthread_t thread = pthread_self();
|
||||
int rc = pthread_setname_np(thread, name);
|
||||
#endif
|
||||
Py_DECREF(name_encoded);
|
||||
if (rc) {
|
||||
errno = rc;
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif // HAVE_PTHREAD_SETNAME_NP
|
||||
|
||||
|
||||
static PyMethodDef thread_methods[] = {
|
||||
{"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
|
||||
METH_VARARGS, start_new_thread_doc},
|
||||
|
@ -2393,6 +2492,8 @@ static PyMethodDef thread_methods[] = {
|
|||
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_SET_NAME_METHODDEF
|
||||
_THREAD__GET_NAME_METHODDEF
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
@ -2484,6 +2585,13 @@ thread_module_exec(PyObject *module)
|
|||
|
||||
llist_init(&state->shutdown_handles);
|
||||
|
||||
#ifdef PYTHREAD_NAME_MAXLEN
|
||||
if (PyModule_AddIntConstant(module, "_NAME_MAXLEN",
|
||||
PYTHREAD_NAME_MAXLEN) < 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue