debuggers.hg

view tools/python/xen/xend/server/SrvDaemon.py @ 4655:a838a908e38e

bitkeeper revision 1.1327.2.2 (4267a9b3MhPpljnjQ5IbfLdzcW2K3w)

Remove twisted from the HTTP server and replace with a
threaded server. Add classes to provide tcp and unix servers
using threads instead of twisted. Remove use of twisted from
the consoles, event server and HTTP resources

Signed-off-by: Mike Wray <mike.wray@hp.com>
author mjw@wray-m-3.hpl.hp.com
date Thu Apr 21 13:25:07 2005 +0000 (2005-04-21)
parents c69fbe48a357
children d781b9d08e80
line source
1 ###########################################################
2 ## Xen controller daemon
3 ## Copyright (c) 2004, K A Fraser (University of Cambridge)
4 ## Copyright (C) 2004, Mike Wray <mike.wray@hp.com>
5 ###########################################################
7 import os
8 import os.path
9 import signal
10 import sys
11 import threading
12 import linecache
13 import socket
14 import pwd
15 import re
16 import StringIO
17 import traceback
18 import time
20 #from twisted.internet import pollreactor; pollreactor.install()
21 from twisted.internet import reactor
23 from xen.lowlevel import xu
25 from xen.xend import sxp
26 from xen.xend import PrettyPrint
27 from xen.xend import EventServer; eserver = EventServer.instance()
28 from xen.xend.XendError import XendError
29 from xen.xend.server import SrvServer
30 from xen.xend import XendRoot
31 from xen.xend.XendLogging import log
33 from xen.util.ip import _readline, _readlines
35 import channel
36 import controller
37 import event
38 from params import *
40 DAEMONIZE = 0
41 DEBUG = 1
43 class Daemon:
44 """The xend daemon.
45 """
46 def __init__(self):
47 self.shutdown = 0
48 self.traceon = 0
50 def daemon_pids(self):
51 pids = []
52 pidex = '(?P<pid>\d+)'
53 pythonex = '(?P<python>\S*python\S*)'
54 cmdex = '(?P<cmd>.*)'
55 procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
56 xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
57 procs = os.popen('ps -e -o pid,args 2>/dev/null')
58 for proc in procs:
59 pm = procre.match(proc)
60 if not pm: continue
61 xm = xendre.match(pm.group('cmd'))
62 if not xm: continue
63 #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
64 pids.append(int(pm.group('pid')))
65 return pids
67 def new_cleanup(self, kill=0):
68 err = 0
69 pids = self.daemon_pids()
70 if kill:
71 for pid in pids:
72 print "Killing daemon pid=%d" % pid
73 os.kill(pid, signal.SIGHUP)
74 elif pids:
75 err = 1
76 print "Daemon already running: ", pids
77 return err
79 def read_pid(self, pidfile):
80 """Read process id from a file.
82 @param pidfile: file to read
83 @return pid or 0
84 """
85 pid = 0
86 if os.path.isfile(pidfile) and os.path.getsize(pidfile):
87 try:
88 pid = open(pidfile, 'r').read()
89 pid = int(pid)
90 except:
91 pid = 0
92 return pid
94 def find_process(self, pid, name):
95 """Search for a process.
97 @param pid: process id
98 @param name: process name
99 @return: pid if found, 0 otherwise
100 """
101 running = 0
102 if pid:
103 lines = _readlines(os.popen('ps %d 2>/dev/null' % pid))
104 exp = '^ *%d.+%s' % (pid, name)
105 for line in lines:
106 if re.search(exp, line):
107 running = pid
108 break
109 return running
111 def cleanup_process(self, pidfile, name, kill):
112 """Clean up the pidfile for a process.
113 If a running process is found, kills it if 'kill' is true.
115 @param pidfile: pid file
116 @param name: process name
117 @param kill: whether to kill the process
118 @return running process id or 0
119 """
120 running = 0
121 pid = self.read_pid(pidfile)
122 if self.find_process(pid, name):
123 if kill:
124 os.kill(pid, 1)
125 else:
126 running = pid
127 if running == 0 and os.path.isfile(pidfile):
128 os.remove(pidfile)
129 return running
131 def cleanup_xend(self, kill=False):
132 return self.cleanup_process(XEND_PID_FILE, "xend", kill)
134 def cleanup_xfrd(self, kill=False):
135 return self.cleanup_process(XFRD_PID_FILE, "xfrd", kill)
137 def cleanup(self, kill=False):
138 self.cleanup_xend(kill=kill)
139 self.cleanup_xfrd(kill=kill)
141 def status(self):
142 """Returns the status of the xend and xfrd daemons.
143 The return value is defined by the LSB:
144 0 Running
145 3 Not running
146 """
147 if (self.cleanup_process(XEND_PID_FILE, "xend", False) == 0 or
148 self.cleanup_process(XFRD_PID_FILE, "xfrd", False) == 0):
149 return 3
150 else:
151 return 0
153 def install_child_reaper(self):
154 #signal.signal(signal.SIGCHLD, self.onSIGCHLD)
155 # Ensure that zombie children are automatically reaped.
156 xu.autoreap()
158 def onSIGCHLD(self, signum, frame):
159 code = 1
160 while code > 0:
161 code = os.waitpid(-1, os.WNOHANG)
163 def fork_pid(self, pidfile):
164 """Fork and write the pid of the child to 'pidfile'.
166 @param pidfile: pid file
167 @return: pid of child in parent, 0 in child
168 """
169 pid = os.fork()
170 if pid:
171 # Parent
172 pidfile = open(pidfile, 'w')
173 pidfile.write(str(pid))
174 pidfile.close()
175 return pid
177 def start_xfrd(self):
178 """Fork and exec xfrd, writing its pid to XFRD_PID_FILE.
179 """
180 if self.fork_pid(XFRD_PID_FILE):
181 # Parent
182 pass
183 else:
184 # Child
185 self.daemonize()
186 os.execl("/usr/sbin/xfrd", "xfrd")
188 def daemonize(self):
189 if not DAEMONIZE: return
190 # Detach from TTY.
191 os.setsid()
193 # Detach from standard file descriptors.
194 # I do this at the file-descriptor level: the overlying Python file
195 # objects also use fd's 0, 1 and 2.
196 os.close(0)
197 os.close(1)
198 os.close(2)
199 if DEBUG:
200 os.open('/dev/null', os.O_RDONLY)
201 # XXX KAF: Why doesn't this capture output from C extensions that
202 # fprintf(stdout) or fprintf(stderr) ??
203 os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
204 os.dup(1)
205 else:
206 os.open('/dev/null', os.O_RDWR)
207 os.dup(0)
208 os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
211 def start(self, trace=0):
212 """Attempts to start the daemons.
213 The return value is defined by the LSB:
214 0 Success
215 4 Insufficient privileges
216 """
217 xend_pid = self.cleanup_xend()
218 xfrd_pid = self.cleanup_xfrd()
221 if self.set_user():
222 return 4
223 os.chdir("/")
225 if xfrd_pid == 0:
226 self.start_xfrd()
227 if xend_pid > 0:
228 # Trying to run an already-running service is a success.
229 return 0
231 self.install_child_reaper()
233 if self.fork_pid(XEND_PID_FILE):
234 #Parent. Sleep to give child time to start.
235 time.sleep(1)
236 else:
237 # Child
238 self.tracing(trace)
239 self.run()
240 return 0
242 def tracing(self, traceon):
243 """Turn tracing on or off.
245 @param traceon: tracing flag
246 """
247 if traceon == self.traceon:
248 return
249 self.traceon = traceon
250 if traceon:
251 self.tracefile = open(XEND_TRACE_FILE, 'w+', 1)
252 self.traceindent = 0
253 sys.settrace(self.trace)
254 try:
255 threading.settrace(self.trace) # Only in Python >= 2.3
256 except:
257 pass
259 def print_trace(self, str):
260 for i in range(self.traceindent):
261 ch = " "
262 if (i % 5):
263 ch = ' '
264 else:
265 ch = '|'
266 self.tracefile.write(ch)
267 self.tracefile.write(str)
269 def trace(self, frame, event, arg):
270 if not self.traceon:
271 print >>self.tracefile
272 print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20
273 self.tracefile.close()
274 self.tracefile = None
275 return None
276 if event == 'call':
277 code = frame.f_code
278 filename = code.co_filename
279 m = re.search('.*xend/(.*)', filename)
280 if not m:
281 return None
282 modulename = m.group(1)
283 if re.search('sxp.py', modulename):
284 return None
285 self.traceindent += 1
286 self.print_trace("> %s:%s\n"
287 % (modulename, code.co_name))
288 elif event == 'line':
289 filename = frame.f_code.co_filename
290 lineno = frame.f_lineno
291 self.print_trace("%4d %s" %
292 (lineno, linecache.getline(filename, lineno)))
293 elif event == 'return':
294 code = frame.f_code
295 filename = code.co_filename
296 m = re.search('.*xend/(.*)', filename)
297 if not m:
298 return None
299 modulename = m.group(1)
300 self.print_trace("< %s:%s\n"
301 % (modulename, code.co_name))
302 self.traceindent -= 1
303 elif event == 'exception':
304 self.print_trace("! Exception:\n")
305 (ex, val, tb) = arg
306 traceback.print_exception(ex, val, tb, 10, self.tracefile)
307 #del tb
308 return self.trace
310 def set_user(self):
311 # Set the UID.
312 try:
313 os.setuid(pwd.getpwnam(XEND_USER)[2])
314 return 0
315 except KeyError, error:
316 print "Error: no such user '%s'" % XEND_USER
317 return 1
319 def stop(self):
320 return self.cleanup(kill=True)
322 def run(self):
323 try:
324 xroot = XendRoot.instance()
325 log.info("Xend Daemon started")
326 self.createFactories()
327 self.listenEvent(xroot)
328 self.listenChannels()
329 serverthread = SrvServer.create(bridge=1)
330 self.daemonize()
331 print 'running serverthread...'
332 serverthread.start()
333 print 'running reactor...'
334 reactor.run()
335 except Exception, ex:
336 print >>sys.stderr, 'Exception starting xend:', ex
337 if DEBUG:
338 traceback.print_exc()
339 log.exception("Exception starting xend")
340 self.exit(1)
342 def createFactories(self):
343 self.channelF = channel.channelFactory()
345 def listenEvent(self, xroot):
346 port = xroot.get_xend_event_port()
347 interface = xroot.get_xend_address()
348 return event.listenEvent(self, port, interface)
350 def listenChannels(self):
351 def virqReceived(virq):
352 print 'virqReceived>', virq
353 eserver.inject('xend.virq', virq)
355 self.channelF.setVirqHandler(virqReceived)
356 self.channelF.start()
358 def exit(self, rc=0):
359 reactor.disconnectAll()
360 self.channelF.stop()
361 # Calling sys.exit() raises a SystemExit exception, which only
362 # kills the current thread. Calling os._exit() makes the whole
363 # Python process exit immediately. There doesn't seem to be another
364 # way to exit a Python with running threads.
365 #sys.exit(rc)
366 os._exit(rc)
368 def instance():
369 global inst
370 try:
371 inst
372 except:
373 inst = Daemon()
374 return inst