Show More
@@ -20,6 +20,7 b' Authors:' | |||||
20 | import errno |
|
20 | import errno | |
21 | import logging |
|
21 | import logging | |
22 | import os |
|
22 | import os | |
|
23 | import select | |||
23 | import signal |
|
24 | import signal | |
24 | import socket |
|
25 | import socket | |
25 | import sys |
|
26 | import sys | |
@@ -450,10 +451,48 b' class NotebookApp(BaseIPythonApplication):' | |||||
450 | break |
|
451 | break | |
451 |
|
452 | |||
452 | def init_signal(self): |
|
453 | def init_signal(self): | |
453 |
signal.signal(signal.SIGINT, self._handle_sig |
|
454 | signal.signal(signal.SIGINT, self._handle_sigint) | |
454 |
signal.signal(signal.SIGTERM, self. |
|
455 | signal.signal(signal.SIGTERM, self._signal_stop) | |
455 |
|
456 | |||
456 |
def _handle_sig |
|
457 | def _handle_sigint(self, sig, frame): | |
|
458 | """SIGINT handler spawns confirmation dialog""" | |||
|
459 | # register more forceful signal handler for ^C^C case | |||
|
460 | signal.signal(signal.SIGINT, self._signal_stop) | |||
|
461 | # request confirmation dialog in bg thread, to avoid | |||
|
462 | # blocking the App | |||
|
463 | thread = threading.Thread(target=self._confirm_exit) | |||
|
464 | thread.daemon = True | |||
|
465 | thread.start() | |||
|
466 | ||||
|
467 | def _restore_sigint_handler(self): | |||
|
468 | """callback for restoring original SIGINT handler""" | |||
|
469 | signal.signal(signal.SIGINT, self._handle_sigint) | |||
|
470 | ||||
|
471 | def _confirm_exit(self): | |||
|
472 | """confirm shutdown on ^C | |||
|
473 | ||||
|
474 | A second ^C, or answering 'y' within 5s will cause shutdown, | |||
|
475 | otherwise original SIGINT handler will be restored. | |||
|
476 | """ | |||
|
477 | sys.stdout.write("Shutdown Notebook Server (y/[n])? ") | |||
|
478 | sys.stdout.flush() | |||
|
479 | r,w,x = select.select([sys.stdin], [], [], 5) | |||
|
480 | if r: | |||
|
481 | line = sys.stdin.readline() | |||
|
482 | if line.lower().startswith('y'): | |||
|
483 | self.log.critical("Shutdown confirmed") | |||
|
484 | ioloop.IOLoop.instance().stop() | |||
|
485 | return | |||
|
486 | else: | |||
|
487 | print "No answer for 5s:", | |||
|
488 | print "resuming operation..." | |||
|
489 | # no answer, or answer is no: | |||
|
490 | # set it back to original SIGINT handler | |||
|
491 | # use IOLoop.add_callback because signal.signal must be called | |||
|
492 | # from main thread | |||
|
493 | ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler) | |||
|
494 | ||||
|
495 | def _signal_stop(self, sig, frame): | |||
457 | self.log.critical("received signal %s, stopping", sig) |
|
496 | self.log.critical("received signal %s, stopping", sig) | |
458 | ioloop.IOLoop.instance().stop() |
|
497 | ioloop.IOLoop.instance().stop() | |
459 |
|
498 |
General Comments 0
You need to be logged in to leave comments.
Login now