Show More
@@ -358,18 +358,13 b' class MTInteractiveShell(InteractiveShell):' | |||
|
358 | 358 | InteractiveShell.__init__(self,name,usage,rc,user_ns, |
|
359 | 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. |
|
|
365 | # enough, because uses like macros cause reentrancy. | |
|
362 | # A queue to hold the code to be executed. | |
|
366 | 363 | self.code_queue = Queue.Queue() |
|
367 | 364 | |
|
368 | 365 | # Stuff to do at closing time |
|
369 |
self._kill = |
|
|
370 | on_kill = kw.get('on_kill') | |
|
371 | if on_kill is None: | |
|
372 | on_kill = [] | |
|
366 | self._kill = None | |
|
367 | on_kill = kw.get('on_kill', []) | |
|
373 | 368 | # Check that all things to kill are callable: |
|
374 | 369 | for t in on_kill: |
|
375 | 370 | if not callable(t): |
@@ -401,13 +396,6 b' class MTInteractiveShell(InteractiveShell):' | |||
|
401 | 396 | # Case 2 |
|
402 | 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 | 399 | # shortcut - if we are in worker thread, or the worker thread is not running, |
|
412 | 400 | # execute directly (to allow recursion and prevent deadlock if code is run early |
|
413 | 401 | # in IPython construction) |
@@ -415,13 +403,13 b' class MTInteractiveShell(InteractiveShell):' | |||
|
415 | 403 | if self.worker_ident is None or self.worker_ident == thread.get_ident(): |
|
416 | 404 | InteractiveShell.runcode(self,code) |
|
417 | 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 | 413 | return False |
|
426 | 414 | |
|
427 | 415 | def runcode(self): |
@@ -430,9 +418,9 b' class MTInteractiveShell(InteractiveShell):' | |||
|
430 | 418 | Multithreaded wrapper around IPython's runcode().""" |
|
431 | 419 | |
|
432 | 420 | global CODE_RUN |
|
433 | # lock thread-protected stuff | |
|
421 | ||
|
422 | # we are in worker thread, stash out the id for runsource() | |
|
434 | 423 | self.worker_ident = thread.get_ident() |
|
435 | got_lock = self.thread_ready.acquire() | |
|
436 | 424 | |
|
437 | 425 | if self._kill: |
|
438 | 426 | print >>Term.cout, 'Closing threads...', |
@@ -440,6 +428,9 b' class MTInteractiveShell(InteractiveShell):' | |||
|
440 | 428 | for tokill in self.on_kill: |
|
441 | 429 | tokill() |
|
442 | 430 | print >>Term.cout, 'Done.' |
|
431 | # allow kill() to return | |
|
432 | self._kill.set() | |
|
433 | return | |
|
443 | 434 | |
|
444 | 435 | # Install sigint handler. We do it every time to ensure that if user |
|
445 | 436 | # code modifies it, we restore our own handling. |
@@ -455,7 +446,7 b' class MTInteractiveShell(InteractiveShell):' | |||
|
455 | 446 | code_to_run = None |
|
456 | 447 | while 1: |
|
457 | 448 | try: |
|
458 | code_to_run = self.code_queue.get_nowait() | |
|
449 | code_to_run, event = self.code_queue.get_nowait() | |
|
459 | 450 | except Queue.Empty: |
|
460 | 451 | break |
|
461 | 452 | # Exceptions need to be raised differently depending on which |
@@ -471,28 +462,22 b' class MTInteractiveShell(InteractiveShell):' | |||
|
471 | 462 | except KeyboardInterrupt: |
|
472 | 463 | print "Keyboard interrupted in mainloop" |
|
473 | 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 | 467 | break |
|
476 | 468 | finally: |
|
477 |
|
|
|
478 | CODE_RUN = False | |
|
479 | ||
|
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 | ||
|
485 | # We're done... | |
|
486 | CODE_RUN = False | |
|
469 | CODE_RUN = False | |
|
470 | # allow runsource() return from wait | |
|
471 | event.set() | |
|
472 | ||
|
473 | ||
|
487 | 474 | # This MUST return true for gtk threading to work |
|
488 | 475 | return True |
|
489 | 476 | |
|
490 | 477 | def kill(self): |
|
491 | 478 | """Kill the thread, returning when it has been shut down.""" |
|
492 | got_lock = self.thread_ready.acquire(False) | |
|
493 |
self._kill |
|
|
494 | if got_lock: | |
|
495 | self.thread_ready.release() | |
|
479 | self._kill = threading.Event() | |
|
480 | self._kill.wait() | |
|
496 | 481 | |
|
497 | 482 | class MatplotlibShellBase: |
|
498 | 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