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