Skip to content

Commit 5eb28bc

Browse files
authoredDec 12, 2022
gh-81057: Move Signal-Related Globals to _PyRuntimeState (gh-100085)
#81057
1 parent 53d9cd9 commit 5eb28bc

File tree

6 files changed

+82
-69
lines changed

6 files changed

+82
-69
lines changed
 

‎Include/internal/pycore_runtime.h

+2-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extern "C" {
2323
#include "pycore_pyhash.h" // struct pyhash_runtime_state
2424
#include "pycore_pythread.h" // struct _pythread_runtime_state
2525
#include "pycore_obmalloc.h" // struct obmalloc_state
26+
#include "pycore_signal.h" // struct _signals_runtime_state
2627
#include "pycore_time.h" // struct _time_runtime_state
2728
#include "pycore_tracemalloc.h" // struct _tracemalloc_runtime_state
2829
#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids
@@ -93,13 +94,9 @@ typedef struct pyruntimestate {
9394
struct _pymem_allocators allocators;
9495
struct _obmalloc_state obmalloc;
9596
struct pyhash_runtime_state pyhash_state;
96-
struct {
97-
/* True if the main interpreter thread exited due to an unhandled
98-
* KeyboardInterrupt exception, suggesting the user pressed ^C. */
99-
int unhandled_keyboard_interrupt;
100-
} signals;
10197
struct _time_runtime_state time;
10298
struct _pythread_runtime_state threads;
99+
struct _signals_runtime_state signals;
103100

104101
struct pyinterpreters {
105102
PyThread_type_lock mutex;

‎Include/internal/pycore_runtime_init.h

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern "C" {
2626
}, \
2727
.obmalloc = _obmalloc_state_INIT(runtime.obmalloc), \
2828
.pyhash_state = pyhash_state_INIT, \
29+
.signals = _signals_RUNTIME_INIT, \
2930
.interpreters = { \
3031
/* This prevents interpreters from getting created \
3132
until _PyInterpreterState_Enable() is called. */ \

‎Include/internal/pycore_signal.h

+63
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ extern "C" {
1010
# error "this header requires Py_BUILD_CORE define"
1111
#endif
1212

13+
#include "pycore_atomic.h" // _Py_atomic_address
14+
1315
#include <signal.h> // NSIG
1416

17+
1518
#ifdef _SIG_MAXSIG
1619
// gh-91145: On FreeBSD, <signal.h> defines NSIG as 32: it doesn't include
1720
// realtime signals: [SIGRTMIN,SIGRTMAX]. Use _SIG_MAXSIG instead. For
@@ -29,6 +32,66 @@ extern "C" {
2932
# define Py_NSIG 64 // Use a reasonable default value
3033
#endif
3134

35+
#define INVALID_FD (-1)
36+
37+
struct _signals_runtime_state {
38+
volatile struct {
39+
_Py_atomic_int tripped;
40+
/* func is atomic to ensure that PyErr_SetInterrupt is async-signal-safe
41+
* (even though it would probably be otherwise, anyway).
42+
*/
43+
_Py_atomic_address func;
44+
} handlers[Py_NSIG];
45+
46+
volatile struct {
47+
#ifdef MS_WINDOWS
48+
/* This would be "SOCKET fd" if <winsock2.h> were always included.
49+
It isn't so we must cast to SOCKET where appropriate. */
50+
volatile int fd;
51+
#elif defined(__VXWORKS__)
52+
int fd;
53+
#else
54+
sig_atomic_t fd;
55+
#endif
56+
57+
int warn_on_full_buffer;
58+
#ifdef MS_WINDOWS
59+
int use_send;
60+
#endif
61+
} wakeup;
62+
63+
/* Speed up sigcheck() when none tripped */
64+
_Py_atomic_int is_tripped;
65+
66+
/* These objects necessarily belong to the main interpreter. */
67+
PyObject *default_handler;
68+
PyObject *ignore_handler;
69+
70+
#ifdef MS_WINDOWS
71+
/* This would be "HANDLE sigint_event" if <windows.h> were always included.
72+
It isn't so we must cast to HANDLE everywhere "sigint_event" is used. */
73+
void *sigint_event;
74+
#endif
75+
76+
/* True if the main interpreter thread exited due to an unhandled
77+
* KeyboardInterrupt exception, suggesting the user pressed ^C. */
78+
int unhandled_keyboard_interrupt;
79+
};
80+
81+
#ifdef MS_WINDOWS
82+
# define _signals_WAKEUP_INIT \
83+
{.fd = INVALID_FD, .warn_on_full_buffer = 1, .use_send = 0}
84+
#else
85+
# define _signals_WAKEUP_INIT \
86+
{.fd = INVALID_FD, .warn_on_full_buffer = 1}
87+
#endif
88+
89+
#define _signals_RUNTIME_INIT \
90+
{ \
91+
.wakeup = _signals_WAKEUP_INIT, \
92+
}
93+
94+
3295
#ifdef __cplusplus
3396
}
3497
#endif

‎Modules/signalmodule.c

+15-56
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "pycore_moduleobject.h" // _PyModule_GetState()
1414
#include "pycore_pyerrors.h" // _PyErr_SetString()
1515
#include "pycore_pystate.h" // _PyThreadState_GET()
16-
#include "pycore_signal.h" // Py_NSIG
16+
#include "pycore_signal.h"
1717

1818
#ifndef MS_WINDOWS
1919
# include "posixmodule.h"
@@ -23,12 +23,13 @@
2323
#endif
2424

2525
#ifdef MS_WINDOWS
26-
# include <windows.h>
2726
# ifdef HAVE_PROCESS_H
2827
# include <process.h>
2928
# endif
3029
#endif
3130

31+
#include "pycore_signal.h" // Py_NSIG
32+
3233
#ifdef HAVE_SIGNAL_H
3334
# include <signal.h>
3435
#endif
@@ -100,47 +101,13 @@ class sigset_t_converter(CConverter):
100101
may not be the thread that received the signal.
101102
*/
102103

103-
static volatile struct {
104-
_Py_atomic_int tripped;
105-
/* func is atomic to ensure that PyErr_SetInterrupt is async-signal-safe
106-
* (even though it would probably be otherwise, anyway).
107-
*/
108-
_Py_atomic_address func;
109-
} Handlers[Py_NSIG];
110-
111-
#ifdef MS_WINDOWS
112-
#define INVALID_FD ((SOCKET_T)-1)
113-
114-
static volatile struct {
115-
SOCKET_T fd;
116-
int warn_on_full_buffer;
117-
int use_send;
118-
} wakeup = {.fd = INVALID_FD, .warn_on_full_buffer = 1, .use_send = 0};
119-
#else
120-
#define INVALID_FD (-1)
121-
static volatile struct {
122-
#ifdef __VXWORKS__
123-
int fd;
124-
#else
125-
sig_atomic_t fd;
126-
#endif
127-
int warn_on_full_buffer;
128-
} wakeup = {.fd = INVALID_FD, .warn_on_full_buffer = 1};
129-
#endif
130-
131-
/* Speed up sigcheck() when none tripped */
132-
static _Py_atomic_int is_tripped;
133-
134-
typedef struct {
135-
PyObject *default_handler;
136-
PyObject *ignore_handler;
137-
#ifdef MS_WINDOWS
138-
HANDLE sigint_event;
139-
#endif
140-
} signal_state_t;
104+
#define Handlers _PyRuntime.signals.handlers
105+
#define wakeup _PyRuntime.signals.wakeup
106+
#define is_tripped _PyRuntime.signals.is_tripped
141107

142108
// State shared by all Python interpreters
143-
static signal_state_t signal_global_state = {0};
109+
typedef struct _signals_runtime_state signal_state_t;
110+
#define signal_global_state _PyRuntime.signals
144111

145112
#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER)
146113
# define PYHAVE_ITIMER_ERROR
@@ -331,13 +298,7 @@ trip_signal(int sig_num)
331298
See bpo-30038 for more details.
332299
*/
333300

334-
int fd;
335-
#ifdef MS_WINDOWS
336-
fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int);
337-
#else
338-
fd = wakeup.fd;
339-
#endif
340-
301+
int fd = wakeup.fd;
341302
if (fd != INVALID_FD) {
342303
unsigned char byte = (unsigned char)sig_num;
343304
#ifdef MS_WINDOWS
@@ -407,7 +368,7 @@ signal_handler(int sig_num)
407368
#ifdef MS_WINDOWS
408369
if (sig_num == SIGINT) {
409370
signal_state_t *state = &signal_global_state;
410-
SetEvent(state->sigint_event);
371+
SetEvent((HANDLE)state->sigint_event);
411372
}
412373
#endif
413374
}
@@ -822,7 +783,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds)
822783
}
823784

824785
old_sockfd = wakeup.fd;
825-
wakeup.fd = sockfd;
786+
wakeup.fd = Py_SAFE_DOWNCAST(sockfd, SOCKET_T, int);
826787
wakeup.warn_on_full_buffer = warn_on_full_buffer;
827788
wakeup.use_send = is_socket;
828789

@@ -873,11 +834,7 @@ PySignal_SetWakeupFd(int fd)
873834
fd = -1;
874835
}
875836

876-
#ifdef MS_WINDOWS
877-
int old_fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int);
878-
#else
879837
int old_fd = wakeup.fd;
880-
#endif
881838
wakeup.fd = fd;
882839
wakeup.warn_on_full_buffer = 1;
883840
return old_fd;
@@ -1654,6 +1611,8 @@ signal_module_exec(PyObject *m)
16541611
signal_state_t *state = &signal_global_state;
16551612
_signal_module_state *modstate = get_signal_state(m);
16561613

