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. |
|
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 = |
|
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) | |
@@ -415,13 +403,13 b' class MTInteractiveShell(InteractiveShell):' | |||||
415 | if self.worker_ident is None or self.worker_ident == thread.get_ident(): |
|
403 | if self.worker_ident is None or self.worker_ident == thread.get_ident(): | |
416 | InteractiveShell.runcode(self,code) |
|
404 | InteractiveShell.runcode(self,code) | |
417 | return |
|
405 | 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 |
|
406 | |||
|
407 | # Case 3 | |||
|
408 | # Store code in queue, so the execution thread can handle it. | |||
|
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 |
|
|
469 | CODE_RUN = False | |
478 | CODE_RUN = False |
|
470 | # allow runsource() return from wait | |
479 |
|
471 | event.set() | ||
480 | # We're done with thread-protected variables |
|
472 | ||
481 | if code_to_run is not None: |
|
473 | ||
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 |
|
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 |
|
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