]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-47176: Interrupt handling for wasm32-emscripten builds without pthreads (GH-32209)
authorHood Chatham <roberthoodchatham@gmail.com>
Sun, 3 Apr 2022 20:58:52 +0000 (13:58 -0700)
committerGitHub <noreply@github.com>
Sun, 3 Apr 2022 20:58:52 +0000 (22:58 +0200)
Co-authored-by: Christian Heimes <christian@python.org>
Co-authored-by: Brett Cannon <brett@python.org>
Include/internal/pycore_emscripten_signal.h [new file with mode: 0644]
Makefile.pre.in
Misc/NEWS.d/next/Core and Builtins/2022-04-02-14-32-21.bpo-47176.kTygYI.rst [new file with mode: 0644]
Modules/signalmodule.c
Python/ceval.c
Python/emscripten_signal.c [new file with mode: 0644]
configure
configure.ac

diff --git a/Include/internal/pycore_emscripten_signal.h b/Include/internal/pycore_emscripten_signal.h
new file mode 100644 (file)
index 0000000..8b3287d
--- /dev/null
@@ -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
index 5318a41dc857a238eaab8b7cdc003ccfac5102e2..f94ba93cff91ccf0c4c0ac04b2830a13762b26ed 100644 (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
 
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 (file)
index 0000000..03fe54a
--- /dev/null
@@ -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.
index 9566263a0dd87e887d49d9571e5e3d78a3c61de2..1ee5c669df015f158121f7e633263fe9708027b6 100644 (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;
     }
index 43080f8db04226636f49458375217a68caea377d..68d2920727ab04f3eec7d02ff0ebf6f3ee62a40f 100644 (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; \
     }
diff --git a/Python/emscripten_signal.c b/Python/emscripten_signal.c
new file mode 100644 (file)
index 0000000..d617ddf
--- /dev/null
@@ -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();
+    }
+}
index a5062d7b81573732b6de9657f7f1f16ca412b73d..bb1aa7568233d5e83ca373d261cf7029f27ae471 100755 (executable)
--- 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=.
index 84bc9b3ca5cf04fb44e1868a6995dc1a4b35cfca..9f0a50ec852b6482994cfc6ea040d8bc5492a61e 100644 (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=.