##// END OF EJS Templates
merge
ldufrechou -
r1092:801835c1 merge
parent child Browse files
Show More
@@ -8,7 +8,7 b' are at the bottom of the file, the rest is left untouched.'
8 Must be loaded with ip.load('ipy_bzr')
8 Must be loaded with ip.load('ipy_bzr')
9
9
10 """
10 """
11 a
11
12 # Copyright (C) 2004, 2005 Aaron Bentley
12 # Copyright (C) 2004, 2005 Aaron Bentley
13 # <aaron@aaronbentley.com>
13 # <aaron@aaronbentley.com>
14 #
14 #
@@ -358,18 +358,13 b' class MTInteractiveShell(InteractiveShell):'
358 InteractiveShell.__init__(self,name,usage,rc,user_ns,
358 InteractiveShell.__init__(self,name,usage,rc,user_ns,
359 user_global_ns,banner2)
359 user_global_ns,banner2)
360
360
361 # Locking control variable.
362 self.thread_ready = threading.Condition(threading.RLock())
363
361
364 # A queue to hold the code to be executed. A scalar variable is NOT
362 # A queue to hold the code to be executed.
365 # enough, because uses like macros cause reentrancy.
366 self.code_queue = Queue.Queue()
363 self.code_queue = Queue.Queue()
367
364
368 # Stuff to do at closing time
365 # Stuff to do at closing time
369 self._kill = False
366 self._kill = None
370 on_kill = kw.get('on_kill')
367 on_kill = kw.get('on_kill', [])
371 if on_kill is None:
372 on_kill = []
373 # Check that all things to kill are callable:
368 # Check that all things to kill are callable:
374 for t in on_kill:
369 for t in on_kill:
375 if not callable(t):
370 if not callable(t):
@@ -377,18 +372,23 b' class MTInteractiveShell(InteractiveShell):'
377 self.on_kill = on_kill
372 self.on_kill = on_kill
378 # thread identity of the "worker thread" (that may execute code directly)
373 # thread identity of the "worker thread" (that may execute code directly)
379 self.worker_ident = None
374 self.worker_ident = None
375
380 def runsource(self, source, filename="<input>", symbol="single"):
376 def runsource(self, source, filename="<input>", symbol="single"):
381 """Compile and run some source in the interpreter.
377 """Compile and run some source in the interpreter.
382
378
383 Modified version of code.py's runsource(), to handle threading issues.
379 Modified version of code.py's runsource(), to handle threading issues.
384 See the original for full docstring details."""
380 See the original for full docstring details."""
385
381
386 global KBINT
382 global KBINT
387
383
388 # If Ctrl-C was typed, we reset the flag and return right away
384 # If Ctrl-C was typed, we reset the flag and return right away
389 if KBINT:
385 if KBINT:
390 KBINT = False
386 KBINT = False
391 return False
387 return False
388
389 if self._kill:
390 # can't queue new code if we are being killed
391 return True
392
392
393 try:
393 try:
394 code = self.compile(source, filename, symbol)
394 code = self.compile(source, filename, symbol)
@@ -401,38 +401,40 b' class MTInteractiveShell(InteractiveShell):'
401 # Case 2
401 # Case 2
402 return True
402 return True
403
403
404 # Case 3
405 # Store code in queue, so the execution thread can handle it.
406
407 # Note that with macros and other applications, we MAY re-enter this
408 # section, so we have to acquire the lock with non-blocking semantics,
409 # else we deadlock.
410
411 # shortcut - if we are in worker thread, or the worker thread is not running,
404 # shortcut - if we are in worker thread, or the worker thread is not running,
412 # execute directly (to allow recursion and prevent deadlock if code is run early
405 # execute directly (to allow recursion and prevent deadlock if code is run early
413 # in IPython construction)
406 # in IPython construction)
414
407
415 if self.worker_ident is None or self.worker_ident == thread.get_ident():
408 if (self.worker_ident is None or self.worker_ident == thread.get_ident()):
416 InteractiveShell.runcode(self,code)
409 InteractiveShell.runcode(self,code)
417 return
410 return
418
419 got_lock = self.thread_ready.acquire(blocking=False)
420 self.code_queue.put(code)
421 if got_lock:
422 self.thread_ready.wait() # Wait until processed in timeout interval
423 self.thread_ready.release()
424
411
412 # Case 3
413 # Store code in queue, so the execution thread can handle it.
414
415 completed_ev, received_ev = threading.Event(), threading.Event()
416
417 self.code_queue.put((code,completed_ev, received_ev))
418 # first make sure the message was received, with timeout
419 received_ev.wait(5)
420 if not received_ev.isSet():
421 # the mainloop is dead, start executing code directly
422 print "Warning: Timeout for mainloop thread exceeded"
423 print "switching to nonthreaded mode (until mainloop wakes up again)"
424 self.worker_ident = None
425 else:
426 completed_ev.wait()
425 return False
427 return False
426
428
427 def runcode(self):
429 def runcode(self):
428 """Execute a code object.
430 """Execute a code object.
429
431
430 Multithreaded wrapper around IPython's runcode()."""
432 Multithreaded wrapper around IPython's runcode()."""
431
433
432 global CODE_RUN
434 global CODE_RUN
433 # lock thread-protected stuff
435
436 # we are in worker thread, stash out the id for runsource()
434 self.worker_ident = thread.get_ident()
437 self.worker_ident = thread.get_ident()
435 got_lock = self.thread_ready.acquire()
436
438
437 if self._kill:
439 if self._kill:
438 print >>Term.cout, 'Closing threads...',
440 print >>Term.cout, 'Closing threads...',
@@ -440,6 +442,9 b' class MTInteractiveShell(InteractiveShell):'
440 for tokill in self.on_kill:
442 for tokill in self.on_kill:
441 tokill()
443 tokill()
442 print >>Term.cout, 'Done.'
444 print >>Term.cout, 'Done.'
445 # allow kill() to return
446 self._kill.set()
447 return True
443
448
444 # Install sigint handler. We do it every time to ensure that if user
449 # Install sigint handler. We do it every time to ensure that if user
445 # code modifies it, we restore our own handling.
450 # code modifies it, we restore our own handling.
@@ -455,9 +460,11 b' class MTInteractiveShell(InteractiveShell):'
455 code_to_run = None
460 code_to_run = None
456 while 1:
461 while 1:
457 try:
462 try:
458 code_to_run = self.code_queue.get_nowait()
463 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
459 except Queue.Empty:
464 except Queue.Empty:
460 break
465 break
466 received_ev.set()
467
461 # Exceptions need to be raised differently depending on which
468 # Exceptions need to be raised differently depending on which
462 # thread is active. This convoluted try/except is only there to
469 # thread is active. This convoluted try/except is only there to
463 # protect against asynchronous exceptions, to ensure that a KBINT
470 # protect against asynchronous exceptions, to ensure that a KBINT
@@ -471,28 +478,23 b' class MTInteractiveShell(InteractiveShell):'
471 except KeyboardInterrupt:
478 except KeyboardInterrupt:
472 print "Keyboard interrupted in mainloop"
479 print "Keyboard interrupted in mainloop"
473 while not self.code_queue.empty():
480 while not self.code_queue.empty():
474 self.code_queue.get_nowait()
481 code, ev1,ev2 = self.code_queue.get_nowait()
482 ev1.set()
483 ev2.set()
475 break
484 break
476 finally:
485 finally:
477 if got_lock:
486 CODE_RUN = False
478 CODE_RUN = False
487 # allow runsource() return from wait
479
488 completed_ev.set()
480 # We're done with thread-protected variables
489
481 if code_to_run is not None:
490
482 self.thread_ready.notify()
483 self.thread_ready.release()
484
485 # We're done...
486 CODE_RUN = False
487 # This MUST return true for gtk threading to work
491 # This MUST return true for gtk threading to work
488 return True
492 return True
489
493
490 def kill(self):
494 def kill(self):
491 """Kill the thread, returning when it has been shut down."""
495 """Kill the thread, returning when it has been shut down."""
492 got_lock = self.thread_ready.acquire(False)
496 self._kill = threading.Event()
493 self._kill = True
497 self._kill.wait()
494 if got_lock:
495 self.thread_ready.release()
496
498
497 class MatplotlibShellBase:
499 class MatplotlibShellBase:
498 """Mixin class to provide the necessary modifications to regular IPython
500 """Mixin class to provide the necessary modifications to regular IPython
@@ -1153,10 +1155,13 b' def _select_shell(argv):'
1153 }
1155 }
1154
1156
1155 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1157 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1156 'tkthread'])
1158 'tkthread', 'twisted'])
1157 user_opts = set([s.replace('-','') for s in argv[:3]])
1159 user_opts = set([s.replace('-','') for s in argv[:3]])
1158 special_opts = user_opts & all_opts
1160 special_opts = user_opts & all_opts
1159
1161
1162 if 'twisted' in special_opts:
1163 import twshell
1164 return twshell.IPShellTwisted
1160 if 'tk' in special_opts:
1165 if 'tk' in special_opts:
1161 USE_TK = True
1166 USE_TK = True
1162 special_opts.remove('tk')
1167 special_opts.remove('tk')
@@ -184,10 +184,9 b" object? -> Details about 'object'. ?object also works, ?? prints more."
184
184
185 # Options that can *only* appear at the cmd line (not in rcfiles).
185 # Options that can *only* appear at the cmd line (not in rcfiles).
186
186
187 # The "ignore" option is a kludge so that Emacs buffers don't crash, since
188 # the 'C-c !' command in emacs automatically appends a -i option at the end.
189 cmdline_only = ('help interact|i ipythondir=s Version upgrade '
187 cmdline_only = ('help interact|i ipythondir=s Version upgrade '
190 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk!')
188 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk! '
189 'twisted!')
191
190
192 # Build the actual name list to be used by DPyGetOpt
191 # Build the actual name list to be used by DPyGetOpt
193 opts_names = qw(cmdline_opts) + qw(cmdline_only)
192 opts_names = qw(cmdline_opts) + qw(cmdline_only)
@@ -245,6 +244,7 b" object? -> Details about 'object'. ?object also works, ?? prints more."
245 system_verbose = 0,
244 system_verbose = 0,
246 term_title = 1,
245 term_title = 1,
247 tk = 0,
246 tk = 0,
247 twisted= 0,
248 upgrade = 0,
248 upgrade = 0,
249 Version = 0,
249 Version = 0,
250 wildcards_case_sensitive = 1,
250 wildcards_case_sensitive = 1,
@@ -80,3 +80,17 b' else:'
80 Term.cout.flush()
80 Term.cout.flush()
81 # Set global flag so that runsource can know that Ctrl-C was hit
81 # Set global flag so that runsource can know that Ctrl-C was hit
82 KBINT = True
82 KBINT = True
83
84 def run_in_frontend(src):
85 """ Check if source snippet can be run in the REPL thread, as opposed to GUI mainloop
86
87 (to prevent unnecessary hanging of mainloop).
88
89 """
90
91 if src.startswith('_ip.system(') and not '\n' in src:
92 return True
93 return False
94
95
96
@@ -1,13 +1,7 b''
1 import sys
1 import sys
2
2
3 from twisted.internet import gtk2reactor
4 gtk2reactor.install()
5
6 from twisted.internet import reactor, threads
3 from twisted.internet import reactor, threads
7
4
8 """ change here to choose the plot shell with the MT option
9 which should cost extra """
10
11 from IPython.ipmaker import make_IPython
5 from IPython.ipmaker import make_IPython
12 from IPython.iplib import InteractiveShell
6 from IPython.iplib import InteractiveShell
13 from IPython.ipstruct import Struct
7 from IPython.ipstruct import Struct
@@ -16,6 +10,11 b' from signal import signal, SIGINT'
16 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
10 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
17 import shellglobals
11 import shellglobals
18
12
13 def install_gtk2():
14 """ Install gtk2 reactor, needs to be called bef """
15 from twisted.internet import gtk2reactor
16 gtk2reactor.install()
17
19
18
20 def hijack_reactor():
19 def hijack_reactor():
21 """Modifies Twisted's reactor with a dummy so user code does
20 """Modifies Twisted's reactor with a dummy so user code does
@@ -106,7 +105,7 b' class TwistedInteractiveShell(InteractiveShell):'
106 # in IPython construction)
105 # in IPython construction)
107
106
108 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
107 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
109 or self.worker_ident == thread.get_ident()):
108 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
110 InteractiveShell.runcode(self,code)
109 InteractiveShell.runcode(self,code)
111 return
110 return
112
111
@@ -125,8 +124,7 b' class TwistedInteractiveShell(InteractiveShell):'
125 print "Warning: Timeout for mainloop thread exceeded"
124 print "Warning: Timeout for mainloop thread exceeded"
126 print "switching to nonthreaded mode (until mainloop wakes up again)"
125 print "switching to nonthreaded mode (until mainloop wakes up again)"
127 self.worker_ident = None
126 self.worker_ident = None
128 else:
127 else:
129 shellglobals.CURRENT_COMPLETE_EV = completed_ev
130 completed_ev.wait()
128 completed_ev.wait()
131
129
132 return False
130 return False
@@ -36,11 +36,11 b' The following special options are ONLY valid at the beginning of the command'
36 line, and not later. This is because they control the initialization of
36 line, and not later. This is because they control the initialization of
37 ipython itself, before the normal option-handling mechanism is active.
37 ipython itself, before the normal option-handling mechanism is active.
38 .TP
38 .TP
39 .B \-gthread, \-qthread, \-q4thread, \-wthread, \-pylab
39 .B \-gthread, \-qthread, \-q4thread, \-wthread, \-pylab, \-twisted
40 Only ONE of these can be given, and it can only be given as the first option
40 Only ONE of these can be given, and it can only be given as the first option
41 passed to IPython (it will have no effect in any other position). They provide
41 passed to IPython (it will have no effect in any other position). They provide
42 threading support for the GTK, QT3, QT4 and WXWidgets toolkits, and for the
42 threading support for the GTK, QT3, QT4 and WXWidgets toolkits, for the
43 matplotlib library.
43 matplotlib library and Twisted reactor.
44 .br
44 .br
45 .sp 1
45 .sp 1
46 With any of the first four options, IPython starts running a separate thread
46 With any of the first four options, IPython starts running a separate thread
@@ -56,6 +56,10 b' request a specific version of wx to be used. This requires that you have the'
56 distributions.
56 distributions.
57 .br
57 .br
58 .sp 1
58 .sp 1
59 If \-twisted is given, IPython start a Twisted reactor and runs IPython mainloop
60 in a dedicated thread, passing commands to be run inside the Twisted reactor.
61 .br
62 .sp 1
59 If \-pylab is given, IPython loads special support for the matplotlib library
63 If \-pylab is given, IPython loads special support for the matplotlib library
60 (http://matplotlib.sourceforge.net), allowing interactive usage of any of its
64 (http://matplotlib.sourceforge.net), allowing interactive usage of any of its
61 backends as defined in the user's .matplotlibrc file. It automatically
65 backends as defined in the user's .matplotlibrc file. It automatically
General Comments 0
You need to be logged in to leave comments. Login now