diff options
author | Victor Stinner <vstinner@python.org> | 2023-09-30 17:25:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-30 17:25:54 (GMT) |
commit | 74e425ec186dde6bcfb172616fe8f35ccb5a09bb (patch) | |
tree | 2c9167ef4bc17e11d2ada574f184949a8f53e5bc | |
parent | f3bb00ea12db6525f07d62368a65efec47d192b9 (diff) | |
download | cpython-74e425ec186dde6bcfb172616fe8f35ccb5a09bb.zip cpython-74e425ec186dde6bcfb172616fe8f35ccb5a09bb.tar.gz cpython-74e425ec186dde6bcfb172616fe8f35ccb5a09bb.tar.bz2 |
gh-110014: Fix _POSIX_THREADS and _POSIX_SEMAPHORES usage (#110139)
* pycore_pythread.h is now the central place to make sure that
_POSIX_THREADS and _POSIX_SEMAPHORES macros are defined if
available.
* Make sure that pycore_pythread.h is included when _POSIX_THREADS
and _POSIX_SEMAPHORES macros are tested.
* PY_TIMEOUT_MAX is now defined as a constant, since its value
depends on _POSIX_THREADS, instead of being defined as a macro.
* Prevent integer overflow in the preprocessor when computing
PY_TIMEOUT_MAX_VALUE on Windows:
replace "0xFFFFFFFELL * 1000 < LLONG_MAX"
with "0xFFFFFFFELL < LLONG_MAX / 1000".
* Document the change and give hints how to fix affected code.
* Add an exception for PY_TIMEOUT_MAX name to smelly.py
* Add PY_TIMEOUT_MAX to the stable ABI
-rw-r--r-- | Doc/data/stable_abi.dat | 1 | ||||
-rw-r--r-- | Doc/whatsnew/3.13.rst | 4 | ||||
-rw-r--r-- | Include/internal/pycore_condvar.h | 12 | ||||
-rw-r--r-- | Include/internal/pycore_pythread.h | 46 | ||||
-rw-r--r-- | Include/internal/pycore_semaphore.h | 4 | ||||
-rw-r--r-- | Include/pythread.h | 17 | ||||
-rw-r--r-- | Lib/test/test_stable_abi_ctypes.py | 1 | ||||
-rw-r--r-- | Misc/stable_abi.toml | 4 | ||||
-rwxr-xr-x | PC/python3dll.c | 1 | ||||
-rw-r--r-- | Python/condvar.h | 3 | ||||
-rw-r--r-- | Python/thread.c | 22 | ||||
-rw-r--r-- | Python/thread_pthread.h | 9 | ||||
-rwxr-xr-x | Tools/build/smelly.py | 7 |
13 files changed, 73 insertions, 58 deletions
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index c189c78..07c6d51 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -1,4 +1,5 @@ role,name,added,ifdef_note,struct_abi_kind +var,PY_TIMEOUT_MAX,3.2,, macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,, function,PyAIter_Check,3.10,, function,PyArg_Parse,3.2,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index c9e6ca8..d6188e6 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -989,6 +989,10 @@ Porting to Python 3.13 * ``Python.h`` no longer includes the ``<unistd.h>`` standard header file. If needed, it should now be included explicitly. For example, it provides the functions: ``close()``, ``getpagesize()``, ``getpid()`` and ``sysconf()``. + As a consequence, ``_POSIX_SEMAPHORES`` and ``_POSIX_THREADS`` macros are no + longer defined by ``Python.h``. The ``HAVE_UNISTD_H`` and ``HAVE_PTHREAD_H`` + macros defined by ``Python.h`` can be used to decide if ``<unistd.h>`` and + ``<pthread.h>`` header files can be included. (Contributed by Victor Stinner in :gh:`108765`.) * ``Python.h`` no longer includes these standard header files: ``<time.h>``, diff --git a/Include/internal/pycore_condvar.h b/Include/internal/pycore_condvar.h index 489e67d..34c21aa 100644 --- a/Include/internal/pycore_condvar.h +++ b/Include/internal/pycore_condvar.h @@ -5,18 +5,8 @@ # error "this header requires Py_BUILD_CORE define" #endif -#ifndef MS_WINDOWS -# include <unistd.h> // _POSIX_THREADS -#endif +#include "pycore_pythread.h" // _POSIX_THREADS -#ifndef _POSIX_THREADS -/* This means pthreads are not implemented in libc headers, hence the macro - not present in unistd.h. But they still can be implemented as an external - library (e.g. gnu pth in pthread emulation) */ -# ifdef HAVE_PTHREAD_H -# include <pthread.h> // _POSIX_THREADS -# endif -#endif #ifdef _POSIX_THREADS /* diff --git a/Include/internal/pycore_pythread.h b/Include/internal/pycore_pythread.h index 5ec2abd..98019c5 100644 --- a/Include/internal/pycore_pythread.h +++ b/Include/internal/pycore_pythread.h @@ -9,29 +9,29 @@ extern "C" { #endif -#ifndef _POSIX_THREADS -/* This means pthreads are not implemented in libc headers, hence the macro - not present in unistd.h. But they still can be implemented as an external - library (e.g. gnu pth in pthread emulation) */ -# ifdef HAVE_PTHREAD_H -# include <pthread.h> // _POSIX_THREADS -# endif -# ifndef _POSIX_THREADS -/* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then - enough of the Posix threads package is implemented to support python - threads. - - This is valid for HP-UX 11.23 running on an ia64 system. If needed, add - a check of __ia64 to verify that we're running on an ia64 system instead - of a pa-risc system. -*/ -# ifdef __hpux -# ifdef _SC_THREADS -# define _POSIX_THREADS -# endif -# endif -# endif /* _POSIX_THREADS */ -#endif /* _POSIX_THREADS */ +// Get _POSIX_THREADS and _POSIX_SEMAPHORES macros if available +#if (defined(HAVE_UNISTD_H) && !defined(_POSIX_THREADS) \ + && !defined(_POSIX_SEMAPHORES)) +# include <unistd.h> // _POSIX_THREADS, _POSIX_SEMAPHORES +#endif +#if (defined(HAVE_PTHREAD_H) && !defined(_POSIX_THREADS) \ + && !defined(_POSIX_SEMAPHORES)) + // This means pthreads are not implemented in libc headers, hence the macro + // not present in <unistd.h>. But they still can be implemented as an + // external library (e.g. gnu pth in pthread emulation) +# include <pthread.h> // _POSIX_THREADS, _POSIX_SEMAPHORES +#endif +#if !defined(_POSIX_THREADS) && defined(__hpux) && defined(_SC_THREADS) + // Check if we're running on HP-UX and _SC_THREADS is defined. If so, then + // enough of the POSIX threads package is implemented to support Python + // threads. + // + // This is valid for HP-UX 11.23 running on an ia64 system. If needed, add + // a check of __ia64 to verify that we're running on an ia64 system instead + // of a pa-risc system. +# define _POSIX_THREADS +#endif + #if defined(_POSIX_THREADS) || defined(HAVE_PTHREAD_STUBS) # define _USE_PTHREADS diff --git a/Include/internal/pycore_semaphore.h b/Include/internal/pycore_semaphore.h index 2a4ecb7..4c37df7 100644 --- a/Include/internal/pycore_semaphore.h +++ b/Include/internal/pycore_semaphore.h @@ -7,7 +7,8 @@ # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_time.h" // _PyTime_t +#include "pycore_pythread.h" // _POSIX_SEMAPHORES +#include "pycore_time.h" // _PyTime_t #ifdef MS_WINDOWS # define WIN32_LEAN_AND_MEAN @@ -26,6 +27,7 @@ # include <semaphore.h> #endif + #ifdef __cplusplus extern "C" { #endif diff --git a/Include/pythread.h b/Include/pythread.h index 6371443..2c2fd63 100644 --- a/Include/pythread.h +++ b/Include/pythread.h @@ -44,22 +44,7 @@ PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int); */ #define PY_TIMEOUT_T long long -#if defined(_POSIX_THREADS) - /* PyThread_acquire_lock_timed() uses _PyTime_FromNanoseconds(us * 1000), - convert microseconds to nanoseconds. */ -# define PY_TIMEOUT_MAX (LLONG_MAX / 1000) -#elif defined (NT_THREADS) - // WaitForSingleObject() accepts timeout in milliseconds in the range - // [0; 0xFFFFFFFE] (DWORD type). INFINITE value (0xFFFFFFFF) means no - // timeout. 0xFFFFFFFE milliseconds is around 49.7 days. -# if 0xFFFFFFFELL * 1000 < LLONG_MAX -# define PY_TIMEOUT_MAX (0xFFFFFFFELL * 1000) -# else -# define PY_TIMEOUT_MAX LLONG_MAX -# endif -#else -# define PY_TIMEOUT_MAX LLONG_MAX -#endif +PyAPI_DATA(const long long) PY_TIMEOUT_MAX; /* If microseconds == 0, the call is non-blocking: it returns immediately diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 94f817f8e..6e9496d 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -35,6 +35,7 @@ class TestStableABIAvailability(unittest.TestCase): SYMBOL_NAMES = ( + "PY_TIMEOUT_MAX", "PyAIter_Check", "PyArg_Parse", "PyArg_ParseTuple", diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 8df3f85..46e2307 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -1843,6 +1843,10 @@ [function.PyThread_start_new_thread] added = '3.2' +# Not mentioned in PEP 384, was implemented as a macro in Python <= 3.12 +[data.PY_TIMEOUT_MAX] + added = '3.2' + # The following were added in PC/python3.def in Python 3.3: # 7800f75827b1be557be16f3b18f5170fbf9fae08 # 9c56409d3353b8cd4cfc19e0467bbe23fd34fc92 diff --git a/PC/python3dll.c b/PC/python3dll.c index 2c1cc80..75728c7 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -768,6 +768,7 @@ EXPORT_DATA(Py_FileSystemDefaultEncodeErrors) EXPORT_DATA(Py_FileSystemDefaultEncoding) EXPORT_DATA(Py_GenericAliasType) EXPORT_DATA(Py_HasFileSystemDefaultEncoding) +EXPORT_DATA(PY_TIMEOUT_MAX) EXPORT_DATA(Py_UTF8Mode) EXPORT_DATA(Py_Version) EXPORT_DATA(PyBaseObject_Type) diff --git a/Python/condvar.h b/Python/condvar.h index 4ddc531..d54db94 100644 --- a/Python/condvar.h +++ b/Python/condvar.h @@ -41,7 +41,8 @@ #define _CONDVAR_IMPL_H_ #include "Python.h" -#include "pycore_condvar.h" +#include "pycore_pythread.h" // _POSIX_THREADS + #ifdef _POSIX_THREADS /* diff --git a/Python/thread.c b/Python/thread.c index 1ac2db2..bf207ce 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -8,7 +8,7 @@ #include "Python.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() -#include "pycore_pythread.h" +#include "pycore_pythread.h" // _POSIX_THREADS #ifndef DONT_HAVE_STDIO_H # include <stdio.h> @@ -17,6 +17,26 @@ #include <stdlib.h> +// Define PY_TIMEOUT_MAX constant. +#ifdef _POSIX_THREADS + // PyThread_acquire_lock_timed() uses _PyTime_FromNanoseconds(us * 1000), + // convert microseconds to nanoseconds. +# define PY_TIMEOUT_MAX_VALUE (LLONG_MAX / 1000) +#elif defined (NT_THREADS) + // WaitForSingleObject() accepts timeout in milliseconds in the range + // [0; 0xFFFFFFFE] (DWORD type). INFINITE value (0xFFFFFFFF) means no + // timeout. 0xFFFFFFFE milliseconds is around 49.7 days. +# if 0xFFFFFFFELL < LLONG_MAX / 1000 +# define PY_TIMEOUT_MAX_VALUE (0xFFFFFFFELL * 1000) +# else +# define PY_TIMEOUT_MAX_VALUE LLONG_MAX +# endif +#else +# define PY_TIMEOUT_MAX_VALUE LLONG_MAX +#endif +const long long PY_TIMEOUT_MAX = PY_TIMEOUT_MAX_VALUE; + + static void PyThread__init_thread(void); /* Forward */ #define initialized _PyRuntime.threads.initialized diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index f96c57d..76a1f77 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -1,4 +1,5 @@ -#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize +#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize +#include "pycore_pythread.h" // _POSIX_SEMAPHORES /* Posix threads interface */ @@ -84,10 +85,10 @@ /* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so we need to add 0 to make it work there as well. */ #if (_POSIX_SEMAPHORES+0) == -1 -#define HAVE_BROKEN_POSIX_SEMAPHORES +# define HAVE_BROKEN_POSIX_SEMAPHORES #else -#include <semaphore.h> -#include <errno.h> +# include <semaphore.h> +# include <errno.h> #endif #endif diff --git a/Tools/build/smelly.py b/Tools/build/smelly.py index 276a5ab..ab34530 100755 --- a/Tools/build/smelly.py +++ b/Tools/build/smelly.py @@ -11,6 +11,11 @@ ALLOWED_PREFIXES = ('Py', '_Py') if sys.platform == 'darwin': ALLOWED_PREFIXES += ('__Py',) +# "Legacy": some old symbols are prefixed by "PY_". +EXCEPTIONS = frozenset({ + 'PY_TIMEOUT_MAX', +}) + IGNORED_EXTENSION = "_ctypes_test" # Ignore constructor and destructor functions IGNORED_SYMBOLS = {'_init', '_fini'} @@ -72,7 +77,7 @@ def get_smelly_symbols(stdout): symbol = parts[-1] result = '%s (type: %s)' % (symbol, symtype) - if symbol.startswith(ALLOWED_PREFIXES): + if symbol.startswith(ALLOWED_PREFIXES) or symbol in EXCEPTIONS: python_symbols.append(result) continue |