summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/prserv
diff options
context:
space:
mode:
authorPaul Barker <pbarker@konsulko.com>2021-04-29 15:11:11 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2021-05-06 11:08:07 +0100
commitd66a1d83f53811da8ecbee91e9d0c3f189b661ea (patch)
treea867d87b48ef690a2519a5164c232bfb1b8beb45 /bitbake/lib/prserv
parent802024fd2a63bdbffbfaf125513561799452e4d2 (diff)
downloadpoky-d66a1d83f53811da8ecbee91e9d0c3f189b661ea.tar.gz
bitbake: prserv: Extract daemonization from PRServer class
The code to start the prservice process as a daemon is extracted out of the PRServer class and simplified. This makes the PRServer class easier to modernise as it no longer needs to worry about process management. (Bitbake rev: 39c7c158c52157b18f5ccbbd673e3298e6402f52) Signed-off-by: Paul Barker <pbarker@konsulko.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/prserv')
-rw-r--r--bitbake/lib/prserv/serv.py175
1 files changed, 72 insertions, 103 deletions
diff --git a/bitbake/lib/prserv/serv.py b/bitbake/lib/prserv/serv.py
index 5d6520da80..24a8c4bacf 100644
--- a/bitbake/lib/prserv/serv.py
+++ b/bitbake/lib/prserv/serv.py
@@ -34,7 +34,7 @@ singleton = None
34 34
35 35
36class PRServer(SimpleXMLRPCServer): 36class PRServer(SimpleXMLRPCServer):
37 def __init__(self, dbfile, logfile, interface, daemon=True): 37 def __init__(self, dbfile, logfile, interface):
38 ''' constructor ''' 38 ''' constructor '''
39 try: 39 try:
40 SimpleXMLRPCServer.__init__(self, interface, 40 SimpleXMLRPCServer.__init__(self, interface,
@@ -47,7 +47,6 @@ class PRServer(SimpleXMLRPCServer):
47 raise PRServiceConfigError 47 raise PRServiceConfigError
48 48
49 self.dbfile=dbfile 49 self.dbfile=dbfile
50 self.daemon=daemon
51 self.logfile=logfile 50 self.logfile=logfile
52 self.working_thread=None 51 self.working_thread=None
53 self.host, self.port = self.socket.getsockname() 52 self.host, self.port = self.socket.getsockname()
@@ -176,106 +175,6 @@ class PRServer(SimpleXMLRPCServer):
176 os.close(self.quitpipein) 175 os.close(self.quitpipein)
177 return 176 return
178 177
179 def start(self):
180 if self.daemon:
181 pid = self.daemonize()
182 else:
183 pid = self.fork()
184 self.pid = pid
185
186 # Ensure both the parent sees this and the child from the work_forever log entry above
187 logger.info("Started PRServer with DBfile: %s, IP: %s, PORT: %s, PID: %s" %
188 (self.dbfile, self.host, self.port, str(pid)))
189
190 def delpid(self):
191 os.remove(self.pidfile)
192
193 def daemonize(self):
194 """
195 See Advanced Programming in the UNIX, Sec 13.3
196 """
197 try:
198 pid = os.fork()
199 if pid > 0:
200 os.waitpid(pid, 0)
201 #parent return instead of exit to give control
202 return pid
203 except OSError as e:
204 raise Exception("%s [%d]" % (e.strerror, e.errno))
205
206 os.setsid()
207 """
208 fork again to make sure the daemon is not session leader,
209 which prevents it from acquiring controlling terminal
210 """
211 try:
212 pid = os.fork()
213 if pid > 0: #parent
214 os._exit(0)
215 except OSError as e:
216 raise Exception("%s [%d]" % (e.strerror, e.errno))
217
218 self.cleanup_handles()
219 os._exit(0)
220
221 def fork(self):
222 try:
223 pid = os.fork()
224 if pid > 0:
225 self.socket.close() # avoid ResourceWarning in parent
226 return pid
227 except OSError as e:
228 raise Exception("%s [%d]" % (e.strerror, e.errno))
229
230 bb.utils.signal_on_parent_exit("SIGTERM")
231 self.cleanup_handles()
232 os._exit(0)
233
234 def cleanup_handles(self):
235 os.chdir("/")
236
237 sys.stdout.flush()
238 sys.stderr.flush()
239
240 # We could be called from a python thread with io.StringIO as
241 # stdout/stderr or it could be 'real' unix fd forking where we need
242 # to physically close the fds to prevent the program launching us from
243 # potentially hanging on a pipe. Handle both cases.
244 si = open('/dev/null', 'r')
245 try:
246 os.dup2(si.fileno(),sys.stdin.fileno())
247 except (AttributeError, io.UnsupportedOperation):
248 sys.stdin = si
249 so = open(self.logfile, 'a+')
250 try:
251 os.dup2(so.fileno(),sys.stdout.fileno())
252 except (AttributeError, io.UnsupportedOperation):
253 sys.stdout = so
254 try:
255 os.dup2(so.fileno(),sys.stderr.fileno())
256 except (AttributeError, io.UnsupportedOperation):
257 sys.stderr = so
258
259 # Clear out all log handlers prior to the fork() to avoid calling
260 # event handlers not part of the PRserver
261 for logger_iter in logging.Logger.manager.loggerDict.keys():
262 logging.getLogger(logger_iter).handlers = []
263
264 # Ensure logging makes it to the logfile
265 streamhandler = logging.StreamHandler()
266 streamhandler.setLevel(logging.DEBUG)
267 formatter = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
268 streamhandler.setFormatter(formatter)
269 logger.addHandler(streamhandler)
270
271 # write pidfile
272 pid = str(os.getpid())
273 with open(self.pidfile, 'w') as pf:
274 pf.write("%s\n" % pid)
275
276 self.work_forever()
277 self.delpid()
278
279class PRServSingleton(object): 178class PRServSingleton(object):
280 def __init__(self, dbfile, logfile, interface): 179 def __init__(self, dbfile, logfile, interface):
281 self.dbfile = dbfile 180 self.dbfile = dbfile
@@ -324,6 +223,76 @@ class PRServerConnection(object):
324 def getinfo(self): 223 def getinfo(self):
325 return self.host, self.port 224 return self.host, self.port
326 225
226def run_as_daemon(func, pidfile, logfile):
227 """
228 See Advanced Programming in the UNIX, Sec 13.3
229 """
230 try:
231 pid = os.fork()
232 if pid > 0:
233 os.waitpid(pid, 0)
234 #parent return instead of exit to give control
235 return pid
236 except OSError as e:
237 raise Exception("%s [%d]" % (e.strerror, e.errno))
238
239 os.setsid()
240 """
241 fork again to make sure the daemon is not session leader,
242 which prevents it from acquiring controlling terminal
243 """
244 try:
245 pid = os.fork()
246 if pid > 0: #parent
247 os._exit(0)
248 except OSError as e:
249 raise Exception("%s [%d]" % (e.strerror, e.errno))
250
251 os.chdir("/")
252
253 sys.stdout.flush()
254 sys.stderr.flush()
255
256 # We could be called from a python thread with io.StringIO as
257 # stdout/stderr or it could be 'real' unix fd forking where we need
258 # to physically close the fds to prevent the program launching us from
259 # potentially hanging on a pipe. Handle both cases.
260 si = open('/dev/null', 'r')
261 try:
262 os.dup2(si.fileno(),sys.stdin.fileno())
263 except (AttributeError, io.UnsupportedOperation):
264 sys.stdin = si
265 so = open(logfile, 'a+')
266 try:
267 os.dup2(so.fileno(),sys.stdout.fileno())
268 except (AttributeError, io.UnsupportedOperation):
269 sys.stdout = so
270 try:
271 os.dup2(so.fileno(),sys.stderr.fileno())
272 except (AttributeError, io.UnsupportedOperation):
273 sys.stderr = so
274
275 # Clear out all log handlers prior to the fork() to avoid calling
276 # event handlers not part of the PRserver
277 for logger_iter in logging.Logger.manager.loggerDict.keys():
278 logging.getLogger(logger_iter).handlers = []
279
280 # Ensure logging makes it to the logfile
281 streamhandler = logging.StreamHandler()
282 streamhandler.setLevel(logging.DEBUG)
283 formatter = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
284 streamhandler.setFormatter(formatter)
285 logger.addHandler(streamhandler)
286
287 # write pidfile
288 pid = str(os.getpid())
289 with open(pidfile, 'w') as pf:
290 pf.write("%s\n" % pid)
291
292 func()
293 os.remove(pidfile)
294 os._exit(0)
295
327def start_daemon(dbfile, host, port, logfile): 296def start_daemon(dbfile, host, port, logfile):
328 ip = socket.gethostbyname(host) 297 ip = socket.gethostbyname(host)
329 pidfile = PIDPREFIX % (ip, port) 298 pidfile = PIDPREFIX % (ip, port)
@@ -339,7 +308,7 @@ def start_daemon(dbfile, host, port, logfile):
339 return 1 308 return 1
340 309
341 server = PRServer(os.path.abspath(dbfile), os.path.abspath(logfile), (ip,port)) 310 server = PRServer(os.path.abspath(dbfile), os.path.abspath(logfile), (ip,port))
342 server.start() 311 run_as_daemon(server.work_forever, pidfile, os.path.abspath(logfile))
343 312
344 # Sometimes, the port (i.e. localhost:0) indicated by the user does not match with 313 # Sometimes, the port (i.e. localhost:0) indicated by the user does not match with
345 # the one the server actually is listening, so at least warn the user about it 314 # the one the server actually is listening, so at least warn the user about it