##// END OF EJS Templates
Simplify MTInteractiveShell: ditch Condition(RLock), use much simpler threading.Event mechanism (relying more on built-in-functionality in Queue)
Ville M. Vainio -
Show More
@@ -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):
@@ -401,13 +396,6 b' class MTInteractiveShell(InteractiveShell):'
401 # Case 2
396 # Case 2
402 return True
397 return True
403
398
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,
399 # 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
400 # execute directly (to allow recursion and prevent deadlock if code is run early
413 # in IPython construction)
401 # in IPython construction)
@@ -416,12 +404,12 b' class MTInteractiveShell(InteractiveShell):'
416 InteractiveShell.runcode(self,code)
404 InteractiveShell.runcode(self,code)
417 return
405 return
418
406
419 got_lock = self.thread_ready.acquire(blocking=False)
407 # Case 3
420 self.code_queue.put(code)
408 # Store code in queue, so the execution thread can handle it.
421 if got_lock:
422 self.thread_ready.wait() # Wait until processed in timeout interval
423 self.thread_ready.release()
424
409
410 ev = threading.Event()
411 self.code_queue.put((code,ev))
412 ev.wait()
425 return False
413 return False
426
414
427 def runcode(self):
415 def runcode(self):
@@ -430,9 +418,9 b' class MTInteractiveShell(InteractiveShell):'
430 Multithreaded wrapper around IPython's runcode()."""
418 Multithreaded wrapper around IPython's runcode()."""
431
419
432 global CODE_RUN
420 global CODE_RUN
433 # lock thread-protected stuff
421
422 # we are in worker thread, stash out the id for runsource()
434 self.worker_ident = thread.get_ident()
423 self.worker_ident = thread.get_ident()
435 got_lock = self.thread_ready.acquire()
436
424
437 if self._kill:
425 if self._kill:
438 print >>Term.cout, 'Closing threads...',
426 print >>Term.cout, 'Closing threads...',
@@ -440,6 +428,9 b' class MTInteractiveShell(InteractiveShell):'
440 for tokill in self.on_kill:
428 for tokill in self.on_kill:
441 tokill()
429 tokill()
442 print >>Term.cout, 'Done.'
430 print >>Term.cout, 'Done.'
431 # allow kill() to return
432 self._kill.set()
433 return
443
434
444 # Install sigint handler. We do it every time to ensure that if user
435 # Install sigint handler. We do it every time to ensure that if user
445 # code modifies it, we restore our own handling.
436 # code modifies it, we restore our own handling.
@@ -455,7 +446,7 b' class MTInteractiveShell(InteractiveShell):'
455 code_to_run = None
446 code_to_run = None
456 while 1:
447 while 1:
457 try:
448 try:
458 code_to_run = self.code_queue.get_nowait()
449 code_to_run, event = self.code_queue.get_nowait()
459 except Queue.Empty:
450 except Queue.Empty:
460 break
451 break
461 # Exceptions need to be raised differently depending on which
452 # Exceptions need to be raised differently depending on which
@@ -471,28 +462,22 b' class MTInteractiveShell(InteractiveShell):'
471 except KeyboardInterrupt:
462 except KeyboardInterrupt:
472 print "Keyboard interrupted in mainloop"
463 print "Keyboard interrupted in mainloop"
473 while not self.code_queue.empty():
464 while not self.code_queue.empty():
474 self.code_queue.get_nowait()
465 code, ev = self.code_queue.get_nowait()
466 ev.set()
475 break
467 break
476 finally:
468 finally:
477 if got_lock:
478 CODE_RUN = False
469 CODE_RUN = False
470 # allow runsource() return from wait
471 event.set()
479
472
480 # We're done with thread-protected variables
481 if code_to_run is not None:
482 self.thread_ready.notify()
483 self.thread_ready.release()
484
473
485 # We're done...
486 CODE_RUN = False
487 # This MUST return true for gtk threading to work
474 # This MUST return true for gtk threading to work
488 return True
475 return True
489
476
490 def kill(self):
477 def kill(self):
491 """Kill the thread, returning when it has been shut down."""
478 """Kill the thread, returning when it has been shut down."""
492 got_lock = self.thread_ready.acquire(False)
479 self._kill = threading.Event()
493 self._kill = True
480 self._kill.wait()
494 if got_lock:
495 self.thread_ready.release()
496
481
497 class MatplotlibShellBase:
482 class MatplotlibShellBase:
498 """Mixin class to provide the necessary modifications to regular IPython
483 """Mixin class to provide the necessary modifications to regular IPython
General Comments 0
You need to be logged in to leave comments. Login now