##// END OF EJS Templates
handle different pointer size on x64 Windows...
Min Ragan-Kelley -
Show More
@@ -1,119 +1,127 b''
1 1 # Standard library imports.
2 2 import ctypes
3 3 import os
4 import platform
4 5 import time
5 6 from thread import interrupt_main
6 7 from threading import Thread
7 8
8 9
9 10 class ParentPollerUnix(Thread):
10 11 """ A Unix-specific daemon thread that terminates the program immediately
11 12 when the parent process no longer exists.
12 13 """
13 14
14 15 def __init__(self):
15 16 super(ParentPollerUnix, self).__init__()
16 17 self.daemon = True
17 18
18 19 def run(self):
19 20 # We cannot use os.waitpid because it works only for child processes.
20 21 from errno import EINTR
21 22 while True:
22 23 try:
23 24 if os.getppid() == 1:
24 25 os._exit(1)
25 26 time.sleep(1.0)
26 27 except OSError, e:
27 28 if e.errno == EINTR:
28 29 continue
29 30 raise
30 31
31 32
32 33 class ParentPollerWindows(Thread):
33 34 """ A Windows-specific daemon thread that listens for a special event that
34 35 signals an interrupt and, optionally, terminates the program immediately
35 36 when the parent process no longer exists.
36 37 """
37 38
38 39 def __init__(self, interrupt_handle=None, parent_handle=None):
39 40 """ Create the poller. At least one of the optional parameters must be
40 41 provided.
41 42
42 43 Parameters:
43 44 -----------
44 45 interrupt_handle : HANDLE (int), optional
45 46 If provided, the program will generate a Ctrl+C event when this
46 47 handle is signaled.
47 48
48 49 parent_handle : HANDLE (int), optional
49 50 If provided, the program will terminate immediately when this
50 51 handle is signaled.
51 52 """
52 53 assert(interrupt_handle or parent_handle)
53 54 super(ParentPollerWindows, self).__init__()
54 55 self.daemon = True
55 56 self.interrupt_handle = interrupt_handle
56 57 self.parent_handle = parent_handle
57 58
58 59 @staticmethod
59 60 def create_interrupt_event():
60 61 """ Create an interrupt event handle.
61 62
62 63 The parent process should use this static method for creating the
63 64 interrupt event that is passed to the child process. It should store
64 65 this handle and use it with ``send_interrupt`` to interrupt the child
65 66 process.
66 67 """
67 68 # Create a security attributes struct that permits inheritance of the
68 69 # handle by new processes.
69 70 # FIXME: We can clean up this mess by requiring pywin32 for IPython.
70 71 class SECURITY_ATTRIBUTES(ctypes.Structure):
71 72 _fields_ = [ ("nLength", ctypes.c_int),
72 73 ("lpSecurityDescriptor", ctypes.c_void_p),
73 74 ("bInheritHandle", ctypes.c_int) ]
74 75 sa = SECURITY_ATTRIBUTES()
75 76 sa_p = ctypes.pointer(sa)
76 77 sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES)
77 78 sa.lpSecurityDescriptor = 0
78 79 sa.bInheritHandle = 1
79 80
80 81 return ctypes.windll.kernel32.CreateEventA(
81 82 sa_p, # lpEventAttributes
82 83 False, # bManualReset
83 84 False, # bInitialState
84 85 '') # lpName
85 86
86 87 @staticmethod
87 88 def send_interrupt(interrupt_handle):
88 89 """ Sends an interrupt event using the specified handle.
89 90 """
90 91 ctypes.windll.kernel32.SetEvent(interrupt_handle)
91 92
92 93 def run(self):
93 94 """ Run the poll loop. This method never returns.
94 95 """
95 96 from _subprocess import WAIT_OBJECT_0, INFINITE
96 97
97 98 # Build the list of handle to listen on.
98 99 handles = []
99 100 if self.interrupt_handle:
100 101 handles.append(self.interrupt_handle)
101 102 if self.parent_handle:
102 103 handles.append(self.parent_handle)
104 arch = platform.architecture()[0]
105 c_int = ctypes.c_int64 if arch.startswith('64') else ctypes.c_int
103 106
104 107 # Listen forever.
105 108 while True:
106 109 result = ctypes.windll.kernel32.WaitForMultipleObjects(
107 110 len(handles), # nCount
108 (ctypes.c_int * len(handles))(*handles), # lpHandles
111 (c_int * len(handles))(*handles), # lpHandles
109 112 False, # bWaitAll
110 113 INFINITE) # dwMilliseconds
111 114
112 115 if WAIT_OBJECT_0 <= result < len(handles):
113 116 handle = handles[result - WAIT_OBJECT_0]
114 117
115 118 if handle == self.interrupt_handle:
116 119 interrupt_main()
117 120
118 121 elif handle == self.parent_handle:
119 122 os._exit(1)
123 elif result < 0:
124 # wait failed, but don't let this throttle CPU
125 # if this is going to repeat, perhaps we should
126 # just give up and return.
127 time.sleep(.1)
General Comments 0
You need to be logged in to leave comments. Login now