Skip to content

Conversation

@ptosco
Copy link

@ptosco ptosco commented Sep 20, 2025

Currently, a long-running C Python module executed on Windows in a Jupyter kernel can only be interrupted by sending twice the "Interrupt kernel" signal.
This happens because the first interrupt signal is intercepted by ipykernel/parentpoller.py and as it is set to auto-reset, it will not reach a C Python module listening for the same signal. At the time, the interrupt_main() call scheduled by ipykernel/parentpoller.py will not be executed as the main Python thread is blocked by the long-running C Python module.
Only when the "Interrupt kernel" is issued again the C Python module will be interrupted.

This PR sets the CreateEvent bManualReset Boolean flag to true, thus requiring the interrupt event to be manually reset by the receiver. This makes it possible for a listening C Python module to be reached by the signal and hence be interrupted, without requiring the interrupt signal to be issued twice.

This can be conveniently tested through the attached waitloop test Python module, which can be installed on all platforms supported by Jupyter by unzipping waitloop_module.zip and then running pip install . in the waitloop_module directory:

Python interpreter - all platforms

>>> import waitloop
>>> waitloop.run()

[Press CTRL+C on your keyboard to interrupt the loop]

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyboardInterrupt

Jupyter notebook - Windows platform

[1]: import waitloop

[2]: waitloop.run()

[Issue Kernel->Interrupt kernel once - waitloop keeps running]
[Issue Kernel->Interrupt kernel again - waitloop stops running]

Jupyter notebook - non-Windows platforms

[1]: import waitloop

[2]: waitloop.run()

[Issue Kernel->Interrupt kernel once - waitloop stops running]

WIth the current Jupyter version, on Windows it is necessary to issue "Interrupt kernel" twice to interrupt waitloop, whereas on non-Windows platforms it is sufficient to issue the command once,

After merging this PR and the sister PR #1434 in the ipykernel repo, a single "Interrupt kernel" will stop waitloop also on Windows, as expected.

@minrk
Copy link
Member

minrk commented Oct 15, 2025

@ptosco thanks, this is awesome to have this potentially fixed after so long! Can you share more about the relationship of the two PRs (i.e. does one need the other, or are they independent, or will things be okay to have one or the other patches in place, just not fully fixed unless you have both)? I mainly want to understand if we need to update any dependencies, or if there are any negative consequences for other implementations that aren't jupyter-client or kernels that aren't ipykernel that won't have these changes.

@ptosco
Copy link
Author

ptosco commented Oct 17, 2025

@minrk Thanks for your comment; I have addressed your concern, which I also had, by conditionally setting the bManualReset flag to True only if ipykernel.parentpoller.ParentPollerWindows implementes the reset_event method; otherwise it sets to False as it previously happened.
ipykernel.parentpoller.ParentPollerWindows does not need a similar check as resetting the event is harmless if the even was already set to auto-reset itself.

@minrk
Copy link
Member

minrk commented Oct 18, 2025

Thanks! Sorry, I think I might have given the wrong impression. I don't think we should be checking ipykernel inside the Jupyter-client process. There's every chance ipykernel is not in the same env, or it is and the kernel isn't ipykernel, or it is ipykernel and a different version from what's in the client's env.

I only wanted to know: what are the consequences when:

  1. Jupyter-client has this patch, but the kernel does not (ipykernel is not the only kernel). What happens here?
  2. the kernel has the patch, but the client does not (jupyter_client is not the only kernel launcher) (answered, no negative consequences)

We can decide how to address it with that information, but it is not knowable from within the client process. What I don't know right now is what will actually happen in case 1, so I don't yet know what to suggest we do. If it's not safe, we need to have a plan for discovering this support from the kernelspec, because Python APIs can't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants