Commits
Click on a commit to change the comparison rangeHandle CPU limit exceeded in Python workers
If we call `TerminateExecution()`, it will exit Python execution without
unwinding the stack or cleaning up the runtime state. This leaves the
Python runtime in a permanently messed up state and all further requests
will fail.
This adds a new `cpuLimitNearlyExceededCallback` to the limit enforcer and
hooks it up so that it triggers a SIGINT inside of Python. This can be used
to raise a `CpuLimitExceeded` Python error into the runtime. If this error
is ignored, then we'll hit the hard limit and be terminated. If we ever do
call `TerminateExecution()` on a Python isolate, we should condemn the isolate,
but that is left as a TODO.
To trigger the SIGINT inside of Python, we have to set two addresses:
1. we set `emscripten_signal_clock` to `0` to make the Python eval breaker check
for a signal on the next tick.
2. we set `_Py_EMSCRIPTEN_SIGNAL_HANDLING` to 1 to make Python check the signal clock.
We also have to set `Module.Py_EmscriptenSignalBuffer` to a buffer with the number
of the signal we wish to trip in it (`SIGINT` aka 2).
When we start a request we set `_Py_EMSCRIPTEN_SIGNAL_HANDLING` to 0 to avoid
ongoing costs of calling out to JavaScript to check the buffer when no signal is set,
and we put a 2 into `Py_EmscriptenSignalBuffer`.
The most annoying aspect of this is that the symbol `emscripten_signal_clock` is not
exported. For Pyodide 0.28.2, I manually located the address of this symbol and hard
coded it. For the next Pyodide, we'll make sure to export it.