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