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