-
-
Notifications
You must be signed in to change notification settings - Fork 33.3k
gh-138004: Encode thread names on Solaris-based platforms as ASCII and fix main/worker threading test #138017
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 33 commits
d97417d
1db08a7
0606968
b556774
38a75d3
31731b1
83fe205
aadf7f3
612a0a4
1fa51f8
d24d0bb
95d289f
d7a47bf
1970a00
6395323
241e097
66c058b
f817412
3349464
ac3d3dd
1ab9ecd
d9ba9e8
d7025f5
3689044
246f880
407b1e9
dc43fc4
7aa256c
b4934a2
ae5ac4b
4fc368d
392aa5a
84daea4
d5e9399
105d4e6
c67e93d
508f24d
25085bf
cd26833
dc86a29
c9f554d
c0f672e
69796ff
15c8481
99f13ec
8fc613b
5e5effb
9690eee
338593c
e642264
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2241,6 +2241,7 @@ def __init__(self, a, *, b) -> None: | |
|
|
||
| with warnings.catch_warnings(record=True) as warnings_log: | ||
| CustomRLock(1, b=2) | ||
|
|
||
| self.assertEqual(warnings_log, []) | ||
|
|
||
| class EventTests(lock_tests.EventTests): | ||
|
|
@@ -2360,6 +2361,8 @@ def work(): | |
| thread = threading.Thread(target=work, name=name) | ||
| thread.start() | ||
| thread.join() | ||
| if not name.isascii() and not work_name: | ||
| self.skipTest(f"Platform does not support non-ASCII thread names: got empty name for {name!r}") | ||
|
||
| self.assertEqual(work_name, expected, | ||
| f"{len(work_name)=} and {len(expected)=}") | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| _thread.set_name() now retries with an ASCII fallback if pthread_setname_np() rejects UTF-8 names on some POSIX-compliant platforms. | ||
jadonduff marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,11 @@ | |
| #ifdef HAVE_SIGNAL_H | ||
| # include <signal.h> // SIGINT | ||
| #endif | ||
| #ifdef HAVE_PTHREAD_H | ||
| # include <pthread.h> | ||
| #endif | ||
| #include <errno.h> | ||
| #include <string.h> | ||
|
|
||
| // ThreadError is just an alias to PyExc_RuntimeError | ||
| #define ThreadError PyExc_RuntimeError | ||
|
|
@@ -2517,6 +2522,58 @@ of the main interpreter."); | |
| # include <pthread_np.h> | ||
| #endif | ||
|
|
||
| /* Helper: encode/truncate and call native API to set thread name. | ||
| * Return: | ||
| * 0 : success | ||
| * >0 : errno-style native error code (e.g. EINVAL) | ||
| * -1 : Python-level error (an exception has been set) | ||
| */ | ||
| static int | ||
| set_encoded_thread_name(PyObject *name_obj, const char *encoding) | ||
| { | ||
| PyObject *name_encoded = PyUnicode_AsEncodedString(name_obj, encoding, "replace"); | ||
| if (name_encoded == NULL) { | ||
| /* PyUnicode_AsEncodedString set an exception */ | ||
| return -1; | ||
| } | ||
|
|
||
| #ifdef _PYTHREAD_NAME_MAXLEN | ||
| if (PyBytes_GET_SIZE(name_encoded) > _PYTHREAD_NAME_MAXLEN) { | ||
| PyObject *truncated = PyBytes_FromStringAndSize( | ||
| PyBytes_AS_STRING(name_encoded), | ||
| _PYTHREAD_NAME_MAXLEN); | ||
| Py_DECREF(name_encoded); | ||
| if (truncated == NULL) { | ||
| /* PyBytes_FromStringAndSize set an exception */ | ||
| return -1; | ||
| } | ||
| name_encoded = truncated; | ||
| } | ||
| #endif | ||
|
|
||
| const char *name = PyBytes_AS_STRING(name_encoded); | ||
| int rc = 0; | ||
|
|
||
| #ifdef __APPLE__ | ||
| rc = pthread_setname_np(name); | ||
| #elif defined(__NetBSD__) | ||
| pthread_t thread = pthread_self(); | ||
| rc = pthread_setname_np(thread, "%s", (void *)name); | ||
| #elif defined(HAVE_PTHREAD_SETNAME_NP) | ||
| pthread_t thread = pthread_self(); | ||
| rc = pthread_setname_np(thread, name); | ||
| #elif defined(HAVE_PTHREAD_SET_NAME_NP) | ||
| pthread_t thread = pthread_self(); | ||
| pthread_set_name_np(thread, name); | ||
| rc = 0; /* that API returns void */ | ||
| #else | ||
| rc = 0; /* no-op if platform unsupported */ | ||
| #endif | ||
|
|
||
| Py_DECREF(name_encoded); | ||
| return rc; | ||
| } | ||
|
|
||
| #if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP) || defined(MS_WINDOWS) | ||
| /*[clinic input] | ||
| _thread._get_name | ||
|
|
@@ -2590,42 +2647,26 @@ _thread_set_name_impl(PyObject *module, PyObject *name_obj) | |
| 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 | ||
| if (PyBytes_GET_SIZE(name_encoded) > _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); | ||
| int rc = set_encoded_thread_name(name_obj, encoding); | ||
| /* Confirm a Python exception was set by the helper. | ||
| If not, convert to a runtime error (defensive). */ | ||
| if (rc == -1 && PyErr_Occurred()) { | ||
| return NULL; | ||
| } | ||
| #endif | ||
|
|
||
| const char *name = PyBytes_AS_STRING(name_encoded); | ||
| #ifdef __APPLE__ | ||
| int rc = pthread_setname_np(name); | ||
| #elif defined(__NetBSD__) | ||
| pthread_t thread = pthread_self(); | ||
| int rc = pthread_setname_np(thread, "%s", (void *)name); | ||
| #elif defined(HAVE_PTHREAD_SETNAME_NP) | ||
| pthread_t thread = pthread_self(); | ||
| int rc = pthread_setname_np(thread, name); | ||
| #else /* defined(HAVE_PTHREAD_SET_NAME_NP) */ | ||
| pthread_t thread = pthread_self(); | ||
| int rc = 0; /* pthread_set_name_np() returns void */ | ||
| pthread_set_name_np(thread, name); | ||
| #endif | ||
| Py_DECREF(name_encoded); | ||
| if (rc) { | ||
| /* If native API refused (EINVAL) and we didn't try ASCII, retry with ASCII. */ | ||
| if (rc == EINVAL && strcmp(encoding, "ascii") != 0) { | ||
| rc = set_encoded_thread_name(name_obj, "ascii"); | ||
| if (rc == -1 && PyErr_Occurred()) { | ||
| return NULL; | ||
| } | ||
| if (rc == 0) { | ||
| Py_RETURN_NONE; | ||
| } | ||
| /* fall through to raise errno below */ | ||
| } | ||
|
||
| errno = rc; | ||
| return PyErr_SetFromErrno(PyExc_OSError); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still an unrelated change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed