bpo-47176: Interrupt handling for wasm32-emscripten builds without pthreads (GH-32209)

Co-authored-by: Christian Heimes <christian@python.org>
Co-authored-by: Brett Cannon <brett@python.org>
This commit is contained in:
Hood Chatham 2022-04-03 13:58:52 -07:00 committed by GitHub
parent bdc4974965
commit 087d0fa5b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 124 additions and 1 deletions

View File

@ -0,0 +1,25 @@
#ifndef Py_EMSCRIPTEN_SIGNAL_H
#define Py_EMSCRIPTEN_SIGNAL_H
#if defined(__EMSCRIPTEN__)
void
_Py_CheckEmscriptenSignals(void);
void
_Py_CheckEmscriptenSignalsPeriodically(void);
#define _Py_CHECK_EMSCRIPTEN_SIGNALS() _Py_CheckEmscriptenSignals()
#define _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY() _Py_CheckEmscriptenSignalsPeriodically()
extern int Py_EMSCRIPTEN_SIGNAL_HANDLING;
#else
#define _Py_CHECK_EMSCRIPTEN_SIGNALS()
#define _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY()
#endif // defined(__EMSCRIPTEN__)
#endif // ndef Py_EMSCRIPTEN_SIGNAL_H

View File

@ -429,7 +429,8 @@ PYTHON_OBJS= \
Python/$(DYNLOADFILE) \
$(LIBOBJS) \
$(MACHDEP_OBJS) \
$(DTRACE_OBJS)
$(DTRACE_OBJS) \
@PLATFORM_OBJS@
##########################################################################
@ -1608,6 +1609,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_unicodeobject.h \
$(srcdir)/Include/internal/pycore_warnings.h \
$(DTRACE_HEADERS) \
@PLATFORM_HEADERS@ \
\
$(srcdir)/Python/stdlib_module_names.h

View File

@ -0,0 +1,6 @@
Emscripten builds cannot handle signals in the usual way due to platform
limitations. Python can now handle signals. To use, set
Module.Py_EmscriptenSignalBuffer to be a single byte SharedArrayBuffer and
set Py_EMSCRIPTEN_SIGNAL_HANDLING to 1. Writing a number into the
SharedArrayBuffer will cause the corresponding signal to be raised into the
Python thread.

View File

@ -13,6 +13,7 @@
#include "pycore_pyerrors.h" // _PyErr_SetString()
#include "pycore_pylifecycle.h" // NSIG
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
#ifndef MS_WINDOWS
# include "posixmodule.h"
@ -1797,6 +1798,7 @@ PyErr_CheckSignals(void)
int
_PyErr_CheckSignalsTstate(PyThreadState *tstate)
{
_Py_CHECK_EMSCRIPTEN_SIGNALS();
if (!_Py_atomic_load(&is_tripped)) {
return 0;
}

View File

@ -21,6 +21,7 @@
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
#include "code.h"
#include "pycore_dict.h"
@ -1292,6 +1293,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
}
#define CHECK_EVAL_BREAKER() \
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \
if (_Py_atomic_load_relaxed(eval_breaker)) { \
goto handle_eval_breaker; \
}

View File

@ -0,0 +1,56 @@
// To enable signal handling, the embedder should:
// 1. set Module.Py_EmscriptenSignalBuffer = some_shared_array_buffer;
// 2. set the Py_EMSCRIPTEN_SIGNAL_HANDLING flag to 1 as follows:
// Module.HEAP8[Module._Py_EMSCRIPTEN_SIGNAL_HANDLING] = 1
//
// The address &Py_EMSCRIPTEN_SIGNAL_HANDLING is exported as
// Module._Py_EMSCRIPTEN_SIGNAL_HANDLING.
#include <emscripten.h>
#include "Python.h"
EM_JS(int, _Py_CheckEmscriptenSignals_Helper, (void), {
if (!Module.Py_EmscriptenSignalBuffer) {
return 0;
}
try {
let result = Module.Py_EmscriptenSignalBuffer[0];
Module.Py_EmscriptenSignalBuffer[0] = 0;
return result;
} catch(e) {
#if !defined(NDEBUG)
console.warn("Error occurred while trying to read signal buffer:", e);
#endif
return 0;
}
});
EMSCRIPTEN_KEEPALIVE int Py_EMSCRIPTEN_SIGNAL_HANDLING = 0;
void
_Py_CheckEmscriptenSignals(void)
{
if (!Py_EMSCRIPTEN_SIGNAL_HANDLING) {
return;
}
int signal = _Py_CheckEmscriptenSignals_Helper();
if (signal) {
PyErr_SetInterruptEx(signal);
}
}
#define PY_EMSCRIPTEN_SIGNAL_INTERVAL 50
static int emscripten_signal_clock = PY_EMSCRIPTEN_SIGNAL_INTERVAL;
void
_Py_CheckEmscriptenSignalsPeriodically(void)
{
if (!Py_EMSCRIPTEN_SIGNAL_HANDLING) {
return;
}
emscripten_signal_clock--;
if (emscripten_signal_clock == 0) {
emscripten_signal_clock = PY_EMSCRIPTEN_SIGNAL_INTERVAL;
_Py_CheckEmscriptenSignals();
}
}

17
configure generated vendored
View File

@ -817,6 +817,8 @@ TRUE
MACHDEP_OBJS
DYNLOADFILE
DLINCLDIR
PLATFORM_OBJS
PLATFORM_HEADERS
DTRACE_OBJS
DTRACE_HEADERS
DFLAGS
@ -13993,6 +13995,21 @@ $as_echo "$ac_cv_dtrace_link" >&6; }
fi
fi
PLATFORM_HEADERS=
PLATFORM_OBJS=
case $ac_sys_system in #(
Emscripten) :
as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o'
as_fn_append PLATFORM_HEADERS ' $(srcdir)/Include/internal/pycore_emscripten_signal.h'
;; #(
*) :
;;
esac
# -I${DLINCLDIR} is added to the compile rule for importdl.o
DLINCLDIR=.

View File

@ -4187,6 +4187,19 @@ then
fi
fi
dnl Platform-specific C and header files.
PLATFORM_HEADERS=
PLATFORM_OBJS=
AS_CASE([$ac_sys_system],
[Emscripten], [
AS_VAR_APPEND([PLATFORM_OBJS], [' Python/emscripten_signal.o'])
AS_VAR_APPEND([PLATFORM_HEADERS], [' $(srcdir)/Include/internal/pycore_emscripten_signal.h'])
],
)
AC_SUBST([PLATFORM_HEADERS])
AC_SUBST([PLATFORM_OBJS])
# -I${DLINCLDIR} is added to the compile rule for importdl.o
AC_SUBST(DLINCLDIR)
DLINCLDIR=.