Skip to content

Commit

Permalink
Add support for kernel interrupts
Browse files Browse the repository at this point in the history
The trio runner didn't support kernel interrupts: it would just continue
to hang. I'm not sure why, but kernelapp.py ignores SIGINT. So in this
commit, the Trio runner registers a new SIGINT handler that uses Trio
cancel scopes to cancel the currently executing cell.

The downside to this approach is that if a cell hangs in a loop that
never reaches a Trio checkpoint, then the cancellation will have no
effect. We could have sent SIGINT to the main thread (i.e. SIG_DFL), but
that would have the effect of potentially raising SIGINT on one of the
background tasks, which would likely force you to restart the kernel.
  • Loading branch information
mehaase committed Jan 31, 2020
1 parent 9c246c8 commit 3bb1bf5
Showing 1 changed file with 15 additions and 5 deletions.
20 changes: 15 additions & 5 deletions ipykernel/trio_runner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import builtins
import logging
import signal
import threading
import traceback
import warnings
Expand All @@ -9,6 +10,7 @@

class TrioRunner:
def __init__(self):
self._cell_cancel_scope = None
self._trio_token = None

def initialize(self, kernel, io_loop):
Expand All @@ -21,7 +23,15 @@ def initialize(self, kernel, io_loop):
name='TornadoBackground')
bg_thread.start()

def interrupt(self, signum, frame):
if self._cell_cancel_scope:
self._cell_cancel_scope.cancel()
else:
raise Exception('Kernel interrupted but no cell is running')

def run(self):
old_sig = signal.signal(signal.SIGINT, self.interrupt)

def log_nursery_exc(exc):
exc = '\n'.join(traceback.format_exception(type(exc), exc,
exc.__traceback__))
Expand All @@ -38,13 +48,13 @@ async def trio_main():
await trio.sleep_forever()

trio.run(trio_main)
signal.signal(signal.SIGINT, old_sig)

def __call__(self, async_fn):
async def loc(coro):
"""
We need the dummy no-op async def to protect from
trio's internal. See https://github.com/python-trio/trio/issues/89
"""
return await coro
self._cell_cancel_scope = trio.CancelScope()
with self._cell_cancel_scope:
return await coro
self._cell_cancel_scope = None

return trio.from_thread.run(loc, async_fn, trio_token=self._trio_token)

0 comments on commit 3bb1bf5

Please sign in to comment.