Show More
@@ -0,0 +1,39 b'' | |||||
|
1 | """Use a Windows event to interrupt a child process like SIGINT. | |||
|
2 | ||||
|
3 | The child needs to explicitly listen for this - see | |||
|
4 | ipython_kernel.parentpoller.ParentPollerWindows for a Python implementation. | |||
|
5 | """ | |||
|
6 | ||||
|
7 | import ctypes | |||
|
8 | ||||
|
9 | def create_interrupt_event(): | |||
|
10 | """Create an interrupt event handle. | |||
|
11 | ||||
|
12 | The parent process should call this to create the | |||
|
13 | interrupt event that is passed to the child process. It should store | |||
|
14 | this handle and use it with ``send_interrupt`` to interrupt the child | |||
|
15 | process. | |||
|
16 | """ | |||
|
17 | # Create a security attributes struct that permits inheritance of the | |||
|
18 | # handle by new processes. | |||
|
19 | # FIXME: We can clean up this mess by requiring pywin32 for IPython. | |||
|
20 | class SECURITY_ATTRIBUTES(ctypes.Structure): | |||
|
21 | _fields_ = [ ("nLength", ctypes.c_int), | |||
|
22 | ("lpSecurityDescriptor", ctypes.c_void_p), | |||
|
23 | ("bInheritHandle", ctypes.c_int) ] | |||
|
24 | sa = SECURITY_ATTRIBUTES() | |||
|
25 | sa_p = ctypes.pointer(sa) | |||
|
26 | sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES) | |||
|
27 | sa.lpSecurityDescriptor = 0 | |||
|
28 | sa.bInheritHandle = 1 | |||
|
29 | ||||
|
30 | return ctypes.windll.kernel32.CreateEventA( | |||
|
31 | sa_p, # lpEventAttributes | |||
|
32 | False, # bManualReset | |||
|
33 | False, # bInitialState | |||
|
34 | '') # lpName | |||
|
35 | ||||
|
36 | def send_interrupt(interrupt_handle): | |||
|
37 | """ Sends an interrupt event using the specified handle. | |||
|
38 | """ | |||
|
39 | ctypes.windll.kernel32.SetEvent(interrupt_handle) |
@@ -69,40 +69,6 b' class ParentPollerWindows(Thread):' | |||||
69 | self.interrupt_handle = interrupt_handle |
|
69 | self.interrupt_handle = interrupt_handle | |
70 | self.parent_handle = parent_handle |
|
70 | self.parent_handle = parent_handle | |
71 |
|
71 | |||
72 | @staticmethod |
|
|||
73 | def create_interrupt_event(): |
|
|||
74 | """ Create an interrupt event handle. |
|
|||
75 |
|
||||
76 | The parent process should use this static method for creating the |
|
|||
77 | interrupt event that is passed to the child process. It should store |
|
|||
78 | this handle and use it with ``send_interrupt`` to interrupt the child |
|
|||
79 | process. |
|
|||
80 | """ |
|
|||
81 | # Create a security attributes struct that permits inheritance of the |
|
|||
82 | # handle by new processes. |
|
|||
83 | # FIXME: We can clean up this mess by requiring pywin32 for IPython. |
|
|||
84 | class SECURITY_ATTRIBUTES(ctypes.Structure): |
|
|||
85 | _fields_ = [ ("nLength", ctypes.c_int), |
|
|||
86 | ("lpSecurityDescriptor", ctypes.c_void_p), |
|
|||
87 | ("bInheritHandle", ctypes.c_int) ] |
|
|||
88 | sa = SECURITY_ATTRIBUTES() |
|
|||
89 | sa_p = ctypes.pointer(sa) |
|
|||
90 | sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES) |
|
|||
91 | sa.lpSecurityDescriptor = 0 |
|
|||
92 | sa.bInheritHandle = 1 |
|
|||
93 |
|
||||
94 | return ctypes.windll.kernel32.CreateEventA( |
|
|||
95 | sa_p, # lpEventAttributes |
|
|||
96 | False, # bManualReset |
|
|||
97 | False, # bInitialState |
|
|||
98 | '') # lpName |
|
|||
99 |
|
||||
100 | @staticmethod |
|
|||
101 | def send_interrupt(interrupt_handle): |
|
|||
102 | """ Sends an interrupt event using the specified handle. |
|
|||
103 | """ |
|
|||
104 | ctypes.windll.kernel32.SetEvent(interrupt_handle) |
|
|||
105 |
|
||||
106 | def run(self): |
|
72 | def run(self): | |
107 | """ Run the poll loop. This method never returns. |
|
73 | """ Run the poll loop. This method never returns. | |
108 | """ |
|
74 | """ |
@@ -175,10 +175,10 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,' | |||||
175 | cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii') |
|
175 | cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii') | |
176 | kwargs['cwd'] = cwd |
|
176 | kwargs['cwd'] = cwd | |
177 |
|
177 | |||
178 | from jupyter_client.parentpoller import ParentPollerWindows |
|
178 | from .win_interrupt import create_interrupt_event | |
179 | # Create a Win32 event for interrupting the kernel |
|
179 | # Create a Win32 event for interrupting the kernel | |
180 | # and store it in an environment variable. |
|
180 | # and store it in an environment variable. | |
181 |
interrupt_event = |
|
181 | interrupt_event = create_interrupt_event() | |
182 | env["JPY_INTERRUPT_EVENT"] = str(interrupt_event) |
|
182 | env["JPY_INTERRUPT_EVENT"] = str(interrupt_event) | |
183 | # deprecated old env name: |
|
183 | # deprecated old env name: | |
184 | env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"] |
|
184 | env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"] |
@@ -381,8 +381,8 b' class KernelManager(ConnectionFileMixin):' | |||||
381 | """ |
|
381 | """ | |
382 | if self.has_kernel: |
|
382 | if self.has_kernel: | |
383 | if sys.platform == 'win32': |
|
383 | if sys.platform == 'win32': | |
384 |
from . |
|
384 | from .win_interrupt import send_interrupt | |
385 |
|
|
385 | send_interrupt(self.kernel.win32_interrupt_event) | |
386 | else: |
|
386 | else: | |
387 | self.kernel.send_signal(signal.SIGINT) |
|
387 | self.kernel.send_signal(signal.SIGINT) | |
388 | else: |
|
388 | else: |
General Comments 0
You need to be logged in to leave comments.
Login now