Skip to content

Commit 28f1396

Browse files
vstinnerGlyphack
authored andcommitted
pythongh-110014: Fix _POSIX_THREADS and _POSIX_SEMAPHORES usage (python#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
1 parent 5afbfdc commit 28f1396

File tree

13 files changed

+73
-58
lines changed

13 files changed

+73
-58
lines changed

Doc/data/stable_abi.dat

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/whatsnew/3.13.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,10 @@ Porting to Python 3.13
989989
* ``Python.h`` no longer includes the ``<unistd.h>`` standard header file. If
990990
needed, it should now be included explicitly. For example, it provides the
991991
functions: ``close()``, ``getpagesize()``, ``getpid()`` and ``sysconf()``.
992+
As a consequence, ``_POSIX_SEMAPHORES`` and ``_POSIX_THREADS`` macros are no
993+
longer defined by ``Python.h``. The ``HAVE_UNISTD_H`` and ``HAVE_PTHREAD_H``
994+
macros defined by ``Python.h`` can be used to decide if ``<unistd.h>`` and
995+
``<pthread.h>`` header files can be included.
992996
(Contributed by Victor Stinner in :gh:`108765`.)
993997

994998
* ``Python.h`` no longer includes these standard header files: ``<time.h>``,

Include/internal/pycore_condvar.h

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,8 @@
55
# error "this header requires Py_BUILD_CORE define"
66
#endif
77

8-
#ifndef MS_WINDOWS
9-
# include <unistd.h> // _POSIX_THREADS
10-
#endif
8+
#include "pycore_pythread.h" // _POSIX_THREADS
119

12-
#ifndef _POSIX_THREADS
13-
/* This means pthreads are not implemented in libc headers, hence the macro
14-
not present in unistd.h. But they still can be implemented as an external
15-
library (e.g. gnu pth in pthread emulation) */
16-
# ifdef HAVE_PTHREAD_H
17-
# include <pthread.h> // _POSIX_THREADS
18-
# endif
19-
#endif
2010

2111
#ifdef _POSIX_THREADS
2212
/*

Include/internal/pycore_pythread.h

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,29 @@ extern "C" {
99
#endif
1010

1111

12-
#ifndef _POSIX_THREADS
13-
/* This means pthreads are not implemented in libc headers, hence the macro
14-
not present in unistd.h. But they still can be implemented as an external
15-
library (e.g. gnu pth in pthread emulation) */
16-
# ifdef HAVE_PTHREAD_H
17-
# include <pthread.h> // _POSIX_THREADS
18-
# endif
19-
# ifndef _POSIX_THREADS
20-
/* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then
21-
enough of the Posix threads package is implemented to support python
22-
threads.
23-
24-
This is valid for HP-UX 11.23 running on an ia64 system. If needed, add
25-
a check of __ia64 to verify that we're running on an ia64 system instead
26-
of a pa-risc system.
27-
*/
28-
# ifdef __hpux
29-
# ifdef _SC_THREADS
30-
# define _POSIX_THREADS
31-
# endif
32-
# endif
33-
# endif /* _POSIX_THREADS */
34-
#endif /* _POSIX_THREADS */
12+
// Get _POSIX_THREADS and _POSIX_SEMAPHORES macros if available
13+
#if (defined(HAVE_UNISTD_H) && !defined(_POSIX_THREADS) \
14+
&& !defined(_POSIX_SEMAPHORES))
15+
# include <unistd.h> // _POSIX_THREADS, _POSIX_SEMAPHORES
16+
#endif
17+
#if (defined(HAVE_PTHREAD_H) && !defined(_POSIX_THREADS) \
18+
&& !defined(_POSIX_SEMAPHORES))
19+
// This means pthreads are not implemented in libc headers, hence the macro
20+
// not present in <unistd.h>. But they still can be implemented as an
21+
// external library (e.g. gnu pth in pthread emulation)
22+
# include <pthread.h> // _POSIX_THREADS, _POSIX_SEMAPHORES
23+
#endif
24+
#if !defined(_POSIX_THREADS) && defined(__hpux) && defined(_SC_THREADS)
25+
// Check if we're running on HP-UX and _SC_THREADS is defined. If so, then
26+
// enough of the POSIX threads package is implemented to support Python
27+
// threads.
28+
//
29+
// This is valid for HP-UX 11.23 running on an ia64 system. If needed, add
30+
// a check of __ia64 to verify that we're running on an ia64 system instead
31+
// of a pa-risc system.
32+
# define _POSIX_THREADS
33+
#endif
34+
3535

3636
#if defined(_POSIX_THREADS) || defined(HAVE_PTHREAD_STUBS)
3737
# define _USE_PTHREADS

Include/internal/pycore_semaphore.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
# error "this header requires Py_BUILD_CORE define"
88
#endif
99

10-
#include "pycore_time.h" // _PyTime_t
10+
#include "pycore_pythread.h" // _POSIX_SEMAPHORES
11+
#include "pycore_time.h" // _PyTime_t
1112

1213
#ifdef MS_WINDOWS
1314
# define WIN32_LEAN_AND_MEAN
@@ -26,6 +27,7 @@
2627
# include <semaphore.h>
2728
#endif
2829

30+
2931
#ifdef __cplusplus
3032
extern "C" {
3133
#endif

Include/pythread.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,7 @@ PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int);
4444
*/
4545
#define PY_TIMEOUT_T long long
4646

