mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	bpo-25658: Implement PEP 539 for Thread Specific Storage (TSS) API (GH-1362)
See PEP 539 for details. Highlights of changes: - Add Thread Specific Storage (TSS) API - Document the Thread Local Storage (TLS) API as deprecated - Update code that used TLS API to use TSS API
This commit is contained in:
		
							parent
							
								
									b8ab9d3fc8
								
							
						
					
					
						commit
						731e189014
					
				
					 18 changed files with 651 additions and 108 deletions
				
			
		|  | @ -46,7 +46,12 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) | |||
|     _PyEval_Initialize(&runtime->ceval); | ||||
| 
 | ||||
|     runtime->gilstate.check_enabled = 1; | ||||
|     runtime->gilstate.autoTLSkey = -1; | ||||
|     /* A TSS key must be initialized with Py_tss_NEEDS_INIT
 | ||||
|        in accordance with the specification. */ | ||||
|     { | ||||
|         Py_tss_t initial = Py_tss_NEEDS_INIT; | ||||
|         runtime->gilstate.autoTSSkey = initial; | ||||
|     } | ||||
| 
 | ||||
|     runtime->interpreters.mutex = PyThread_allocate_lock(); | ||||
|     if (runtime->interpreters.mutex == NULL) | ||||
|  | @ -485,9 +490,9 @@ PyThreadState_Delete(PyThreadState *tstate) | |||
|     if (tstate == GET_TSTATE()) | ||||
|         Py_FatalError("PyThreadState_Delete: tstate is still current"); | ||||
|     if (_PyRuntime.gilstate.autoInterpreterState && | ||||
|         PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == tstate) | ||||
|         PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == tstate) | ||||
|     { | ||||
|         PyThread_delete_key_value(_PyRuntime.gilstate.autoTLSkey); | ||||
|         PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, NULL); | ||||
|     } | ||||
|     tstate_delete_common(tstate); | ||||
| } | ||||
|  | @ -502,9 +507,9 @@ PyThreadState_DeleteCurrent() | |||
|             "PyThreadState_DeleteCurrent: no current tstate"); | ||||
|     tstate_delete_common(tstate); | ||||
|     if (_PyRuntime.gilstate.autoInterpreterState && | ||||
|         PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == tstate) | ||||
|         PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == tstate) | ||||
|     { | ||||
|         PyThread_delete_key_value(_PyRuntime.gilstate.autoTLSkey); | ||||
|         PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, NULL); | ||||
|     } | ||||
|     SET_TSTATE(NULL); | ||||
|     PyEval_ReleaseLock(); | ||||
|  | @ -761,11 +766,11 @@ void | |||
| _PyGILState_Init(PyInterpreterState *i, PyThreadState *t) | ||||
| { | ||||
|     assert(i && t); /* must init with valid states */ | ||||
|     _PyRuntime.gilstate.autoTLSkey = PyThread_create_key(); | ||||
|     if (_PyRuntime.gilstate.autoTLSkey == -1) | ||||
|         Py_FatalError("Could not allocate TLS entry"); | ||||
|     if (PyThread_tss_create(&_PyRuntime.gilstate.autoTSSkey) != 0) { | ||||
|         Py_FatalError("Could not allocate TSS entry"); | ||||
|     } | ||||
|     _PyRuntime.gilstate.autoInterpreterState = i; | ||||
|     assert(PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == NULL); | ||||
|     assert(PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == NULL); | ||||
|     assert(t->gilstate_counter == 0); | ||||
| 
 | ||||
|     _PyGILState_NoteThreadState(t); | ||||
|  | @ -780,14 +785,13 @@ _PyGILState_GetInterpreterStateUnsafe(void) | |||
| void | ||||
| _PyGILState_Fini(void) | ||||
| { | ||||
|     PyThread_delete_key(_PyRuntime.gilstate.autoTLSkey); | ||||
|     _PyRuntime.gilstate.autoTLSkey = -1; | ||||
|     PyThread_tss_delete(&_PyRuntime.gilstate.autoTSSkey); | ||||
|     _PyRuntime.gilstate.autoInterpreterState = NULL; | ||||
| } | ||||
| 
 | ||||
| /* Reset the TLS key - called by PyOS_AfterFork_Child().
 | ||||
| /* Reset the TSS key - called by PyOS_AfterFork_Child().
 | ||||
|  * This should not be necessary, but some - buggy - pthread implementations | ||||
|  * don't reset TLS upon fork(), see issue #10517. | ||||
|  * don't reset TSS upon fork(), see issue #10517. | ||||
|  */ | ||||
| void | ||||
| _PyGILState_Reinit(void) | ||||
|  | @ -796,15 +800,18 @@ _PyGILState_Reinit(void) | |||
|     if (_PyRuntime.interpreters.mutex == NULL) | ||||
|         Py_FatalError("Can't initialize threads for interpreter"); | ||||
|     PyThreadState *tstate = PyGILState_GetThisThreadState(); | ||||
|     PyThread_delete_key(_PyRuntime.gilstate.autoTLSkey); | ||||
|     if ((_PyRuntime.gilstate.autoTLSkey = PyThread_create_key()) == -1) | ||||
|         Py_FatalError("Could not allocate TLS entry"); | ||||
|     PyThread_tss_delete(&_PyRuntime.gilstate.autoTSSkey); | ||||
|     if (PyThread_tss_create(&_PyRuntime.gilstate.autoTSSkey) != 0) { | ||||
|         Py_FatalError("Could not allocate TSS entry"); | ||||
|     } | ||||
| 
 | ||||
|     /* If the thread had an associated auto thread state, reassociate it with
 | ||||
|      * the new key. */ | ||||
|     if (tstate && PyThread_set_key_value(_PyRuntime.gilstate.autoTLSkey, | ||||
|                                          (void *)tstate) < 0) | ||||
|         Py_FatalError("Couldn't create autoTLSkey mapping"); | ||||
|     if (tstate && | ||||
|         PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, (void *)tstate) != 0) | ||||
|     { | ||||
|         Py_FatalError("Couldn't create autoTSSkey mapping"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* When a thread state is created for a thread by some mechanism other than
 | ||||
|  | @ -815,13 +822,13 @@ _PyGILState_Reinit(void) | |||
| static void | ||||
| _PyGILState_NoteThreadState(PyThreadState* tstate) | ||||
| { | ||||
|     /* If autoTLSkey isn't initialized, this must be the very first
 | ||||
|     /* If autoTSSkey isn't initialized, this must be the very first
 | ||||
|        threadstate created in Py_Initialize().  Don't do anything for now | ||||
|        (we'll be back here when _PyGILState_Init is called). */ | ||||
|     if (!_PyRuntime.gilstate.autoInterpreterState) | ||||
|         return; | ||||
| 
 | ||||
|     /* Stick the thread state for this thread in thread local storage.
 | ||||
|     /* Stick the thread state for this thread in thread specific storage.
 | ||||
| 
 | ||||
|        The only situation where you can legitimately have more than one | ||||
|        thread state for an OS level thread is when there are multiple | ||||
|  | @ -833,12 +840,11 @@ _PyGILState_NoteThreadState(PyThreadState* tstate) | |||
|        The first thread state created for that given OS level thread will | ||||
|        "win", which seems reasonable behaviour. | ||||
|     */ | ||||
|     if (PyThread_get_key_value(_PyRuntime.gilstate.autoTLSkey) == NULL) { | ||||
|         if ((PyThread_set_key_value(_PyRuntime.gilstate.autoTLSkey, | ||||
|                                     (void *)tstate) | ||||
|              ) < 0) | ||||
|     if (PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey) == NULL) { | ||||
|         if ((PyThread_tss_set(&_PyRuntime.gilstate.autoTSSkey, (void *)tstate) | ||||
|              ) != 0) | ||||
|         { | ||||
|             Py_FatalError("Couldn't create autoTLSkey mapping"); | ||||
|             Py_FatalError("Couldn't create autoTSSkey mapping"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -852,8 +858,7 @@ PyGILState_GetThisThreadState(void) | |||
| { | ||||
|     if (_PyRuntime.gilstate.autoInterpreterState == NULL) | ||||
|         return NULL; | ||||
|     return (PyThreadState *)PyThread_get_key_value( | ||||
|                 _PyRuntime.gilstate.autoTLSkey); | ||||
|     return (PyThreadState *)PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey); | ||||
| } | ||||
| 
 | ||||
| int | ||||
|  | @ -864,8 +869,9 @@ PyGILState_Check(void) | |||
|     if (!_PyGILState_check_enabled) | ||||
|         return 1; | ||||
| 
 | ||||
|     if (_PyRuntime.gilstate.autoTLSkey == -1) | ||||
|     if (!PyThread_tss_is_created(&_PyRuntime.gilstate.autoTSSkey)) { | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     tstate = GET_TSTATE(); | ||||
|     if (tstate == NULL) | ||||
|  | @ -886,8 +892,7 @@ PyGILState_Ensure(void) | |||
|     */ | ||||
|     /* Py_Initialize() hasn't been called! */ | ||||
|     assert(_PyRuntime.gilstate.autoInterpreterState); | ||||
|     tcur = (PyThreadState *)PyThread_get_key_value( | ||||
|                 _PyRuntime.gilstate.autoTLSkey); | ||||
|     tcur = (PyThreadState *)PyThread_tss_get(&_PyRuntime.gilstate.autoTSSkey); | ||||
|     if (tcur == NULL) { | ||||
|         /* At startup, Python has no concrete GIL. If PyGILState_Ensure() is
 | ||||
|            called from a new thread for the first time, we need the create the | ||||
|  | @ -919,8 +924,8 @@ PyGILState_Ensure(void) | |||
| void | ||||
| PyGILState_Release(PyGILState_STATE oldstate) | ||||
| { | ||||
|     PyThreadState *tcur = (PyThreadState *)PyThread_get_key_value( | ||||
|                                 _PyRuntime.gilstate.autoTLSkey); | ||||
|     PyThreadState *tcur = (PyThreadState *)PyThread_tss_get( | ||||
|                                 &_PyRuntime.gilstate.autoTSSkey); | ||||
|     if (tcur == NULL) | ||||
|         Py_FatalError("auto-releasing thread-state, " | ||||
|                       "but no thread-state for this thread"); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Masayuki Yamamoto
						Masayuki Yamamoto