Skip to content

Commit a08dbf7

Browse files
committed
Allow subinterpreters to handle signals.
1 parent d8fa40b commit a08dbf7

5 files changed

Lines changed: 19 additions & 5 deletions

File tree

Include/cpython/pylifecycle.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ typedef struct {
4747
int allow_daemon_threads;
4848
int check_multi_interp_extensions;
4949
int gil;
50+
int can_handle_signals;
5051
} PyInterpreterConfig;
5152

5253
#define _PyInterpreterConfig_INIT \
@@ -58,6 +59,7 @@ typedef struct {
5859
.allow_daemon_threads = 0, \
5960
.check_multi_interp_extensions = 1, \
6061
.gil = PyInterpreterConfig_OWN_GIL, \
62+
.can_handle_signals = 1, \
6163
}
6264

6365
// gh-117649: The free-threaded build does not currently support single-phase
@@ -78,6 +80,7 @@ typedef struct {
7880
.allow_daemon_threads = 1, \
7981
.check_multi_interp_extensions = _PyInterpreterConfig_LEGACY_CHECK_MULTI_INTERP_EXTENSIONS, \
8082
.gil = PyInterpreterConfig_SHARED_GIL, \
83+
.can_handle_signals = 0, \
8184
}
8285

8386
PyAPI_FUNC(PyStatus) Py_NewInterpreterFromConfig(

Include/internal/pycore_interp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ might not be allowed in the current interpreter (i.e. os.fork() would fail).
9393
/* Set if os.exec*() is allowed. */
9494
#define Py_RTFLAGS_EXEC (1UL << 16)
9595

96+
/* Set if signal handling is allowed. */
97+
#define Py_RTFLAGS_CAN_HANDLE_SIGNALS (1UL << 17)
98+
9699
extern int _PyInterpreterState_HasFeature(PyInterpreterState *interp,
97100
unsigned long feature);
98101

Include/internal/pycore_pystate.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern "C" {
1111
#include "pycore_pythonrun.h" // _PyOS_STACK_MARGIN_SHIFT
1212
#include "pycore_typedefs.h" // _PyRuntimeState
1313
#include "pycore_tstate.h"
14-
14+
#include "pycore_interp.h" // _PyInterpreterState_HasFeature
1515

1616
// Values for PyThreadState.state. A thread must be in the "attached" state
1717
// before calling most Python APIs. If the GIL is enabled, then "attached"
@@ -78,11 +78,12 @@ extern void _PyInterpreterState_ReinitRunningMain(PyThreadState *);
7878
extern const PyConfig* _Py_GetMainConfig(void);
7979

8080

81-
/* Only handle signals on the main thread of the main interpreter. */
81+
/* Only handle signals on the main thread of an interpreter that supports it. */
8282
static inline int
8383
_Py_ThreadCanHandleSignals(PyInterpreterState *interp)
8484
{
85-
return (_Py_IsMainThread() && _Py_IsMainInterpreter(interp));
85+
return (_Py_IsMainThread()
86+
&& _PyInterpreterState_HasFeature(interp, Py_RTFLAGS_CAN_HANDLE_SIGNALS));
8687
}
8788

8889

Python/interpconfig.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ _PyInterpreterConfig_AsDict(PyInterpreterConfig *config)
8787
ADD_BOOL(allow_threads);
8888
ADD_BOOL(allow_daemon_threads);
8989
ADD_BOOL(check_multi_interp_extensions);
90+
ADD_BOOL(can_handle_signals);
9091

9192
ADD_STR(gil, gil_flag_to_str(config->gil));
9293

@@ -182,6 +183,7 @@ interp_config_from_dict(PyObject *origdict, PyInterpreterConfig *config,
182183
COPY_BOOL(allow_threads);
183184
COPY_BOOL(allow_daemon_threads);
184185
COPY_BOOL(check_multi_interp_extensions);
186+
COPY_BOOL(can_handle_signals);
185187

186188
// PyInterpreterConfig.gil
187189
char buf[20];

Python/pylifecycle.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,10 @@ init_interp_settings(PyInterpreterState *interp,
566566
interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;
567567
}
568568

569+
if (config->can_handle_signals) {
570+
interp->feature_flags |= Py_RTFLAGS_CAN_HANDLE_SIGNALS;
571+
}
572+
569573
switch (config->gil) {
570574
case PyInterpreterConfig_DEFAULT_GIL: break;
571575
case PyInterpreterConfig_SHARED_GIL: break;
@@ -636,10 +640,11 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
636640
}
637641

638642
PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
639-
// The main interpreter always has its own GIL and supports single-phase
640-
// init extensions.
643+
// The main interpreter always has its own GIL, supports single-phase
644+
// init extensions, and can handle signals.
641645
config.gil = PyInterpreterConfig_OWN_GIL;
642646
config.check_multi_interp_extensions = 0;
647+
config.can_handle_signals = 1;
643648
status = init_interp_settings(interp, &config);
644649
if (_PyStatus_EXCEPTION(status)) {
645650
return status;

0 commit comments

Comments
 (0)