47-
#if defined(_POSIX_THREADS)
48-
/* PyThread_acquire_lock_timed() uses _PyTime_FromNanoseconds(us * 1000),
49-
convert microseconds to nanoseconds. */
50-
# define PY_TIMEOUT_MAX (LLONG_MAX / 1000)
51-
#elif defined (NT_THREADS)
52-
// WaitForSingleObject() accepts timeout in milliseconds in the range
53-
// [0; 0xFFFFFFFE] (DWORD type). INFINITE value (0xFFFFFFFF) means no
54-
// timeout. 0xFFFFFFFE milliseconds is around 49.7 days.
55-
# if 0xFFFFFFFELL * 1000 < LLONG_MAX
56-
# define PY_TIMEOUT_MAX (0xFFFFFFFELL * 1000)
57-
# else
58-
# define PY_TIMEOUT_MAX LLONG_MAX
59-
# endif
60-
#else
61-
# define PY_TIMEOUT_MAX LLONG_MAX
62-
#endif
47+
PyAPI_DATA(const long long) PY_TIMEOUT_MAX;
6348

6449

6550
/* If microseconds == 0, the call is non-blocking: it returns immediately

Lib/test/test_stable_abi_ctypes.py

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Misc/stable_abi.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,10 @@
18431843
[function.PyThread_start_new_thread]
18441844
added = '3.2'
18451845

1846+
# Not mentioned in PEP 384, was implemented as a macro in Python <= 3.12
1847+
[data.PY_TIMEOUT_MAX]
1848+
added = '3.2'
1849+
18461850
# The following were added in PC/python3.def in Python 3.3:
18471851
# 7800f75827b1be557be16f3b18f5170fbf9fae08
18481852
# 9c56409d3353b8cd4cfc19e0467bbe23fd34fc92

PC/python3dll.c

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/condvar.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
#define _CONDVAR_IMPL_H_
4242

4343
#include "Python.h"
44-
#include "pycore_condvar.h"
44+
#include "pycore_pythread.h" // _POSIX_THREADS
45+
4546

4647
#ifdef _POSIX_THREADS
4748
/*

Python/thread.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "Python.h"
99
#include "pycore_pystate.h" // _PyInterpreterState_GET()
1010
#include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin()
11-
#include "pycore_pythread.h"
11+
#include "pycore_pythread.h" // _POSIX_THREADS
1212

1313
#ifndef DONT_HAVE_STDIO_H
1414
# include <stdio.h>
@@ -17,6 +17,26 @@
1717
#include <stdlib.h>
1818

1919

20+
// Define PY_TIMEOUT_MAX constant.
21+
#ifdef _POSIX_THREADS
22+
// PyThread_acquire_lock_timed() uses _PyTime_FromNanoseconds(us * 1000),
23+
// convert microseconds to nanoseconds.
24+
# define PY_TIMEOUT_MAX_VALUE (LLONG_MAX / 1000)
25+
#elif defined (NT_THREADS)
26+
// WaitForSingleObject() accepts timeout in milliseconds in the range
27+
// [0; 0xFFFFFFFE] (DWORD type). INFINITE value (0xFFFFFFFF) means no
28+
// timeout. 0xFFFFFFFE milliseconds is around 49.7 days.
29+
# if 0xFFFFFFFELL < LLONG_MAX / 1000
30+
# define PY_TIMEOUT_MAX_VALUE (0xFFFFFFFELL * 1000)
31+
# else
32+
# define PY_TIMEOUT_MAX_VALUE LLONG_MAX
33+
# endif
34+
#else
35+
# define PY_TIMEOUT_MAX_VALUE LLONG_MAX
36+
#endif
37+
const long long PY_TIMEOUT_MAX = PY_TIMEOUT_MAX_VALUE;
38+
39+
2040
static void PyThread__init_thread(void); /* Forward */
2141

2242
#define initialized _PyRuntime.threads.initialized

Python/thread_pthread.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
1+
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
2+
#include "pycore_pythread.h" // _POSIX_SEMAPHORES
23

34
/* Posix threads interface */
45

@@ -84,10 +85,10 @@
8485
/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so
8586
we need to add 0 to make it work there as well. */
8687
#if (_POSIX_SEMAPHORES+0) == -1
87-
#define HAVE_BROKEN_POSIX_SEMAPHORES
88+
# define HAVE_BROKEN_POSIX_SEMAPHORES
8889
#else
89-
#include <semaphore.h>
90-
#include <errno.h>
90+
# include <semaphore.h>
91+
# include <errno.h>
9192
#endif
9293
#endif
9394

Tools/build/smelly.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
if sys.platform == 'darwin':
1212
ALLOWED_PREFIXES += ('__Py',)
1313

14+
# "Legacy": some old symbols are prefixed by "PY_".
15+
EXCEPTIONS = frozenset({
16+
'PY_TIMEOUT_MAX',
17+
})
18+
1419
IGNORED_EXTENSION = "_ctypes_test"
1520
# Ignore constructor and destructor functions
1621
IGNORED_SYMBOLS = {'_init', '_fini'}
@@ -72,7 +77,7 @@ def get_smelly_symbols(stdout):
7277
symbol = parts[-1]
7378
result = '%s (type: %s)' % (symbol, symtype)
7479

75-
if symbol.startswith(ALLOWED_PREFIXES):
80+
if symbol.startswith(ALLOWED_PREFIXES) or symbol in EXCEPTIONS:
7681
python_symbols.append(result)
7782
continue
7883

0 commit comments

Comments
 (0)