Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-81057: Move Signal-Related Globals to _PyRuntimeState #100085

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6dcffac
Add struct _signals_runtime_state.
ericsnowcurrently Dec 6, 2022
5e49464
Move signalmodule.c:Handlers to _PyRuntimeState.
ericsnowcurrently Dec 6, 2022
07332af
Move signalmodule.c:wakeup to _PyRuntimeState.
ericsnowcurrently Dec 6, 2022
1b5ec60
Move signalmodule.c:is_tripped to _PyRuntimeState.
ericsnowcurrently Dec 6, 2022
280f6f4
Move signalmodule.c:signal_global_state to _PyRuntimeState.
ericsnowcurrently Dec 7, 2022
fd6a2de
Fix includes (e.g. for Windows) in pycore_signal.h.
ericsnowcurrently Dec 8, 2022
410190b
Drop the socketmodule.h include.
ericsnowcurrently Dec 8, 2022
1fc3dce
Fix the include for SOCKET on Windows.
ericsnowcurrently Dec 8, 2022
d4f05e4
Fix formatting.
ericsnowcurrently Dec 8, 2022
1ddece1
Fix order of includes on WINDOWS.
ericsnowcurrently Dec 8, 2022
9592a8b
Fix includes on Windows.
ericsnowcurrently Dec 9, 2022
cc43787
Fix INVALID_FD on Windows.
ericsnowcurrently Dec 9, 2022
0164014
Revert "Fix includes on Windows."
ericsnowcurrently Dec 9, 2022
1d8d9e2
Include the headers conditionally.
ericsnowcurrently Dec 9, 2022
555f727
Fail instead of falling back to includes.
ericsnowcurrently Dec 9, 2022
57dc4a8
Reach for a sweet spot.
ericsnowcurrently Dec 10, 2022
08799ad
Pull in HANDLE.
ericsnowcurrently Dec 10, 2022
3bad4d6
Drop an unnecessary ifdef.
ericsnowcurrently Dec 12, 2022
3624161
Force the ifdef checks for the actual definition of _PyRuntime.
ericsnowcurrently Dec 12, 2022
2191c97
Drop the ifdef checks.
ericsnowcurrently Dec 12, 2022
76794fb
Change members/macros to fail (or warn) when used without the proper …
ericsnowcurrently Dec 12, 2022
c9aee62
Make sure the Windows includes happen early enough.
ericsnowcurrently Dec 12, 2022
ca33ad7
Move the includes up.
ericsnowcurrently Dec 12, 2022
7f35360
Check for _WINSOCKAPI_ instead of SOCKET.
ericsnowcurrently Dec 12, 2022
3d23778
Define a HANDLE macro where needed.
ericsnowcurrently Dec 12, 2022
73e3bc1
Use void* for the "fd" field.
ericsnowcurrently Dec 12, 2022
4195e62
Use void* for the "sigint_event" field.
ericsnowcurrently Dec 12, 2022
36cda7b
Use an int for wakeup.fd, instead of SOCKET.
ericsnowcurrently Dec 12, 2022
2a3bdf1
Drop the explicit includes.
ericsnowcurrently Dec 12, 2022
38596a0
Fix a warning.
ericsnowcurrently Dec 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern "C" {
#include "pycore_pyhash.h" // struct pyhash_runtime_state
#include "pycore_pythread.h" // struct _pythread_runtime_state
#include "pycore_obmalloc.h" // struct obmalloc_state
#include "pycore_signal.h" // struct _signals_runtime_state
#include "pycore_time.h" // struct _time_runtime_state
#include "pycore_tracemalloc.h" // struct _tracemalloc_runtime_state
#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids
Expand Down Expand Up @@ -93,13 +94,9 @@ typedef struct pyruntimestate {
struct _pymem_allocators allocators;
struct _obmalloc_state obmalloc;
struct pyhash_runtime_state pyhash_state;
struct {
/* True if the main interpreter thread exited due to an unhandled
* KeyboardInterrupt exception, suggesting the user pressed ^C. */
int unhandled_keyboard_interrupt;
} signals;
struct _time_runtime_state time;
struct _pythread_runtime_state threads;
struct _signals_runtime_state signals;

struct pyinterpreters {
PyThread_type_lock mutex;
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ extern "C" {
}, \
.obmalloc = _obmalloc_state_INIT(runtime.obmalloc), \
.pyhash_state = pyhash_state_INIT, \
.signals = _signals_RUNTIME_INIT, \
.interpreters = { \
/* This prevents interpreters from getting created \
until _PyInterpreterState_Enable() is called. */ \
Expand Down
63 changes: 63 additions & 0 deletions Include/internal/pycore_signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif

#include "pycore_atomic.h" // _Py_atomic_address

#include <signal.h> // NSIG


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

#define INVALID_FD (-1)

struct _signals_runtime_state {
volatile struct {
_Py_atomic_int tripped;
/* func is atomic to ensure that PyErr_SetInterrupt is async-signal-safe
* (even though it would probably be otherwise, anyway).
*/
_Py_atomic_address func;
} handlers[Py_NSIG];

volatile struct {
#ifdef MS_WINDOWS
/* This would be "SOCKET fd" if <winsock2.h> were always included.
It isn't so we must cast to SOCKET where appropriate. */
volatile int fd;
#elif defined(__VXWORKS__)
int fd;
#else
sig_atomic_t fd;
#endif

int warn_on_full_buffer;
#ifdef MS_WINDOWS
int use_send;
#endif
} wakeup;

/* Speed up sigcheck() when none tripped */
_Py_atomic_int is_tripped;

/* These objects necessarily belong to the main interpreter. */
PyObject *default_handler;
PyObject *ignore_handler;

#ifdef MS_WINDOWS
/* This would be "HANDLE sigint_event" if <windows.h> were always included.
It isn't so we must cast to HANDLE everywhere "sigint_event" is used. */
void *sigint_event;
#endif

/* True if the main interpreter thread exited due to an unhandled
* KeyboardInterrupt exception, suggesting the user pressed ^C. */
int unhandled_keyboard_interrupt;
};

#ifdef MS_WINDOWS
# define _signals_WAKEUP_INIT \
{.fd = INVALID_FD, .warn_on_full_buffer = 1, .use_send = 0}
#else
# define _signals_WAKEUP_INIT \
{.fd = INVALID_FD, .warn_on_full_buffer = 1}
#endif

#define _signals_RUNTIME_INIT \
{ \
.wakeup = _signals_WAKEUP_INIT, \
}


#ifdef __cplusplus
}
#endif
Expand Down
71 changes: 15 additions & 56 deletions Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_pyerrors.h" // _PyErr_SetString()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_signal.h" // Py_NSIG
#include "pycore_signal.h"

#ifndef MS_WINDOWS
# include "posixmodule.h"
Expand All @@ -23,12 +23,13 @@
#endif

#ifdef MS_WINDOWS
# include <windows.h>
# ifdef HAVE_PROCESS_H
# include <process.h>
# endif
#endif

#include "pycore_signal.h" // Py_NSIG

#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
Expand Down Expand Up @@ -100,47 +101,13 @@ class sigset_t_converter(CConverter):
may not be the thread that received the signal.
*/

static volatile struct {
_Py_atomic_int tripped;
/* func is atomic to ensure that PyErr_SetInterrupt is async-signal-safe
* (even though it would probably be otherwise, anyway).
*/
_Py_atomic_address func;
} Handlers[Py_NSIG];

#ifdef MS_WINDOWS
#define INVALID_FD ((SOCKET_T)-1)

static volatile struct {
SOCKET_T fd;
int warn_on_full_buffer;
int use_send;
} wakeup = {.fd = INVALID_FD, .warn_on_full_buffer = 1, .use_send = 0};
#else
#define INVALID_FD (-1)
static volatile struct {
#ifdef __VXWORKS__
int fd;
#else
sig_atomic_t fd;
#endif
int warn_on_full_buffer;
} wakeup = {.fd = INVALID_FD, .warn_on_full_buffer = 1};
#endif

/* Speed up sigcheck() when none tripped */
static _Py_atomic_int is_tripped;

typedef struct {
PyObject *default_handler;
PyObject *ignore_handler;
#ifdef MS_WINDOWS
HANDLE sigint_event;
#endif
} signal_state_t;
#define Handlers _PyRuntime.signals.handlers
#define wakeup _PyRuntime.signals.wakeup
#define is_tripped _PyRuntime.signals.is_tripped

// State shared by all Python interpreters
static signal_state_t signal_global_state = {0};
typedef struct _signals_runtime_state signal_state_t;
#define signal_global_state _PyRuntime.signals

#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER)
# define PYHAVE_ITIMER_ERROR
Expand Down Expand Up @@ -331,13 +298,7 @@ trip_signal(int sig_num)
See bpo-30038 for more details.
*/

int fd;
#ifdef MS_WINDOWS
fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int);
#else
fd = wakeup.fd;
#endif

int fd = wakeup.fd;
if (fd != INVALID_FD) {
unsigned char byte = (unsigned char)sig_num;
#ifdef MS_WINDOWS
Expand Down Expand Up @@ -407,7 +368,7 @@ signal_handler(int sig_num)
#ifdef MS_WINDOWS
if (sig_num == SIGINT) {
signal_state_t *state = &signal_global_state;
SetEvent(state->sigint_event);
SetEvent((HANDLE)state->sigint_event);
}
#endif
}
Expand Down Expand Up @@ -822,7 +783,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds)
}

