##// END OF EJS Templates
MTInteractiveShell: implement "code received" event in runsource & runcode to prevent hanging indefinitely when the mainloop is dead (typical with -gthread) if you close the window
Ville M. Vainio -
Show More
@@ -22,7 +22,7 b" name = 'ipython'"
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
23 # bdist_deb does not accept underscores (a Debian convention).
23 # bdist_deb does not accept underscores (a Debian convention).
24
24
25 revision = '46'
25 revision = '52'
26
26
27 version = '0.8.3.bzr.r' + revision
27 version = '0.8.3.bzr.r' + revision
28
28
@@ -372,12 +372,13 b' class MTInteractiveShell(InteractiveShell):'
372 self.on_kill = on_kill
372 self.on_kill = on_kill
373 # thread identity of the "worker thread" (that may execute code directly)
373 # thread identity of the "worker thread" (that may execute code directly)
374 self.worker_ident = None
374 self.worker_ident = None
375
375 def runsource(self, source, filename="<input>", symbol="single"):
376 def runsource(self, source, filename="<input>", symbol="single"):
376 """Compile and run some source in the interpreter.
377 """Compile and run some source in the interpreter.
377
378
378 Modified version of code.py's runsource(), to handle threading issues.
379 Modified version of code.py's runsource(), to handle threading issues.
379 See the original for full docstring details."""
380 See the original for full docstring details."""
380
381
381 global KBINT
382 global KBINT
382
383
383 # 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
@@ -411,16 +412,25 b' class MTInteractiveShell(InteractiveShell):'
411 # Case 3
412 # Case 3
412 # Store code in queue, so the execution thread can handle it.
413 # Store code in queue, so the execution thread can handle it.
413
414
414 ev = threading.Event()
415 completed_ev, received_ev = threading.Event(), threading.Event()
415 self.code_queue.put((code,ev))
416
416 ev.wait()
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()
417 return False
427 return False
418
428
419 def runcode(self):
429 def runcode(self):
420 """Execute a code object.
430 """Execute a code object.
421
431
422 Multithreaded wrapper around IPython's runcode()."""
432 Multithreaded wrapper around IPython's runcode()."""
423
433
424 global CODE_RUN
434 global CODE_RUN
425
435
426 # we are in worker thread, stash out the id for runsource()
436 # we are in worker thread, stash out the id for runsource()
@@ -450,9 +460,11 b' class MTInteractiveShell(InteractiveShell):'
450 code_to_run = None
460 code_to_run = None
451 while 1:
461 while 1:
452 try:
462 try:
453 code_to_run, event = self.code_queue.get_nowait()
463 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
454 except Queue.Empty:
464 except Queue.Empty:
455 break
465 break
466 received_ev.set()
467
456 # Exceptions need to be raised differently depending on which
468 # Exceptions need to be raised differently depending on which
457 # thread is active. This convoluted try/except is only there to
469 # thread is active. This convoluted try/except is only there to
458 # protect against asynchronous exceptions, to ensure that a KBINT
470 # protect against asynchronous exceptions, to ensure that a KBINT
@@ -466,13 +478,14 b' class MTInteractiveShell(InteractiveShell):'
466 except KeyboardInterrupt:
478 except KeyboardInterrupt:
467 print "Keyboard interrupted in mainloop"
479 print "Keyboard interrupted in mainloop"
468 while not self.code_queue.empty():
480 while not self.code_queue.empty():
469 code, ev = self.code_queue.get_nowait()
481 code, ev1,ev2 = self.code_queue.get_nowait()
470 ev.set()
482 ev1.set()
483 ev2.set()
471 break
484 break
472 finally:
485 finally:
473 CODE_RUN = False
486 CODE_RUN = False
474 # allow runsource() return from wait
487 # allow runsource() return from wait
475 event.set()
488 completed_ev.set()
476
489
477
490
478 # This MUST return true for gtk threading to work
491 # This MUST return true for gtk threading to work
@@ -480,7 +493,7 b' class MTInteractiveShell(InteractiveShell):'
480
493
481 def kill(self):
494 def kill(self):
482 """Kill the thread, returning when it has been shut down."""
495 """Kill the thread, returning when it has been shut down."""
483 self._kill = threading.Event()
496 self._kill = threading.Event()
484 self._kill.wait()
497 self._kill.wait()
485
498
486 class MatplotlibShellBase:
499 class MatplotlibShellBase:
General Comments 0
You need to be logged in to leave comments. Login now