Show More
@@ -11,11 +11,16 b' Things to do:' | |||||
11 | * Implement event loop and poll version. |
|
11 | * Implement event loop and poll version. | |
12 | """ |
|
12 | """ | |
13 |
|
13 | |||
|
14 | #----------------------------------------------------------------------------- | |||
|
15 | # Imports | |||
|
16 | #----------------------------------------------------------------------------- | |||
|
17 | ||||
14 | # Standard library imports. |
|
18 | # Standard library imports. | |
15 | import __builtin__ |
|
19 | import __builtin__ | |
16 | from code import CommandCompiler |
|
20 | from code import CommandCompiler | |
17 | import os |
|
21 | import os | |
18 | import sys |
|
22 | import sys | |
|
23 | from threading import Thread | |||
19 | import time |
|
24 | import time | |
20 | import traceback |
|
25 | import traceback | |
21 |
|
26 | |||
@@ -27,6 +32,9 b' from IPython.external.argparse import ArgumentParser' | |||||
27 | from session import Session, Message, extract_header |
|
32 | from session import Session, Message, extract_header | |
28 | from completer import KernelCompleter |
|
33 | from completer import KernelCompleter | |
29 |
|
34 | |||
|
35 | #----------------------------------------------------------------------------- | |||
|
36 | # Kernel and stream classes | |||
|
37 | #----------------------------------------------------------------------------- | |||
30 |
|
38 | |||
31 | class InStream(object): |
|
39 | class InStream(object): | |
32 | """ A file like object that reads from a 0MQ XREQ socket.""" |
|
40 | """ A file like object that reads from a 0MQ XREQ socket.""" | |
@@ -210,7 +218,6 b' class Kernel(object):' | |||||
210 | self.history = [] |
|
218 | self.history = [] | |
211 | self.compiler = CommandCompiler() |
|
219 | self.compiler = CommandCompiler() | |
212 | self.completer = KernelCompleter(self.user_ns) |
|
220 | self.completer = KernelCompleter(self.user_ns) | |
213 | self.poll_ppid = False |
|
|||
214 |
|
221 | |||
215 | # Build dict of handlers for message types |
|
222 | # Build dict of handlers for message types | |
216 | msg_types = [ 'execute_request', 'complete_request', |
|
223 | msg_types = [ 'execute_request', 'complete_request', | |
@@ -325,10 +332,6 b' class Kernel(object):' | |||||
325 |
|
332 | |||
326 | def start(self): |
|
333 | def start(self): | |
327 | while True: |
|
334 | while True: | |
328 | if self.poll_ppid and os.getppid() == 1: |
|
|||
329 | print>>sys.__stderr__, "KILLED KERNEL. No parent process." |
|
|||
330 | os._exit(1) |
|
|||
331 |
|
||||
332 | ident = self.reply_socket.recv() |
|
335 | ident = self.reply_socket.recv() | |
333 | assert self.reply_socket.rcvmore(), "Unexpected missing message part." |
|
336 | assert self.reply_socket.rcvmore(), "Unexpected missing message part." | |
334 | msg = self.reply_socket.recv_json() |
|
337 | msg = self.reply_socket.recv_json() | |
@@ -341,6 +344,34 b' class Kernel(object):' | |||||
341 | else: |
|
344 | else: | |
342 | handler(ident, omsg) |
|
345 | handler(ident, omsg) | |
343 |
|
346 | |||
|
347 | #----------------------------------------------------------------------------- | |||
|
348 | # Kernel main and launch functions | |||
|
349 | #----------------------------------------------------------------------------- | |||
|
350 | ||||
|
351 | class UnixPoller(Thread): | |||
|
352 | ||||
|
353 | def __init__(self): | |||
|
354 | super(UnixPoller, self).__init__() | |||
|
355 | self.daemon = True | |||
|
356 | ||||
|
357 | def run(self): | |||
|
358 | while True: | |||
|
359 | if os.getppid() == 1: | |||
|
360 | os._exit(1) | |||
|
361 | time.sleep(5.0) | |||
|
362 | ||||
|
363 | class WindowsPoller(Thread): | |||
|
364 | ||||
|
365 | def __init__(self, handle): | |||
|
366 | super(WindowsPoller, self).__init__() | |||
|
367 | self.daemon = True | |||
|
368 | self.handle = handle | |||
|
369 | ||||
|
370 | def run(self): | |||
|
371 | from _subprocess import WaitForSingleObject, WAIT_OBJECT_0, INFINITE | |||
|
372 | result = WaitForSingleObject(self.handle, INFINITE) | |||
|
373 | if result == WAIT_OBJECT_0: | |||
|
374 | os._exit(1) | |||
344 |
|
375 | |||
345 | def bind_port(socket, ip, port): |
|
376 | def bind_port(socket, ip, port): | |
346 | """ Binds the specified ZMQ socket. If the port is less than zero, a random |
|
377 | """ Binds the specified ZMQ socket. If the port is less than zero, a random | |
@@ -367,8 +398,13 b' def main():' | |||||
367 | help='set the PUB channel port [default: random]') |
|
398 | help='set the PUB channel port [default: random]') | |
368 | parser.add_argument('--req', type=int, metavar='PORT', default=0, |
|
399 | parser.add_argument('--req', type=int, metavar='PORT', default=0, | |
369 | help='set the REQ channel port [default: random]') |
|
400 | help='set the REQ channel port [default: random]') | |
370 | parser.add_argument('--require-parent', action='store_true', |
|
401 | if sys.platform == 'win32': | |
371 | help='ensure that this process dies with its parent') |
|
402 | parser.add_argument('--parent', type=int, metavar='HANDLE', | |
|
403 | default=0, help='kill this process if the process ' | |||
|
404 | 'with HANDLE dies') | |||
|
405 | else: | |||
|
406 | parser.add_argument('--parent', action='store_true', | |||
|
407 | help='kill this process if its parent dies') | |||
372 | namespace = parser.parse_args() |
|
408 | namespace = parser.parse_args() | |
373 |
|
409 | |||
374 | # Create a context, a session, and the kernel sockets. |
|
410 | # Create a context, a session, and the kernel sockets. | |
@@ -398,15 +434,18 b' def main():' | |||||
398 | kernel = Kernel(session, reply_socket, pub_socket) |
|
434 | kernel = Kernel(session, reply_socket, pub_socket) | |
399 |
|
435 | |||
400 | # Configure this kernel/process to die on parent termination, if necessary. |
|
436 | # Configure this kernel/process to die on parent termination, if necessary. | |
401 |
if namespace. |
|
437 | if namespace.parent: | |
402 | if sys.platform == 'linux2': |
|
438 | if sys.platform == 'linux2': | |
403 | import ctypes, ctypes.util, signal |
|
439 | import ctypes, ctypes.util, signal | |
404 | PR_SET_PDEATHSIG = 1 |
|
440 | PR_SET_PDEATHSIG = 1 | |
405 | libc = ctypes.CDLL(ctypes.util.find_library('c')) |
|
441 | libc = ctypes.CDLL(ctypes.util.find_library('c')) | |
406 | libc.prctl(PR_SET_PDEATHSIG, signal.SIGKILL) |
|
442 | libc.prctl(PR_SET_PDEATHSIG, signal.SIGKILL) | |
407 |
|
443 | elif sys.platform == 'win32': | ||
408 | elif sys.platform != 'win32': |
|
444 | poller = WindowsPoller(namespace.parent) | |
409 | kernel.poll_ppid = True |
|
445 | poller.start() | |
|
446 | else: | |||
|
447 | poller = UnixPoller() | |||
|
448 | poller.start() | |||
410 |
|
449 | |||
411 | # Start the kernel mainloop. |
|
450 | # Start the kernel mainloop. | |
412 | kernel.start() |
|
451 | kernel.start() | |
@@ -430,7 +469,7 b' def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False):' | |||||
430 | If set, the kernel process is guaranteed to survive if this process |
|
469 | If set, the kernel process is guaranteed to survive if this process | |
431 | dies. If not set, an effort is made to ensure that the kernel is killed |
|
470 | dies. If not set, an effort is made to ensure that the kernel is killed | |
432 | when this process dies. Note that in this case it is still good practice |
|
471 | when this process dies. Note that in this case it is still good practice | |
433 |
to |
|
472 | to kill kernels manually before exiting. | |
434 |
|
473 | |||
435 | Returns |
|
474 | Returns | |
436 | ------- |
|
475 | ------- | |
@@ -463,15 +502,22 b' def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False):' | |||||
463 | command = 'from IPython.zmq.kernel import main; main()' |
|
502 | command = 'from IPython.zmq.kernel import main; main()' | |
464 | arguments = [ sys.executable, '-c', command, '--xrep', str(xrep_port), |
|
503 | arguments = [ sys.executable, '-c', command, '--xrep', str(xrep_port), | |
465 | '--pub', str(pub_port), '--req', str(req_port) ] |
|
504 | '--pub', str(pub_port), '--req', str(req_port) ] | |
466 |
|
||||
467 | if independent: |
|
505 | if independent: | |
468 | if sys.platform == 'win32': |
|
506 | if sys.platform == 'win32': | |
469 | proc = Popen(['start', '/b'] + arguments, shell=True) |
|
507 | proc = Popen(['start', '/b'] + arguments, shell=True) | |
470 | else: |
|
508 | else: | |
471 | proc = Popen(arguments, preexec_fn=lambda: os.setsid()) |
|
509 | proc = Popen(arguments, preexec_fn=lambda: os.setsid()) | |
472 |
|
||||
473 | else: |
|
510 | else: | |
474 | proc = Popen(arguments + ['--require-parent']) |
|
511 | if sys.platform == 'win32': | |
|
512 | from _subprocess import DuplicateHandle, GetCurrentProcess, \ | |||
|
513 | DUPLICATE_SAME_ACCESS | |||
|
514 | pid = GetCurrentProcess() | |||
|
515 | handle = DuplicateHandle(pid, pid, pid, 0, | |||
|
516 | True, # Inheritable by new processes. | |||
|
517 | DUPLICATE_SAME_ACCESS) | |||
|
518 | proc = Popen(arguments + ['--parent', str(int(handle))]) | |||
|
519 | else: | |||
|
520 | proc = Popen(arguments + ['--parent']) | |||
475 |
|
521 | |||
476 | return proc, xrep_port, pub_port, req_port |
|
522 | return proc, xrep_port, pub_port, req_port | |
477 |
|
523 |
General Comments 0
You need to be logged in to leave comments.
Login now