old_sockfd = wakeup.fd;
wakeup.fd = sockfd;
wakeup.fd = Py_SAFE_DOWNCAST(sockfd, SOCKET_T, int);
wakeup.warn_on_full_buffer = warn_on_full_buffer;
wakeup.use_send = is_socket;

Expand Down Expand Up @@ -873,11 +834,7 @@ PySignal_SetWakeupFd(int fd)
fd = -1;
}

#ifdef MS_WINDOWS
int old_fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int);
#else
int old_fd = wakeup.fd;
#endif
wakeup.fd = fd;
wakeup.warn_on_full_buffer = 1;
return old_fd;
Expand Down Expand Up @@ -1654,6 +1611,8 @@ signal_module_exec(PyObject *m)
signal_state_t *state = &signal_global_state;
_signal_module_state *modstate = get_signal_state(m);

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

Expand Down Expand Up @@ -1783,7 +1742,7 @@ _PySignal_Fini(void)

#ifdef MS_WINDOWS
if (state->sigint_event != NULL) {
CloseHandle(state->sigint_event);
CloseHandle((HANDLE)state->sigint_event);
state->sigint_event = NULL;
}
#endif
Expand Down Expand Up @@ -2009,7 +1968,7 @@ _PySignal_Init(int install_signal_handlers)

#ifdef MS_WINDOWS
/* Create manual-reset event, initially unset */
state->sigint_event = CreateEvent(NULL, TRUE, FALSE, FALSE);
state->sigint_event = (void *)CreateEvent(NULL, TRUE, FALSE, FALSE);
if (state->sigint_event == NULL) {
PyErr_SetFromWindowsErr(0);
return -1;
Expand Down
1 change: 0 additions & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ extern void _PyIO_Fini(void);

#ifdef MS_WINDOWS
# undef BYTE
# include "windows.h"

extern PyTypeObject PyWindowsConsoleIO_Type;
# define PyWindowsConsoleIO_Check(op) \
Expand Down
8 changes: 1 addition & 7 deletions Tools/c-analyzer/cpython/globals-to-fix.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -365,13 +365,7 @@ Modules/itertoolsmodule.c - ziplongest_type -
##################################
## global non-objects to fix in builtin modules

##-----------------------
## state

Modules/signalmodule.c - is_tripped -
Modules/signalmodule.c - signal_global_state -
Modules/signalmodule.c - wakeup -
Modules/signalmodule.c - Handlers -
# <none>


##################################
Expand Down