From 13264ca8fc70dccda2bfa617fac3033042624e25 Mon Sep 17 00:00:00 2001 From: Matt Page Date: Thu, 25 Apr 2024 16:06:46 -0700 Subject: [PATCH 1/2] Disable the function/code cache in free-threaded builds This is only used by the specializing interpreter and the tier 2 optimizer, both of which are disabled in free-threaded builds. [Sample race](https://gist.github.com/mpage/d05a1c4616eedc9337f3f335e6485f91) that is fixed. --- Include/internal/pycore_function.h | 7 +++++++ Objects/codeobject.c | 6 ++++++ Objects/funcobject.c | 10 ++++++++++ Tools/tsan/suppressions_free_threading.txt | 1 - 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 24fbb3ddbee602..5b21eb96a3c45f 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -4,6 +4,8 @@ extern "C" { #endif +#include "pycore_lock.h" + #ifndef Py_BUILD_CORE # error "this header requires Py_BUILD_CORE define" #endif @@ -24,6 +26,11 @@ struct _func_version_cache_item { }; struct _py_func_state { + #ifdef Py_GIL_DISABLED + // Protects next_version + PyMutex mutex; + #endif + uint32_t next_version; // Borrowed references to function and code objects whose // func_version % FUNC_VERSION_CACHE_SIZE diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 014632962bfcf3..14a12590361902 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -416,10 +416,16 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) co->co_ncellvars = ncellvars; co->co_nfreevars = nfreevars; PyInterpreterState *interp = _PyInterpreterState_GET(); +#ifdef Py_GIL_DISABLED + PyMutex_Lock(&interp->func_state.mutex); +#endif co->co_version = interp->func_state.next_version; if (interp->func_state.next_version != 0) { interp->func_state.next_version++; } +#ifdef Py_GIL_DISABLED + PyMutex_Unlock(&interp->func_state.mutex); +#endif co->_co_monitoring = NULL; co->_co_instrumentation_version = 0; /* not set */ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 276b3db2970371..8a30213888ef87 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -287,6 +287,7 @@ functions is running. void _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version) { +#ifndef Py_GIL_DISABLED PyInterpreterState *interp = _PyInterpreterState_GET(); if (func->func_version != 0) { struct _func_version_cache_item *slot = @@ -297,7 +298,9 @@ _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version) // Leave slot->code alone, there may be use for it. } } +#endif func->func_version = version; +#ifndef Py_GIL_DISABLED if (version != 0) { struct _func_version_cache_item *slot = interp->func_state.func_version_cache @@ -305,11 +308,13 @@ _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version) slot->func = func; slot->code = func->func_code; } +#endif } void _PyFunction_ClearCodeByVersion(uint32_t version) { +#ifndef Py_GIL_DISABLED PyInterpreterState *interp = _PyInterpreterState_GET(); struct _func_version_cache_item *slot = interp->func_state.func_version_cache @@ -322,11 +327,15 @@ _PyFunction_ClearCodeByVersion(uint32_t version) slot->func = NULL; } } +#endif } PyFunctionObject * _PyFunction_LookupByVersion(uint32_t version, PyObject **p_code) { +#ifdef Py_GIL_DISABLED + return NULL; +#else PyInterpreterState *interp = _PyInterpreterState_GET(); struct _func_version_cache_item *slot = interp->func_state.func_version_cache @@ -346,6 +355,7 @@ _PyFunction_LookupByVersion(uint32_t version, PyObject **p_code) return slot->func; } return NULL; +#endif } uint32_t diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index e4ca32bebc5a22..06874d4982215c 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -16,7 +16,6 @@ race:_in_weak_set race:_mi_heap_delayed_free_partial race:_Py_IsOwnedByCurrentThread race:_PyEval_EvalFrameDefault -race:_PyFunction_SetVersion race:_PyImport_AcquireLock race:_PyImport_ReleaseLock race:_PyInterpreterState_SetNotRunningMain From 912fed24d8c3d2c81466ea27cd41ae6ce0e7ac83 Mon Sep 17 00:00:00 2001 From: Matt Page Date: Thu, 25 Apr 2024 18:24:24 -0700 Subject: [PATCH 2/2] Fix indentation --- Include/internal/pycore_function.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 5b21eb96a3c45f..6d44e933e8a8cb 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -26,10 +26,10 @@ struct _func_version_cache_item { }; struct _py_func_state { - #ifdef Py_GIL_DISABLED +#ifdef Py_GIL_DISABLED // Protects next_version PyMutex mutex; - #endif +#endif uint32_t next_version; // Borrowed references to function and code objects whose