diff --git a/Include/pyport.h b/Include/pyport.h index 62db8d07701d1d2..e77b39026a59c1f 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -509,23 +509,18 @@ extern "C" { #endif #ifdef WITH_THREAD -# ifdef Py_BUILD_CORE -# ifdef HAVE_THREAD_LOCAL -# error "HAVE_THREAD_LOCAL is already defined" -# endif -# define HAVE_THREAD_LOCAL 1 -# ifdef thread_local -# define _Py_thread_local thread_local -# elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) -# define _Py_thread_local _Thread_local -# elif defined(_MSC_VER) /* AKA NT_THREADS */ -# define _Py_thread_local __declspec(thread) -# elif defined(__GNUC__) /* includes clang */ -# define _Py_thread_local __thread -# else - // fall back to the PyThread_tss_*() API, or ignore. -# undef HAVE_THREAD_LOCAL -# endif +// HAVE_THREAD_LOCAL is just defined here for compatibility's sake +# define HAVE_THREAD_LOCAL 1 +# ifdef thread_local +# define _Py_thread_local thread_local +# elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) +# define _Py_thread_local _Thread_local +# elif defined(_MSC_VER) /* AKA NT_THREADS */ +# define _Py_thread_local __declspec(thread) +# elif defined(__GNUC__) /* includes clang */ +# define _Py_thread_local __thread +# else +# error "no supported thread-local variable storage classifier" # endif #endif diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index b71a36ec2f7aab4..95121debbbfa74e 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -3160,6 +3160,7 @@ def test_check_state_first(self): # Also, we test with a single-phase module that has global state, # which is shared by all interpreters. + @no_rerun(reason="module state is not cleared (see gh-140657)") @requires_subinterpreters def test_basic_multiple_interpreters_main_no_reset(self): # without resetting; already loaded in main interpreter diff --git a/Python/import.c b/Python/import.c index 45206b467938462..d4b574a8828dc5d 100644 --- a/Python/import.c +++ b/Python/import.c @@ -782,18 +782,13 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) substitute this (if the name actually matches). */ -#ifdef HAVE_THREAD_LOCAL _Py_thread_local const char *pkgcontext = NULL; # undef PKGCONTEXT # define PKGCONTEXT pkgcontext -#endif const char * _PyImport_ResolveNameWithPackageContext(const char *name) { -#ifndef HAVE_THREAD_LOCAL - PyMutex_Lock(&EXTENSIONS.mutex); -#endif if (PKGCONTEXT != NULL) { const char *p = strrchr(PKGCONTEXT, '.'); if (p != NULL && strcmp(name, p+1) == 0) { @@ -801,23 +796,14 @@ _PyImport_ResolveNameWithPackageContext(const char *name) PKGCONTEXT = NULL; } } -#ifndef HAVE_THREAD_LOCAL - PyMutex_Unlock(&EXTENSIONS.mutex); -#endif return name; } const char * _PyImport_SwapPackageContext(const char *newcontext) { -#ifndef HAVE_THREAD_LOCAL - PyMutex_Lock(&EXTENSIONS.mutex); -#endif const char *oldcontext = PKGCONTEXT; PKGCONTEXT = newcontext; -#ifndef HAVE_THREAD_LOCAL - PyMutex_Unlock(&EXTENSIONS.mutex); -#endif return oldcontext; } diff --git a/Python/pystate.c b/Python/pystate.c index 2141e842a37d2f3..24681536797f94e 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -67,9 +67,6 @@ to avoid the expense of doing their own locking). For each of these functions, the GIL must be held by the current thread. */ -#ifndef HAVE_THREAD_LOCAL -# error "no supported thread-local variable storage classifier" -#endif /* The attached thread state for the current thread. */ _Py_thread_local PyThreadState *_Py_tss_tstate = NULL; diff --git a/Python/traceback.c b/Python/traceback.c index 2639d50aa667177..ef67368550aafb4 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -980,6 +980,52 @@ _Py_DumpASCII(int fd, PyObject *text) } } + +#ifdef MS_WINDOWS +static void +_Py_DumpWideString(int fd, wchar_t *str) +{ + Py_ssize_t size = wcslen(str); + int truncated; + if (MAX_STRING_LENGTH < size) { + size = MAX_STRING_LENGTH; + truncated = 1; + } + else { + truncated = 0; + } + + for (Py_ssize_t i=0; i < size; i++) { + Py_UCS4 ch = str[i]; + if (' ' <= ch && ch <= 126) { + /* printable ASCII character */ + dump_char(fd, (char)ch); + } + else if (ch <= 0xff) { + PUTS(fd, "\\x"); + _Py_DumpHexadecimal(fd, ch, 2); + } + else if (Py_UNICODE_IS_HIGH_SURROGATE(ch) + && Py_UNICODE_IS_LOW_SURROGATE(str[i+1])) { + ch = Py_UNICODE_JOIN_SURROGATES(ch, str[i+1]); + i++; // Skip the low surrogate character + PUTS(fd, "\\U"); + _Py_DumpHexadecimal(fd, ch, 8); + } + else { + Py_BUILD_ASSERT(sizeof(wchar_t) == 2); + PUTS(fd, "\\u"); + _Py_DumpHexadecimal(fd, ch, 4); + } + } + + if (truncated) { + PUTS(fd, "..."); + } +} +#endif + + /* Write a frame into the file fd: "File "xxx", line xxx in xxx". This function is signal safe. */ @@ -1149,20 +1195,15 @@ write_thread_name(int fd, PyThreadState *tstate) return; } - wchar_t *wname; - HRESULT hr = pGetThreadDescription(thread, &wname); + wchar_t *name; + HRESULT hr = pGetThreadDescription(thread, &name); if (!FAILED(hr)) { - char *name = _Py_EncodeLocaleRaw(wname, NULL); - if (name != NULL) { - size_t len = strlen(name); - if (len) { - PUTS(fd, " ["); - (void)_Py_write_noraise(fd, name, len); - PUTS(fd, "]"); - } - PyMem_RawFree(name); + if (name[0] != 0) { + PUTS(fd, " ["); + _Py_DumpWideString(fd, name); + PUTS(fd, "]"); } - LocalFree(wname); + LocalFree(name); } CloseHandle(thread); #endif