1614+
// XXX For proper isolation, these values must be guaranteed
1615+
// to be effectively const (e.g. immortal).
16571616
modstate->default_handler = state->default_handler; // borrowed ref
16581617
modstate->ignore_handler = state->ignore_handler; // borrowed ref
16591618

@@ -1783,7 +1742,7 @@ _PySignal_Fini(void)
17831742

17841743
#ifdef MS_WINDOWS
17851744
if (state->sigint_event != NULL) {
1786-
CloseHandle(state->sigint_event);
1745+
CloseHandle((HANDLE)state->sigint_event);
17871746
state->sigint_event = NULL;
17881747
}
17891748
#endif
@@ -2009,7 +1968,7 @@ _PySignal_Init(int install_signal_handlers)
20091968

20101969
#ifdef MS_WINDOWS
20111970
/* Create manual-reset event, initially unset */
2012-
state->sigint_event = CreateEvent(NULL, TRUE, FALSE, FALSE);
1971+
state->sigint_event = (void *)CreateEvent(NULL, TRUE, FALSE, FALSE);
20131972
if (state->sigint_event == NULL) {
20141973
PyErr_SetFromWindowsErr(0);
20151974
return -1;

‎Python/pylifecycle.c

-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ extern void _PyIO_Fini(void);
5454

5555
#ifdef MS_WINDOWS
5656
# undef BYTE
57-
# include "windows.h"
5857

5958
extern PyTypeObject PyWindowsConsoleIO_Type;
6059
# define PyWindowsConsoleIO_Check(op) \

‎Tools/c-analyzer/cpython/globals-to-fix.tsv

+1-7
Original file line numberDiff line numberDiff line change
@@ -365,13 +365,7 @@ Modules/itertoolsmodule.c - ziplongest_type -
365365
##################################
366366
## global non-objects to fix in builtin modules
367367

368-
##-----------------------
369-
## state
370-
371-
Modules/signalmodule.c - is_tripped -
372-
Modules/signalmodule.c - signal_global_state -
373-
Modules/signalmodule.c - wakeup -
374-
Modules/signalmodule.c - Handlers -
368+
# <none>
375369

376370

377371
##################################

0 commit comments

Comments
 (0)
Please sign in to comment.