[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