##// END OF EJS Templates
Minor debug statement removed.
Brian Granger -
Show More
@@ -1,192 +1,191 b''
1 """ Defines helper functions for creating kernel entry points and process
1 """ Defines helper functions for creating kernel entry points and process
2 launchers.
2 launchers.
3 """
3 """
4
4
5 # Standard library imports.
5 # Standard library imports.
6 import socket
6 import socket
7 from subprocess import Popen
7 from subprocess import Popen
8 import sys
8 import sys
9
9
10 # System library imports.
10 # System library imports.
11 import zmq
11 import zmq
12
12
13 # Local imports.
13 # Local imports.
14 from IPython.external.argparse import ArgumentParser
14 from IPython.external.argparse import ArgumentParser
15 from exitpoller import ExitPollerUnix, ExitPollerWindows
15 from exitpoller import ExitPollerUnix, ExitPollerWindows
16 from displayhook import DisplayHook
16 from displayhook import DisplayHook
17 from iostream import OutStream
17 from iostream import OutStream
18 from session import Session
18 from session import Session
19
19
20
20
21 def bind_port(socket, ip, port):
21 def bind_port(socket, ip, port):
22 """ Binds the specified ZMQ socket. If the port is zero, a random port is
22 """ Binds the specified ZMQ socket. If the port is zero, a random port is
23 chosen. Returns the port that was bound.
23 chosen. Returns the port that was bound.
24 """
24 """
25 connection = 'tcp://%s' % ip
25 connection = 'tcp://%s' % ip
26 if port <= 0:
26 if port <= 0:
27 port = socket.bind_to_random_port(connection)
27 port = socket.bind_to_random_port(connection)
28 else:
28 else:
29 connection += ':%i' % port
29 connection += ':%i' % port
30 socket.bind(connection)
30 socket.bind(connection)
31 return port
31 return port
32
32
33
33
34 def make_argument_parser():
34 def make_argument_parser():
35 """ Creates an ArgumentParser for the generic arguments supported by all
35 """ Creates an ArgumentParser for the generic arguments supported by all
36 kernel entry points.
36 kernel entry points.
37 """
37 """
38 parser = ArgumentParser()
38 parser = ArgumentParser()
39 parser.add_argument('--ip', type=str, default='127.0.0.1',
39 parser.add_argument('--ip', type=str, default='127.0.0.1',
40 help='set the kernel\'s IP address [default: local]')
40 help='set the kernel\'s IP address [default: local]')
41 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
41 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
42 help='set the XREP channel port [default: random]')
42 help='set the XREP channel port [default: random]')
43 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
43 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
44 help='set the PUB channel port [default: random]')
44 help='set the PUB channel port [default: random]')
45 parser.add_argument('--req', type=int, metavar='PORT', default=0,
45 parser.add_argument('--req', type=int, metavar='PORT', default=0,
46 help='set the REQ channel port [default: random]')
46 help='set the REQ channel port [default: random]')
47
47
48 if sys.platform == 'win32':
48 if sys.platform == 'win32':
49 parser.add_argument('--parent', type=int, metavar='HANDLE',
49 parser.add_argument('--parent', type=int, metavar='HANDLE',
50 default=0, help='kill this process if the process '
50 default=0, help='kill this process if the process '
51 'with HANDLE dies')
51 'with HANDLE dies')
52 else:
52 else:
53 parser.add_argument('--parent', action='store_true',
53 parser.add_argument('--parent', action='store_true',
54 help='kill this process if its parent dies')
54 help='kill this process if its parent dies')
55
55
56 return parser
56 return parser
57
57
58
58
59 def make_kernel(namespace, kernel_factory,
59 def make_kernel(namespace, kernel_factory,
60 out_stream_factory=None, display_hook_factory=None):
60 out_stream_factory=None, display_hook_factory=None):
61 """ Creates a kernel.
61 """ Creates a kernel.
62 """
62 """
63 # Create a context, a session, and the kernel sockets.
63 # Create a context, a session, and the kernel sockets.
64 print >>sys.__stdout__, "Starting the kernel..."
64 print >>sys.__stdout__, "Starting the kernel..."
65 context = zmq.Context()
65 context = zmq.Context()
66 session = Session(username=u'kernel')
66 session = Session(username=u'kernel')
67
67
68 reply_socket = context.socket(zmq.XREP)
68 reply_socket = context.socket(zmq.XREP)
69 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
69 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
70 print >>sys.__stdout__, "XREP Channel on port", xrep_port
70 print >>sys.__stdout__, "XREP Channel on port", xrep_port
71
71
72 pub_socket = context.socket(zmq.PUB)
72 pub_socket = context.socket(zmq.PUB)
73 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
73 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
74 print >>sys.__stdout__, "PUB Channel on port", pub_port
74 print >>sys.__stdout__, "PUB Channel on port", pub_port
75
75
76 req_socket = context.socket(zmq.XREQ)
76 req_socket = context.socket(zmq.XREQ)
77 req_port = bind_port(req_socket, namespace.ip, namespace.req)
77 req_port = bind_port(req_socket, namespace.ip, namespace.req)
78 print >>sys.__stdout__, "REQ Channel on port", req_port
78 print >>sys.__stdout__, "REQ Channel on port", req_port
79
79
80 # Redirect input streams and set a display hook.
80 # Redirect input streams and set a display hook.
81 if out_stream_factory:
81 if out_stream_factory:
82 pass
83 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
82 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
84 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
83 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
85 if display_hook_factory:
84 if display_hook_factory:
86 sys.displayhook = display_hook_factory(session, pub_socket)
85 sys.displayhook = display_hook_factory(session, pub_socket)
87
86
88 # Create the kernel.
87 # Create the kernel.
89 return kernel_factory(session=session, reply_socket=reply_socket,
88 return kernel_factory(session=session, reply_socket=reply_socket,
90 pub_socket=pub_socket, req_socket=req_socket)
89 pub_socket=pub_socket, req_socket=req_socket)
91
90
92
91
93 def start_kernel(namespace, kernel):
92 def start_kernel(namespace, kernel):
94 """ Starts a kernel.
93 """ Starts a kernel.
95 """
94 """
96 # Configure this kernel/process to die on parent termination, if necessary.
95 # Configure this kernel/process to die on parent termination, if necessary.
97 if namespace.parent:
96 if namespace.parent:
98 if sys.platform == 'win32':
97 if sys.platform == 'win32':
99 poller = ExitPollerWindows(namespace.parent)
98 poller = ExitPollerWindows(namespace.parent)
100 else:
99 else:
101 poller = ExitPollerUnix()
100 poller = ExitPollerUnix()
102 poller.start()
101 poller.start()
103
102
104 # Start the kernel mainloop.
103 # Start the kernel mainloop.
105 kernel.start()
104 kernel.start()
106
105
107
106
108 def make_default_main(kernel_factory):
107 def make_default_main(kernel_factory):
109 """ Creates the simplest possible kernel entry point.
108 """ Creates the simplest possible kernel entry point.
110 """
109 """
111 def main():
110 def main():
112 namespace = make_argument_parser().parse_args()
111 namespace = make_argument_parser().parse_args()
113 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
112 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
114 start_kernel(namespace, kernel)
113 start_kernel(namespace, kernel)
115 return main
114 return main
116
115
117
116
118 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0,
117 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0,
119 independent=False, extra_arguments=[]):
118 independent=False, extra_arguments=[]):
120 """ Launches a localhost kernel, binding to the specified ports.
119 """ Launches a localhost kernel, binding to the specified ports.
121
120
122 Parameters
121 Parameters
123 ----------
122 ----------
124 code : str,
123 code : str,
125 A string of Python code that imports and executes a kernel entry point.
124 A string of Python code that imports and executes a kernel entry point.
126
125
127 xrep_port : int, optional
126 xrep_port : int, optional
128 The port to use for XREP channel.
127 The port to use for XREP channel.
129
128
130 pub_port : int, optional
129 pub_port : int, optional
131 The port to use for the SUB channel.
130 The port to use for the SUB channel.
132
131
133 req_port : int, optional
132 req_port : int, optional
134 The port to use for the REQ (raw input) channel.
133 The port to use for the REQ (raw input) channel.
135
134
136 independent : bool, optional (default False)
135 independent : bool, optional (default False)
137 If set, the kernel process is guaranteed to survive if this process
136 If set, the kernel process is guaranteed to survive if this process
138 dies. If not set, an effort is made to ensure that the kernel is killed
137 dies. If not set, an effort is made to ensure that the kernel is killed
139 when this process dies. Note that in this case it is still good practice
138 when this process dies. Note that in this case it is still good practice
140 to kill kernels manually before exiting.
139 to kill kernels manually before exiting.
141
140
142 extra_arguments = list, optional
141 extra_arguments = list, optional
143 A list of extra arguments to pass when executing the launch code.
142 A list of extra arguments to pass when executing the launch code.
144
143
145 Returns
144 Returns
146 -------
145 -------
147 A tuple of form:
146 A tuple of form:
148 (kernel_process, xrep_port, pub_port, req_port)
147 (kernel_process, xrep_port, pub_port, req_port)
149 where kernel_process is a Popen object and the ports are integers.
148 where kernel_process is a Popen object and the ports are integers.
150 """
149 """
151 # Find open ports as necessary.
150 # Find open ports as necessary.
152 ports = []
151 ports = []
153 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
152 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
154 for i in xrange(ports_needed):
153 for i in xrange(ports_needed):
155 sock = socket.socket()
154 sock = socket.socket()
156 sock.bind(('', 0))
155 sock.bind(('', 0))
157 ports.append(sock)
156 ports.append(sock)
158 for i, sock in enumerate(ports):
157 for i, sock in enumerate(ports):
159 port = sock.getsockname()[1]
158 port = sock.getsockname()[1]
160 sock.close()
159 sock.close()
161 ports[i] = port
160 ports[i] = port
162 if xrep_port <= 0:
161 if xrep_port <= 0:
163 xrep_port = ports.pop(0)
162 xrep_port = ports.pop(0)
164 if pub_port <= 0:
163 if pub_port <= 0:
165 pub_port = ports.pop(0)
164 pub_port = ports.pop(0)
166 if req_port <= 0:
165 if req_port <= 0:
167 req_port = ports.pop(0)
166 req_port = ports.pop(0)
168
167
169 # Build the kernel launch command.
168 # Build the kernel launch command.
170 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
169 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
171 '--pub', str(pub_port), '--req', str(req_port) ]
170 '--pub', str(pub_port), '--req', str(req_port) ]
172 arguments.extend(extra_arguments)
171 arguments.extend(extra_arguments)
173
172
174 # Spawn a kernel.
173 # Spawn a kernel.
175 if independent:
174 if independent:
176 if sys.platform == 'win32':
175 if sys.platform == 'win32':
177 proc = Popen(['start', '/b'] + arguments, shell=True)
176 proc = Popen(['start', '/b'] + arguments, shell=True)
178 else:
177 else:
179 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
178 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
180 else:
179 else:
181 if sys.platform == 'win32':
180 if sys.platform == 'win32':
182 from _subprocess import DuplicateHandle, GetCurrentProcess, \
181 from _subprocess import DuplicateHandle, GetCurrentProcess, \
183 DUPLICATE_SAME_ACCESS
182 DUPLICATE_SAME_ACCESS
184 pid = GetCurrentProcess()
183 pid = GetCurrentProcess()
185 handle = DuplicateHandle(pid, pid, pid, 0,
184 handle = DuplicateHandle(pid, pid, pid, 0,
186 True, # Inheritable by new processes.
185 True, # Inheritable by new processes.
187 DUPLICATE_SAME_ACCESS)
186 DUPLICATE_SAME_ACCESS)
188 proc = Popen(arguments + ['--parent', str(int(handle))])
187 proc = Popen(arguments + ['--parent', str(int(handle))])
189 else:
188 else:
190 proc = Popen(arguments + ['--parent'])
189 proc = Popen(arguments + ['--parent'])
191
190
192 return proc, xrep_port, pub_port, req_port
191 return proc, xrep_port, pub_port, req_port
General Comments 0
You need to be logged in to leave comments. Login now