##// 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 12 from IPython.iplib import InteractiveShell
13 13 from IPython.ipstruct import Struct
14 14 import Queue,thread,threading,signal
15
16 from IPython.Shell import *
17
18 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 20 def hijack_reactor():
21 21 """Modifies Twisted's reactor with a dummy so user code does
@@ -81,12 +81,9 b' class TwistedInteractiveShell(InteractiveShell):'
81 81 Modified version of code.py's runsource(), to handle threading issues.
82 82 See the original for full docstring details."""
83 83
84 print "rs"
85 global KBINT
86
87 84 # If Ctrl-C was typed, we reset the flag and return right away
88 if KBINT:
89 KBINT = False
85 if shellglobals.KBINT:
86 shellglobals.KBINT = False
90 87 return False
91 88
92 89 if self._kill:
@@ -113,7 +110,6 b' class TwistedInteractiveShell(InteractiveShell):'
113 110 InteractiveShell.runcode(self,code)
114 111 return
115 112
116 self.first_run = False
117 113 # Case 3
118 114 # Store code in queue, so the execution thread can handle it.
119 115
@@ -130,6 +126,7 b' class TwistedInteractiveShell(InteractiveShell):'
130 126 print "switching to nonthreaded mode (until mainloop wakes up again)"
131 127 self.worker_ident = None
132 128 else:
129 shellglobals.CURRENT_COMPLETE_EV = completed_ev
133 130 completed_ev.wait()
134 131
135 132 return False
@@ -139,7 +136,6 b' class TwistedInteractiveShell(InteractiveShell):'
139 136
140 137 Multithreaded wrapper around IPython's runcode()."""
141 138
142 global CODE_RUN
143 139
144 140 # we are in worker thread, stash out the id for runsource()
145 141 self.worker_ident = thread.get_ident()
@@ -154,10 +150,11 b' class TwistedInteractiveShell(InteractiveShell):'
154 150 self._kill.set()
155 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 154 # code modifies it, we restore our own handling.
159 155 try:
160 signal(SIGINT,sigint_handler)
156 pass
157 signal(SIGINT,shellglobals.sigint_handler)
161 158 except SystemError:
162 159 # This happens under Windows, which seems to have all sorts
163 160 # of problems with signal handling. Oh well...
@@ -176,13 +173,13 b' class TwistedInteractiveShell(InteractiveShell):'
176 173
177 174 # Exceptions need to be raised differently depending on which
178 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 177 # at the wrong time doesn't deadlock everything. The global
181 178 # CODE_TO_RUN is set to true/false as close as possible to the
182 179 # runcode() call, so that the KBINT handler is correctly informed.
183 180 try:
184 181 try:
185 CODE_RUN = True
182 shellglobals.CODE_RUN = True
186 183 InteractiveShell.runcode(self,code_to_run)
187 184 except KeyboardInterrupt:
188 185 print "Keyboard interrupted in mainloop"
@@ -190,7 +187,7 b' class TwistedInteractiveShell(InteractiveShell):'
190 187 code = self.code_queue.get_nowait()
191 188 break
192 189 finally:
193 CODE_RUN = False
190 shellglobals.CODE_RUN = False
194 191 # allow runsource() return from wait
195 192 completed_ev.set()
196 193
General Comments 0
You need to be logged in to leave comments. Login now