[Python-checkins] bpo-47176: Interrupt handling for wasm32-emscripten builds without pthreads (GH-32209)
tiran
webhook-mailer at python.org
Sun Apr 3 16:59:24 EDT 2022
https://github.com/python/cpython/commit/087d0fa5b97796560c0d8ceab4f0360fd54baf4f
commit: 087d0fa5b97796560c0d8ceab4f0360fd54baf4f
branch: main
author: Hood Chatham <roberthoodchatham at gmail.com>
committer: tiran <christian at python.org>
date: 2022-04-03T22:58:52+02:00
summary:
bpo-47176: Interrupt handling for wasm32-emscripten builds without pthreads (GH-32209)
Co-authored-by: Christian Heimes <christian at python.org>
Co-authored-by: Brett Cannon <brett at python.org>
files:
A Include/internal/pycore_emscripten_signal.h
A Misc/NEWS.d/next/Core and Builtins/2022-04-02-14-32-21.bpo-47176.kTygYI.rst
A Python/emscripten_signal.c
M Makefile.pre.in
M Modules/signalmodule.c
M Python/ceval.c
M configure
M configure.ac
diff --git a/Include/internal/pycore_emscripten_signal.h b/Include/internal/pycore_emscripten_signal.h
new file mode 100644
index 0000000000000..8b3287d85da4b
--- /dev/null
+++ b/Include/internal/pycore_emscripten_signal.h
@@ -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
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 5318a41dc857a..f94ba93cff91c 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -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
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-02-14-32-21.bpo-47176.kTygYI.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-02-14-32-21.bpo-47176.kTygYI.rst
new file mode 100644
index 0000000000000..03fe54a372552
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-04-02-14-32-21.bpo-47176.kTygYI.rst
@@ -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.
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 9566263a0dd87..1ee5c669df015 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -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;
}
diff --git a/Python/ceval.c b/Python/ceval.c
index 43080f8db0422..68d2920727ab0 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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; \
}
diff --git a/Python/emscripten_signal.c b/Python/emscripten_signal.c
new file mode 100644
index 0000000000000..d617ddfeb37c5
--- /dev/null
+++ b/Python/emscripten_signal.c
@@ -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();
+ }
+}
diff --git a/configure b/configure
index a5062d7b81573..bb1aa7568233d 100755
--- a/configure
+++ b/configure
@@ -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=.
diff --git a/configure.ac b/configure.ac
index 84bc9b3ca5cf0..9f0a50ec852b6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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=.
More information about the Python-checkins
mailing list