diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index ed3ee090ae53db..44fb5a0859fa2c 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -191,6 +191,12 @@ struct _ts { PyObject *previous_executor; uint64_t dict_global_version; + + // For Python/fileutils.c + int fileutils_ioctl_works; + int fileutils_skiproot_initialized; + int fileutils_combineex_initialized; + int fileutils__Py_open_cloexec_works; }; #ifdef Py_DEBUG diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index b5129ffcbffdcf..c4beeeef74e674 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -203,10 +203,6 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *) self; } -#ifdef O_CLOEXEC -extern int _Py_open_cloexec_works; -#endif - /*[clinic input] _io.FileIO.__init__ file as nameobj: object @@ -247,7 +243,8 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, int fd = -1; int fd_is_own = 0; #ifdef O_CLOEXEC - int *atomic_flag_works = &_Py_open_cloexec_works; + PyThreadState *tstate = PyThreadState_Get(); + int *atomic_flag_works = &tstate->fileutils__Py_open_cloexec_works; #elif !defined(MS_WINDOWS) int *atomic_flag_works = NULL; #endif diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a8fd5c494769b5..a6a6e114d36fdc 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10969,10 +10969,6 @@ os_tcsetpgrp_impl(PyObject *module, int fd, pid_t pgid) /* Functions acting on file descriptors */ -#ifdef O_CLOEXEC -extern int _Py_open_cloexec_works; -#endif - /*[clinic input] os.open -> int @@ -11003,7 +10999,8 @@ os_open_impl(PyObject *module, path_t *path, int flags, int mode, int dir_fd) #endif #ifdef O_CLOEXEC - int *atomic_flag_works = &_Py_open_cloexec_works; + PyThreadState *tstate = PyThreadState_Get(); + int *atomic_flag_works = &tstate->fileutils__Py_open_cloexec_works; #elif !defined(MS_WINDOWS) int *atomic_flag_works = NULL; #endif diff --git a/Python/fileutils.c b/Python/fileutils.c index e6a5391a3a28b5..2d430f39bdcaa8 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -37,18 +37,6 @@ extern int winerror_to_errno(int); # include // fcntl(F_GETFD) #endif -#ifdef O_CLOEXEC -/* Does open() support the O_CLOEXEC flag? Possible values: - - -1: unknown - 0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23 - 1: open() supports O_CLOEXEC flag, close-on-exec is set - - The flag is used by _Py_open(), _Py_open_noraise(), io.FileIO - and os.open(). */ -int _Py_open_cloexec_works = -1; -#endif - // The value must be the same in unicodeobject.c. #define MAX_UNICODE 0x10ffff @@ -1455,7 +1443,7 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) DWORD flags; #else #if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX) - static int ioctl_works = -1; + PyThreadState *tstate = PyThreadState_Get(); int request; int err; #endif @@ -1502,7 +1490,7 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) #else #if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX) - if (ioctl_works != 0 && raise != 0) { + if (tstate->fileutils_ioctl_works != 0 && raise != 0) { /* fast-path: ioctl() only requires one syscall */ /* caveat: raise=0 is an indicator that we must be async-signal-safe * thus avoid using ioctl() so we skip the fast-path. */ @@ -1512,7 +1500,7 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) request = FIOCLEX; err = ioctl(fd, request, NULL); if (!err) { - ioctl_works = 1; + tstate->fileutils_ioctl_works = 1; return 0; } @@ -1539,7 +1527,7 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) with EACCES. While FIOCLEX is safe operation it may be unavailable because ioctl was denied altogether. This can be the case on Android. */ - ioctl_works = 0; + tstate->fileutils_ioctl_works = 0; } /* fallback to fcntl() if ioctl() does not work */ } @@ -1626,7 +1614,16 @@ _Py_open_impl(const char *pathname, int flags, int gil_held) #ifdef MS_WINDOWS flags |= O_NOINHERIT; #elif defined(O_CLOEXEC) - atomic_flag_works = &_Py_open_cloexec_works; + PyThreadState *tstate = PyThreadState_Get(); + /* Does open() support the O_CLOEXEC flag? Possible values: + + -1: unknown + 0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23 + 1: open() supports O_CLOEXEC flag, close-on-exec is set + + The flag is used by _Py_open(), _Py_open_noraise(), io.FileIO + and os.open(). */ + atomic_flag_works = &tstate->fileutils__Py_open_cloexec_works; flags |= O_CLOEXEC; #else atomic_flag_works = NULL; @@ -2236,12 +2233,12 @@ _Py_abspath(const wchar_t *path, wchar_t **abspath_p) HRESULT PathCchSkipRoot(const wchar_t *path, const wchar_t **rootEnd) { - static int initialized = 0; + PyThreadState *tstate = PyThreadState_Get(); typedef HRESULT(__stdcall *PPathCchSkipRoot) (PCWSTR pszPath, PCWSTR *ppszRootEnd); static PPathCchSkipRoot _PathCchSkipRoot; - if (initialized == 0) { + if (tstate->fileutils_skiproot_initialized == 0) { HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (pathapi) { @@ -2251,7 +2248,7 @@ PathCchSkipRoot(const wchar_t *path, const wchar_t **rootEnd) else { _PathCchSkipRoot = NULL; } - initialized = 1; + tstate->fileutils_skiproot_initialized = 1; } if (!_PathCchSkipRoot) { @@ -2265,7 +2262,7 @@ static HRESULT PathCchCombineEx(wchar_t *buffer, size_t bufsize, const wchar_t *dirname, const wchar_t *relfile, unsigned long flags) { - static int initialized = 0; + PyThreadState *tstate = PyThreadState_Get(); typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, @@ -2273,7 +2270,7 @@ PathCchCombineEx(wchar_t *buffer, size_t bufsize, const wchar_t *dirname, unsigned long dwFlags); static PPathCchCombineEx _PathCchCombineEx; - if (initialized == 0) { + if (tstate->fileutils_combineex_initialized == 0) { HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (pathapi) { @@ -2283,7 +2280,7 @@ PathCchCombineEx(wchar_t *buffer, size_t bufsize, const wchar_t *dirname, else { _PathCchCombineEx = NULL; } - initialized = 1; + tstate->fileutils_combineex_initialized = 1; } if (!_PathCchCombineEx) { diff --git a/Python/pystate.c b/Python/pystate.c index e1a95907b57d20..65fb385068d401 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1498,6 +1498,10 @@ init_threadstate(_PyThreadStateImpl *_tstate, tstate->what_event = -1; tstate->previous_executor = NULL; tstate->dict_global_version = 0; + tstate->fileutils_ioctl_works = -1; + tstate->fileutils_skiproot_initialized = 0; + tstate->fileutils_combineex_initialized = 0; + tstate->fileutils__Py_open_cloexec_works = -1; tstate->delete_later = NULL; diff --git a/Tools/c-analyzer/TODO b/Tools/c-analyzer/TODO index 3d599538510bd9..e3dc1a453e91af 100644 --- a/Tools/c-analyzer/TODO +++ b/Tools/c-analyzer/TODO @@ -36,10 +36,6 @@ Objects/bytesobject.c:_Py_onel_strings Py_ssize_t _Py_ Objects/dictobject.c:empty_keys_struct static PyDictKeysObject empty_keys_struct -# "initialized" -Python/fileutils.c:_Py_open_cloexec_works int _Py_open_cloexec_works - - # other non-object (40) Modules/_tracemalloc.c:allocators static struct { PyMemAllocatorEx mem; PyMemAllocatorEx raw; PyMemAllocatorEx obj; } allocators Modules/_tracemalloc.c:tables_lock static PyThread_type_lock tables_lock diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 466f25daa14dc6..1b6b3dfcfef26e 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -16,8 +16,6 @@ filename funcname name reason ## indicators for resource availability/capability # (set during first init) Python/bootstrap_hash.c py_getrandom getrandom_works - -Python/fileutils.c - _Py_open_cloexec_works - -Python/fileutils.c set_inheritable ioctl_works - # (set lazily, *after* first init) # XXX Is this thread-safe? Modules/posixmodule.c os_dup2_impl dup3_works - @@ -628,7 +626,6 @@ Include/py_curses.h - PyCurses_API - Include/pydecimal.h - _decimal_api - Modules/_blake2/blake2module.c - blake2b_type_spec - Modules/_blake2/blake2module.c - blake2s_type_spec - -Modules/_io/fileio.c - _Py_open_cloexec_works - Modules/_io/_iomodule.h - PyIOBase_Type - Modules/_io/_iomodule.h - PyRawIOBase_Type - Modules/_io/_iomodule.h - PyBufferedIOBase_Type - @@ -677,7 +674,6 @@ Modules/_sqlite/module.c - _pysqlite_enable_callback_tracebacks - Modules/_sqlite/module.c - pysqlite_BaseTypeAdapted - Modules/_sqlite/module.h - pysqlite_global_state - Modules/_testcapimodule.c - _PyBytesIOBuffer_Type - -Modules/posixmodule.c - _Py_open_cloexec_works - Modules/posixmodule.c - environ - Objects/object.c - _Py_GenericAliasIterType - Objects/object.c - _PyMemoryIter_Type - diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 4c8b0b8abd2963..b86c8fce11f57e 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -35,7 +35,6 @@ race_top:new_reference race_top:set_contains_key # https://gist.github.com/colesbury/d13d033f413b4ad07929d044bed86c35 race_top:set_discard_entry -race_top:set_inheritable race_top:_PyDict_CheckConsistency race_top:_Py_dict_lookup_threadsafe race_top:_multiprocessing_SemLock_acquire_impl