win_interrupt.py 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. """Use a Windows event to interrupt a child process like SIGINT.
  2. The child needs to explicitly listen for this - see
  3. ipykernel.parentpoller.ParentPollerWindows for a Python implementation.
  4. """
  5. import ctypes
  6. from typing import Any
  7. def create_interrupt_event() -> Any:
  8. """Create an interrupt event handle.
  9. The parent process should call this to create the
  10. interrupt event that is passed to the child process. It should store
  11. this handle and use it with ``send_interrupt`` to interrupt the child
  12. process.
  13. """
  14. # Create a security attributes struct that permits inheritance of the
  15. # handle by new processes.
  16. # FIXME: We can clean up this mess by requiring pywin32 for IPython.
  17. class SECURITY_ATTRIBUTES(ctypes.Structure): # noqa
  18. _fields_ = [
  19. ("nLength", ctypes.c_int),
  20. ("lpSecurityDescriptor", ctypes.c_void_p),
  21. ("bInheritHandle", ctypes.c_int),
  22. ]
  23. sa = SECURITY_ATTRIBUTES()
  24. sa_p = ctypes.pointer(sa)
  25. sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES)
  26. sa.lpSecurityDescriptor = 0
  27. sa.bInheritHandle = 1
  28. return ctypes.windll.kernel32.CreateEventA( # type:ignore[attr-defined]
  29. sa_p,
  30. False,
  31. False,
  32. "", # lpEventAttributes # bManualReset # bInitialState
  33. ) # lpName
  34. def send_interrupt(interrupt_handle: Any) -> None:
  35. """Sends an interrupt event using the specified handle."""
  36. ctypes.windll.kernel32.SetEvent(interrupt_handle) # type:ignore[attr-defined]