mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	gh-117657: Fix data races reported by TSAN on interp->threads.main (#118865)
				
					
				
			Use relaxed loads/stores when reading/writing to this field.
This commit is contained in:
		
							parent
							
								
									db5af7da09
								
							
						
					
					
						commit
						22d5185308
					
				
					 3 changed files with 21 additions and 13 deletions
				
			
		|  | @ -0,0 +1 @@ | ||||||
|  | Fix data races on the field that stores a pointer to the interpreter's main thread that occur in free-threaded builds. | ||||||
|  | @ -1038,6 +1038,17 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | static inline void | ||||||
|  | set_main_thread(PyInterpreterState *interp, PyThreadState *tstate) | ||||||
|  | { | ||||||
|  |     _Py_atomic_store_ptr_relaxed(&interp->threads.main, tstate); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline PyThreadState * | ||||||
|  | get_main_thread(PyInterpreterState *interp) | ||||||
|  | { | ||||||
|  |     return _Py_atomic_load_ptr_relaxed(&interp->threads.main); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| _PyInterpreterState_SetRunningMain(PyInterpreterState *interp) | _PyInterpreterState_SetRunningMain(PyInterpreterState *interp) | ||||||
|  | @ -1052,21 +1063,22 @@ _PyInterpreterState_SetRunningMain(PyInterpreterState *interp) | ||||||
|                         "current tstate has wrong interpreter"); |                         "current tstate has wrong interpreter"); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     interp->threads.main = tstate; |     set_main_thread(interp, tstate); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| _PyInterpreterState_SetNotRunningMain(PyInterpreterState *interp) | _PyInterpreterState_SetNotRunningMain(PyInterpreterState *interp) | ||||||
| { | { | ||||||
|     assert(interp->threads.main == current_fast_get()); |     assert(get_main_thread(interp) == current_fast_get()); | ||||||
|     interp->threads.main = NULL; |     set_main_thread(interp, NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| _PyInterpreterState_IsRunningMain(PyInterpreterState *interp) | _PyInterpreterState_IsRunningMain(PyInterpreterState *interp) | ||||||
| { | { | ||||||
|     if (interp->threads.main != NULL) { |     if (get_main_thread(interp) != NULL) { | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|     // Embedders might not know to call _PyInterpreterState_SetRunningMain(),
 |     // Embedders might not know to call _PyInterpreterState_SetRunningMain(),
 | ||||||
|  | @ -1082,18 +1094,15 @@ int | ||||||
| _PyThreadState_IsRunningMain(PyThreadState *tstate) | _PyThreadState_IsRunningMain(PyThreadState *tstate) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = tstate->interp; |     PyInterpreterState *interp = tstate->interp; | ||||||
|     if (interp->threads.main != NULL) { |  | ||||||
|         return tstate == interp->threads.main; |  | ||||||
|     } |  | ||||||
|     // See the note in _PyInterpreterState_IsRunningMain() about
 |     // See the note in _PyInterpreterState_IsRunningMain() about
 | ||||||
|     // possible false negatives here for embedders.
 |     // possible false negatives here for embedders.
 | ||||||
|     return 0; |     return get_main_thread(interp) == tstate; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| _PyInterpreterState_FailIfRunningMain(PyInterpreterState *interp) | _PyInterpreterState_FailIfRunningMain(PyInterpreterState *interp) | ||||||
| { | { | ||||||
|     if (interp->threads.main != NULL) { |     if (get_main_thread(interp) != NULL) { | ||||||
|         PyErr_SetString(PyExc_InterpreterError, |         PyErr_SetString(PyExc_InterpreterError, | ||||||
|                         "interpreter already running"); |                         "interpreter already running"); | ||||||
|         return -1; |         return -1; | ||||||
|  | @ -1105,8 +1114,8 @@ void | ||||||
| _PyInterpreterState_ReinitRunningMain(PyThreadState *tstate) | _PyInterpreterState_ReinitRunningMain(PyThreadState *tstate) | ||||||
| { | { | ||||||
|     PyInterpreterState *interp = tstate->interp; |     PyInterpreterState *interp = tstate->interp; | ||||||
|     if (interp->threads.main != tstate) { |     if (get_main_thread(interp) != tstate) { | ||||||
|         interp->threads.main = NULL; |         set_main_thread(interp, NULL); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -33,8 +33,6 @@ race_top:_mi_heap_delayed_free_partial | ||||||
| race_top:_PyEval_EvalFrameDefault | race_top:_PyEval_EvalFrameDefault | ||||||
| race_top:_PyImport_AcquireLock | race_top:_PyImport_AcquireLock | ||||||
| race_top:_PyImport_ReleaseLock | race_top:_PyImport_ReleaseLock | ||||||
| race_top:_PyInterpreterState_SetNotRunningMain |  | ||||||
| race_top:_PyInterpreterState_IsRunningMain |  | ||||||
| # https://gist.github.com/mpage/0a24eb2dd458441ededb498e9b0e5de8 | # https://gist.github.com/mpage/0a24eb2dd458441ededb498e9b0e5de8 | ||||||
| race_top:_PyParkingLot_Park | race_top:_PyParkingLot_Park | ||||||
| race_top:_PyType_HasFeature | race_top:_PyType_HasFeature | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 mpage
						mpage