Skip to content

Commit

Permalink
gh-81057: Move Signal-Related Globals to _PyRuntimeState (gh-100085)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsnowcurrently authored Dec 12, 2022
1 parent 53d9cd9 commit 5eb28bc
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 69 deletions.
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

0 comments on commit 5eb28bc

Please sign in to comment.