##// END OF EJS Templates
SIGINT fixing for twshell
Ville M. Vainio -
Show More
@@ -0,0 +1,82 b''
1 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
2
3 import thread,inspect
4
5 try:
6 import ctypes
7 HAS_CTYPES = True
8 except ImportError:
9 HAS_CTYPES = False
10
11
12 # Globals
13 # global flag to pass around information about Ctrl-C without exceptions
14 KBINT = False
15
16 # global flag to turn on/off Tk support.
17 USE_TK = False
18
19 # ID for the main thread, used for cross-thread exceptions
20 MAIN_THREAD_ID = thread.get_ident()
21
22 # Tag when runcode() is active, for exception handling
23 CODE_RUN = None
24
25
26 #-----------------------------------------------------------------------------
27 # This class is trivial now, but I want to have it in to publish a clean
28 # interface. Later when the internals are reorganized, code that uses this
29 # shouldn't have to change.
30
31
32 if HAS_CTYPES:
33 # Add async exception support. Trick taken from:
34 # http://sebulba.wikispaces.com/recipe+thread2
35 def _async_raise(tid, exctype):
36 """raises the exception, performs cleanup if needed"""
37 if not inspect.isclass(exctype):
38 raise TypeError("Only types can be raised (not instances)")
39 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
40 ctypes.py_object(exctype))
41 if res == 0:
42 raise ValueError("invalid thread id")
43 elif res != 1:
44 # """if it returns a number greater than one, you're in trouble,
45 # and you should call it again with exc=NULL to revert the effect"""
46 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
47 raise SystemError("PyThreadState_SetAsyncExc failed")
48
49 def sigint_handler (signum,stack_frame):
50 """Sigint handler for threaded apps.
51
52 This is a horrible hack to pass information about SIGINT _without_
53 using exceptions, since I haven't been able to properly manage
54 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
55 done (or at least that's my understanding from a c.l.py thread where
56 this was discussed)."""
57
58 global KBINT
59
60 if CODE_RUN:
61 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
62 else:
63 KBINT = True
64 print '\nKeyboardInterrupt - Press <Enter> to continue.',
65 Term.cout.flush()
66
67 else:
68 def sigint_handler (signum,stack_frame):
69 """Sigint handler for threaded apps.
70
71 This is a horrible hack to pass information about SIGINT _without_
72 using exceptions, since I haven't been able to properly manage
73 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
74 done (or at least that's my understanding from a c.l.py thread where
75 this was discussed)."""
76
77 global KBINT
78
79 print '\nKeyboardInterrupt - Press <Enter> to continue.',
80 Term.cout.flush()
81 # Set global flag so that runsource can know that Ctrl-C was hit
82 KBINT = True
@@ -12,10 +12,10 b' from IPython.ipmaker import make_IPython'
12 from IPython.iplib import InteractiveShell
12 from IPython.iplib import InteractiveShell
13 from IPython.ipstruct import Struct
13 from IPython.ipstruct import Struct
14 import Queue,thread,threading,signal
14 import Queue,thread,threading,signal
15
16 from IPython.Shell import *
17
18 from signal import signal, SIGINT
15 from signal import signal, SIGINT
16 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
17 import shellglobals
18
19
19
20 def hijack_reactor():
20 def hijack_reactor():
21 """Modifies Twisted's reactor with a dummy so user code does
21 """Modifies Twisted's reactor with a dummy so user code does
@@ -81,12 +81,9 b' class TwistedInteractiveShell(InteractiveShell):'
81 Modified version of code.py's runsource(), to handle threading issues.
81 Modified version of code.py's runsource(), to handle threading issues.
82 See the original for full docstring details."""
82 See the original for full docstring details."""
83
83
84 print "rs"
85 global KBINT
86
87 # If Ctrl-C was typed, we reset the flag and return right away
84 # If Ctrl-C was typed, we reset the flag and return right away
88 if KBINT:
85 if shellglobals.KBINT:
89 KBINT = False
86 shellglobals.KBINT = False
90 return False
87 return False
91
88
92 if self._kill:
89 if self._kill:
@@ -113,7 +110,6 b' class TwistedInteractiveShell(InteractiveShell):'
113 InteractiveShell.runcode(self,code)
110 InteractiveShell.runcode(self,code)
114 return
111 return
115
112
116 self.first_run = False
117 # Case 3
113 # Case 3
118 # Store code in queue, so the execution thread can handle it.
114 # Store code in queue, so the execution thread can handle it.
119
115
@@ -130,6 +126,7 b' class TwistedInteractiveShell(InteractiveShell):'
130 print "switching to nonthreaded mode (until mainloop wakes up again)"
126 print "switching to nonthreaded mode (until mainloop wakes up again)"
131 self.worker_ident = None
127 self.worker_ident = None
132 else:
128 else:
129 shellglobals.CURRENT_COMPLETE_EV = completed_ev
133 completed_ev.wait()
130 completed_ev.wait()
134
131
135 return False
132 return False
@@ -139,7 +136,6 b' class TwistedInteractiveShell(InteractiveShell):'
139
136
140 Multithreaded wrapper around IPython's runcode()."""
137 Multithreaded wrapper around IPython's runcode()."""
141
138
142 global CODE_RUN
143
139
144 # we are in worker thread, stash out the id for runsource()
140 # we are in worker thread, stash out the id for runsource()
145 self.worker_ident = thread.get_ident()
141 self.worker_ident = thread.get_ident()
@@ -154,10 +150,11 b' class TwistedInteractiveShell(InteractiveShell):'
154 self._kill.set()
150 self._kill.set()
155 return True
151 return True
156
152
157 # Install sigint handler. We do it every time to ensure that if user
153 # Install SIGINT handler. We do it every time to ensure that if user
158 # code modifies it, we restore our own handling.
154 # code modifies it, we restore our own handling.
159 try:
155 try:
160 signal(SIGINT,sigint_handler)
156 pass
157 signal(SIGINT,shellglobals.sigint_handler)
161 except SystemError:
158 except SystemError:
162 # This happens under Windows, which seems to have all sorts
159 # This happens under Windows, which seems to have all sorts
163 # of problems with signal handling. Oh well...
160 # of problems with signal handling. Oh well...
@@ -176,13 +173,13 b' class TwistedInteractiveShell(InteractiveShell):'
176
173
177 # Exceptions need to be raised differently depending on which
174 # Exceptions need to be raised differently depending on which
178 # thread is active. This convoluted try/except is only there to
175 # thread is active. This convoluted try/except is only there to
179 # protect against asynchronous exceptions, to ensure that a KBINT
176 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
180 # at the wrong time doesn't deadlock everything. The global
177 # at the wrong time doesn't deadlock everything. The global
181 # CODE_TO_RUN is set to true/false as close as possible to the
178 # CODE_TO_RUN is set to true/false as close as possible to the
182 # runcode() call, so that the KBINT handler is correctly informed.
179 # runcode() call, so that the KBINT handler is correctly informed.
183 try:
180 try:
184 try:
181 try:
185 CODE_RUN = True
182 shellglobals.CODE_RUN = True
186 InteractiveShell.runcode(self,code_to_run)
183 InteractiveShell.runcode(self,code_to_run)
187 except KeyboardInterrupt:
184 except KeyboardInterrupt:
188 print "Keyboard interrupted in mainloop"
185 print "Keyboard interrupted in mainloop"
@@ -190,7 +187,7 b' class TwistedInteractiveShell(InteractiveShell):'
190 code = self.code_queue.get_nowait()
187 code = self.code_queue.get_nowait()
191 break
188 break
192 finally:
189 finally:
193 CODE_RUN = False
190 shellglobals.CODE_RUN = False
194 # allow runsource() return from wait
191 # allow runsource() return from wait
195 completed_ev.set()
192 completed_ev.set()
196
193
General Comments 0
You need to be logged in to leave comments. Login now