diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 19faceebf1d8ee..27d45b07c32658 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -33,6 +33,12 @@ struct _Py_unicode_runtime_ids { }; struct _Py_unicode_runtime_state { + struct { + PyThread_type_lock lock; + PyThreadState *tstate; + /* The actual interned dict is at + _PyRuntime.cached_objects.interned_strings. */ + } interned; struct _Py_unicode_runtime_ids ids; }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index b9fb53147b9b51..2561ced241d0c3 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14533,13 +14533,12 @@ _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) return _PyStatus_OK(); } - // Initialize the global interned dict + /* Initialize the global interned dict. */ PyObject *interned = PyDict_New(); if (interned == NULL) { PyErr_Clear(); return _PyStatus_ERR("failed to create interned dict"); } - set_interned_dict(interned); /* Intern statically allocated string identifiers and deepfreeze strings. @@ -14585,6 +14584,63 @@ _PyUnicode_InitTypes(PyInterpreterState *interp) } +static PyThreadState * +get_interned_tstate(void) +{ + PyThreadState *tstate = _PyRuntime.unicode_state.interned.tstate; + if (tstate == NULL) { + PyInterpreterState *main_interp = _PyInterpreterState_Main(); + /* We do not "bind" the thread state here. */ + tstate = _PyThreadState_New(main_interp); + if (tstate == NULL) { + PyErr_Clear(); + return NULL; + } + } + return tstate; +} + +static void +clear_interned_tstate(void) +{ + PyThreadState *tstate = _PyRuntime.unicode_state.interned.tstate; + if (tstate != NULL) { + _PyRuntime.unicode_state.interned.tstate = NULL; + PyThreadState_Clear(tstate); + PyThreadState_Delete(tstate); + } +} + +static inline PyObject * +store_interned(PyObject *obj) +{ + PyObject *interned = get_interned_dict(); + assert(interned != NULL); + + /* Swap to the main interpreter, if necessary. */ + PyThreadState *oldts = NULL; + if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) { + PyThreadState *main_tstate = get_interned_tstate(); + if (main_tstate == NULL) { + return NULL; + } + oldts = PyThreadState_Swap(main_tstate); + assert(oldts != NULL); + } + + PyObject *t = PyDict_SetDefault(interned, obj, obj); + if (t == NULL) { + PyErr_Clear(); + } + + /* Swap back. */ + if (oldts != NULL) { + PyThreadState_Swap(oldts); + } + + return t; +} + void PyUnicode_InternInPlace(PyObject **p) { @@ -14608,20 +14664,20 @@ PyUnicode_InternInPlace(PyObject **p) return; } - PyObject *interned = get_interned_dict(); - assert(interned != NULL); - - PyObject *t = PyDict_SetDefault(interned, s, s); - if (t == NULL) { - PyErr_Clear(); - return; - } - + PyThread_acquire_lock(_PyRuntime.unicode_state.interned.lock, WAIT_LOCK); + PyObject *t = store_interned(s); + PyThread_release_lock(_PyRuntime.unicode_state.interned.lock); if (t != s) { - Py_SETREF(*p, Py_NewRef(t)); + if (t != NULL) { + Py_SETREF(*p, Py_NewRef(t)); + } return; } + /* Immortalize the object. */ + // XXX Uncomment this once the PEP 683 implementation has landed. + //_Py_SetImmortal(s); + /* The two references in interned dict (key and value) are not counted by refcnt. unicode_dealloc() and _PyUnicode_ClearInterned() take care of this. */ @@ -14696,6 +14752,8 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) PyDict_Clear(interned); Py_DECREF(interned); set_interned_dict(NULL); + + clear_interned_tstate(); } diff --git a/Python/pystate.c b/Python/pystate.c index 60adb54685ce68..82826a4d512e91 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -356,7 +356,8 @@ _Py_COMP_DIAG_POP static int alloc_for_runtime(PyThread_type_lock *plock1, PyThread_type_lock *plock2, - PyThread_type_lock *plock3, PyThread_type_lock *plock4) + PyThread_type_lock *plock3, PyThread_type_lock *plock4, + PyThread_type_lock *plock5) { /* Force default allocator, since _PyRuntimeState_Fini() must use the same allocator than this function. */ @@ -389,12 +390,22 @@ alloc_for_runtime(PyThread_type_lock *plock1, PyThread_type_lock *plock2, return -1; } + PyThread_type_lock lock5 = PyThread_allocate_lock(); + if (lock4 == NULL) { + PyThread_free_lock(lock1); + PyThread_free_lock(lock2); + PyThread_free_lock(lock3); + PyThread_free_lock(lock4); + return -1; + } + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); *plock1 = lock1; *plock2 = lock2; *plock3 = lock3; *plock4 = lock4; + *plock5 = lock5; return 0; } @@ -404,6 +415,7 @@ init_runtime(_PyRuntimeState *runtime, _Py_AuditHookEntry *audit_hook_head, Py_ssize_t unicode_next_index, PyThread_type_lock unicode_ids_mutex, + PyThread_type_lock interned_mutex, PyThread_type_lock interpreters_mutex, PyThread_type_lock xidregistry_mutex, PyThread_type_lock getargs_mutex) @@ -435,6 +447,7 @@ init_runtime(_PyRuntimeState *runtime, runtime->unicode_state.ids.next_index = unicode_next_index; runtime->unicode_state.ids.lock = unicode_ids_mutex; + runtime->unicode_state.interned.lock = interned_mutex; runtime->_initialized = 1; } @@ -452,8 +465,8 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) // is called multiple times. Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index; - PyThread_type_lock lock1, lock2, lock3, lock4; - if (alloc_for_runtime(&lock1, &lock2, &lock3, &lock4) != 0) { + PyThread_type_lock lock1, lock2, lock3, lock4, lock5; + if (alloc_for_runtime(&lock1, &lock2, &lock3, &lock4, &lock5) != 0) { return _PyStatus_NO_MEMORY(); } @@ -474,7 +487,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) } init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head, - unicode_next_index, lock1, lock2, lock3, lock4); + unicode_next_index, lock1, lock2, lock3, lock4, lock5); return _PyStatus_OK(); } @@ -530,6 +543,7 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) int reinit_interp = _PyThread_at_fork_reinit(&runtime->interpreters.mutex); int reinit_xidregistry = _PyThread_at_fork_reinit(&runtime->xidregistry.mutex); int reinit_unicode_ids = _PyThread_at_fork_reinit(&runtime->unicode_state.ids.lock); + int reinit_interned = _PyThread_at_fork_reinit(&runtime->unicode_state.interned.lock); int reinit_getargs = _PyThread_at_fork_reinit(&runtime->getargs.mutex); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); @@ -542,6 +556,7 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) || reinit_main_id < 0 || reinit_xidregistry < 0 || reinit_unicode_ids < 0 + || reinit_interned < 0 || reinit_getargs < 0) { return _PyStatus_ERR("Failed to reinitialize runtime locks"); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy