blob: 6c37967513cabba5bf07f1eb5a924dc74b2ee18e [file] [log] [blame]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001#!/usr/bin/env python3
Brad Bishopc342db32019-05-15 21:57:59 -04002#
3# SPDX-License-Identifier: GPL-2.0-only
4#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05005
6import os
7import sys
8import warnings
9sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
10from bb import fetch2
11import logging
12import bb
13import select
14import errno
15import signal
Patrick Williamsc0f7c042017-02-23 20:41:17 -060016import pickle
Brad Bishop37a0e4d2017-12-04 01:01:44 -050017import traceback
18import queue
Patrick Williamsf1e5d692016-03-30 15:21:19 -050019from multiprocessing import Lock
Brad Bishop37a0e4d2017-12-04 01:01:44 -050020from threading import Thread
Patrick Williamsc124f4f2015-09-15 14:41:29 -050021
Patrick Williamsc0f7c042017-02-23 20:41:17 -060022if sys.getfilesystemencoding() != "utf-8":
Brad Bishopd7bf8c12018-02-25 22:55:05 -050023 sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\nPython can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -060024
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025# Users shouldn't be running this code directly
26if len(sys.argv) != 2 or not sys.argv[1].startswith("decafbad"):
27 print("bitbake-worker is meant for internal execution by bitbake itself, please don't use it standalone.")
28 sys.exit(1)
29
30profiling = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050031if sys.argv[1].startswith("decafbadbad"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032 profiling = True
33 try:
34 import cProfile as profile
35 except:
36 import profile
37
38# Unbuffer stdout to avoid log truncation in the event
39# of an unorderly exit as well as to provide timely
40# updates to log files for use with tail
41try:
42 if sys.stdout.name == '<stdout>':
Patrick Williamsc0f7c042017-02-23 20:41:17 -060043 import fcntl
44 fl = fcntl.fcntl(sys.stdout.fileno(), fcntl.F_GETFL)
45 fl |= os.O_SYNC
46 fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, fl)
47 #sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048except:
49 pass
50
51logger = logging.getLogger("BitBake")
52
Patrick Williamsc124f4f2015-09-15 14:41:29 -050053worker_pipe = sys.stdout.fileno()
54bb.utils.nonblockingfd(worker_pipe)
Patrick Williamsf1e5d692016-03-30 15:21:19 -050055# Need to guard against multiprocessing being used in child processes
56# and multiple processes trying to write to the parent at the same time
57worker_pipe_lock = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058
59handler = bb.event.LogHandler()
60logger.addHandler(handler)
61
62if 0:
63 # Code to write out a log file of all events passing through the worker
64 logfilename = "/tmp/workerlogfile"
65 format_str = "%(levelname)s: %(message)s"
66 conlogformat = bb.msg.BBLogFormatter(format_str)
67 consolelog = logging.FileHandler(logfilename)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068 consolelog.setFormatter(conlogformat)
69 logger.addHandler(consolelog)
70
Brad Bishop37a0e4d2017-12-04 01:01:44 -050071worker_queue = queue.Queue()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050072
73def worker_fire(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060074 data = b"<event>" + pickle.dumps(event) + b"</event>"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050075 worker_fire_prepickled(data)
76
77def worker_fire_prepickled(event):
78 global worker_queue
79
Brad Bishop37a0e4d2017-12-04 01:01:44 -050080 worker_queue.put(event)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050081
Brad Bishop37a0e4d2017-12-04 01:01:44 -050082#
83# We can end up with write contention with the cooker, it can be trying to send commands
84# and we can be trying to send event data back. Therefore use a separate thread for writing
85# back data to cooker.
86#
87worker_thread_exit = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050088
Brad Bishop37a0e4d2017-12-04 01:01:44 -050089def worker_flush(worker_queue):
90 worker_queue_int = b""
91 global worker_pipe, worker_thread_exit
Patrick Williamsc124f4f2015-09-15 14:41:29 -050092
Brad Bishop37a0e4d2017-12-04 01:01:44 -050093 while True:
94 try:
95 worker_queue_int = worker_queue_int + worker_queue.get(True, 1)
96 except queue.Empty:
97 pass
98 while (worker_queue_int or not worker_queue.empty()):
99 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500100 (_, ready, _) = select.select([], [worker_pipe], [], 1)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500101 if not worker_queue.empty():
102 worker_queue_int = worker_queue_int + worker_queue.get()
103 written = os.write(worker_pipe, worker_queue_int)
104 worker_queue_int = worker_queue_int[written:]
105 except (IOError, OSError) as e:
106 if e.errno != errno.EAGAIN and e.errno != errno.EPIPE:
107 raise
108 if worker_thread_exit and worker_queue.empty() and not worker_queue_int:
109 return
110
111worker_thread = Thread(target=worker_flush, args=(worker_queue,))
112worker_thread.start()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500113
114def worker_child_fire(event, d):
115 global worker_pipe
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500116 global worker_pipe_lock
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600118 data = b"<event>" + pickle.dumps(event) + b"</event>"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500119 try:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500120 worker_pipe_lock.acquire()
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600121 while(len(data)):
122 written = worker_pipe.write(data)
123 data = data[written:]
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500124 worker_pipe_lock.release()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 except IOError:
126 sigterm_handler(None, None)
127 raise
128
129bb.event.worker_fire = worker_fire
130
131lf = None
132#lf = open("/tmp/workercommandlog", "w+")
133def workerlog_write(msg):
134 if lf:
135 lf.write(msg)
136 lf.flush()
137
138def sigterm_handler(signum, frame):
139 signal.signal(signal.SIGTERM, signal.SIG_DFL)
140 os.killpg(0, signal.SIGTERM)
141 sys.exit()
142
Brad Bishop19323692019-04-05 15:28:33 -0400143def fork_off_task(cfg, data, databuilder, workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, extraconfigdata, quieterrors=False, dry_run_exec=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144 # We need to setup the environment BEFORE the fork, since
145 # a fork() or exec*() activates PSEUDO...
146
147 envbackup = {}
148 fakeenv = {}
149 umask = None
150
151 taskdep = workerdata["taskdeps"][fn]
152 if 'umask' in taskdep and taskname in taskdep['umask']:
153 # umask might come in as a number or text string..
154 try:
155 umask = int(taskdep['umask'][taskname],8)
156 except TypeError:
157 umask = taskdep['umask'][taskname]
158
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500159 dry_run = cfg.dry_run or dry_run_exec
160
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161 # We can't use the fakeroot environment in a dry run as it possibly hasn't been built
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500162 if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not dry_run:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163 envvars = (workerdata["fakerootenv"][fn] or "").split()
164 for key, value in (var.split('=') for var in envvars):
165 envbackup[key] = os.environ.get(key)
166 os.environ[key] = value
167 fakeenv[key] = value
168
169 fakedirs = (workerdata["fakerootdirs"][fn] or "").split()
170 for p in fakedirs:
171 bb.utils.mkdirhier(p)
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600172 logger.debug2('Running %s:%s under fakeroot, fakedirs: %s' %
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173 (fn, taskname, ', '.join(fakedirs)))
174 else:
175 envvars = (workerdata["fakerootnoenv"][fn] or "").split()
176 for key, value in (var.split('=') for var in envvars):
177 envbackup[key] = os.environ.get(key)
178 os.environ[key] = value
179 fakeenv[key] = value
180
181 sys.stdout.flush()
182 sys.stderr.flush()
183
184 try:
185 pipein, pipeout = os.pipe()
186 pipein = os.fdopen(pipein, 'rb', 4096)
187 pipeout = os.fdopen(pipeout, 'wb', 0)
188 pid = os.fork()
189 except OSError as e:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 logger.critical("fork failed: %d (%s)" % (e.errno, e.strerror))
191 sys.exit(1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500192
193 if pid == 0:
194 def child():
195 global worker_pipe
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500196 global worker_pipe_lock
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500197 pipein.close()
198
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500199 bb.utils.signal_on_parent_exit("SIGTERM")
200
201 # Save out the PID so that the event can include it the
202 # events
203 bb.event.worker_pid = os.getpid()
204 bb.event.worker_fire = worker_child_fire
205 worker_pipe = pipeout
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500206 worker_pipe_lock = Lock()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500207
208 # Make the child the process group leader and ensure no
209 # child process will be controlled by the current terminal
210 # This ensures signals sent to the controlling terminal like Ctrl+C
211 # don't stop the child processes.
212 os.setsid()
Brad Bishop1d80a2e2019-11-15 16:35:03 -0500213
214 signal.signal(signal.SIGTERM, sigterm_handler)
215 # Let SIGHUP exit as SIGTERM
216 signal.signal(signal.SIGHUP, sigterm_handler)
217
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500218 # No stdin
219 newsi = os.open(os.devnull, os.O_RDWR)
220 os.dup2(newsi, sys.stdin.fileno())
221
222 if umask:
223 os.umask(umask)
224
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500225 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600226 bb_cache = bb.cache.NoCache(databuilder)
227 (realfn, virtual, mc) = bb.cache.virtualfn2realfn(fn)
228 the_data = databuilder.mcdata[mc]
229 the_data.setVar("BB_WORKERCONTEXT", "1")
230 the_data.setVar("BB_TASKDEPDATA", taskdepdata)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500231 if cfg.limited_deps:
232 the_data.setVar("BB_LIMITEDDEPS", "1")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600233 the_data.setVar("BUILDNAME", workerdata["buildname"])
234 the_data.setVar("DATE", workerdata["date"])
235 the_data.setVar("TIME", workerdata["time"])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500236 for varname, value in extraconfigdata.items():
237 the_data.setVar(varname, value)
238
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600239 bb.parse.siggen.set_taskdata(workerdata["sigdata"])
Brad Bishop08902b02019-08-20 09:16:51 -0400240 if "newhashes" in workerdata:
241 bb.parse.siggen.set_taskhashes(workerdata["newhashes"])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600242 ret = 0
243
244 the_data = bb_cache.loadDataFull(fn, appends)
Brad Bishop19323692019-04-05 15:28:33 -0400245 the_data.setVar('BB_TASKHASH', taskhash)
246 the_data.setVar('BB_UNIHASH', unihash)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500247
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500248 bb.utils.set_process_name("%s:%s" % (the_data.getVar("PN"), taskname.replace("do_", "")))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500249
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250 # exported_vars() returns a generator which *cannot* be passed to os.environ.update()
251 # successfully. We also need to unset anything from the environment which shouldn't be there
252 exports = bb.data.exported_vars(the_data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600253
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500254 bb.utils.empty_environment()
255 for e, v in exports:
256 os.environ[e] = v
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600257
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500258 for e in fakeenv:
259 os.environ[e] = fakeenv[e]
260 the_data.setVar(e, fakeenv[e])
261 the_data.setVarFlag(e, 'export', "1")
262
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500263 task_exports = the_data.getVarFlag(taskname, 'exports')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600264 if task_exports:
265 for e in task_exports.split():
266 the_data.setVarFlag(e, 'export', '1')
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500267 v = the_data.getVar(e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600268 if v is not None:
269 os.environ[e] = v
270
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500271 if quieterrors:
272 the_data.setVarFlag(taskname, "quieterrors", "1")
273
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500274 except Exception:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500275 if not quieterrors:
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500276 logger.critical(traceback.format_exc())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500277 os._exit(1)
278 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500279 if dry_run:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280 return 0
281 return bb.build.exec_task(fn, taskname, the_data, cfg.profile)
282 except:
283 os._exit(1)
284 if not profiling:
285 os._exit(child())
286 else:
287 profname = "profile-%s.log" % (fn.replace("/", "-") + "-" + taskname)
288 prof = profile.Profile()
289 try:
290 ret = profile.Profile.runcall(prof, child)
291 finally:
292 prof.dump_stats(profname)
293 bb.utils.process_profilelog(profname)
294 os._exit(ret)
295 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600296 for key, value in iter(envbackup.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500297 if value is None:
298 del os.environ[key]
299 else:
300 os.environ[key] = value
301
302 return pid, pipein, pipeout
303
304class runQueueWorkerPipe():
305 """
306 Abstraction for a pipe between a worker thread and the worker server
307 """
308 def __init__(self, pipein, pipeout):
309 self.input = pipein
310 if pipeout:
311 pipeout.close()
312 bb.utils.nonblockingfd(self.input)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600313 self.queue = b""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500314
315 def read(self):
316 start = len(self.queue)
317 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600318 self.queue = self.queue + (self.input.read(102400) or b"")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500319 except (OSError, IOError) as e:
320 if e.errno != errno.EAGAIN:
321 raise
322
323 end = len(self.queue)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600324 index = self.queue.find(b"</event>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500325 while index != -1:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600326 msg = self.queue[:index+8]
327 assert msg.startswith(b"<event>") and msg.count(b"<event>") == 1
328 worker_fire_prepickled(msg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500329 self.queue = self.queue[index+8:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600330 index = self.queue.find(b"</event>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500331 return (end > start)
332
333 def close(self):
334 while self.read():
335 continue
336 if len(self.queue) > 0:
337 print("Warning, worker child left partial message: %s" % self.queue)
338 self.input.close()
339
340normalexit = False
341
342class BitbakeWorker(object):
343 def __init__(self, din):
344 self.input = din
345 bb.utils.nonblockingfd(self.input)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600346 self.queue = b""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500347 self.cookercfg = None
348 self.databuilder = None
349 self.data = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500350 self.extraconfigdata = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500351 self.build_pids = {}
352 self.build_pipes = {}
353
354 signal.signal(signal.SIGTERM, self.sigterm_exception)
355 # Let SIGHUP exit as SIGTERM
356 signal.signal(signal.SIGHUP, self.sigterm_exception)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500357 if "beef" in sys.argv[1]:
358 bb.utils.set_process_name("Worker (Fakeroot)")
359 else:
360 bb.utils.set_process_name("Worker")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500361
362 def sigterm_exception(self, signum, stackframe):
363 if signum == signal.SIGTERM:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500364 bb.warn("Worker received SIGTERM, shutting down...")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500365 elif signum == signal.SIGHUP:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500366 bb.warn("Worker received SIGHUP, shutting down...")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500367 self.handle_finishnow(None)
368 signal.signal(signal.SIGTERM, signal.SIG_DFL)
369 os.kill(os.getpid(), signal.SIGTERM)
370
371 def serve(self):
372 while True:
373 (ready, _, _) = select.select([self.input] + [i.input for i in self.build_pipes.values()], [] , [], 1)
374 if self.input in ready:
375 try:
376 r = self.input.read()
377 if len(r) == 0:
378 # EOF on pipe, server must have terminated
379 self.sigterm_exception(signal.SIGTERM, None)
380 self.queue = self.queue + r
381 except (OSError, IOError):
382 pass
383 if len(self.queue):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600384 self.handle_item(b"cookerconfig", self.handle_cookercfg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500385 self.handle_item(b"extraconfigdata", self.handle_extraconfigdata)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600386 self.handle_item(b"workerdata", self.handle_workerdata)
Brad Bishop08902b02019-08-20 09:16:51 -0400387 self.handle_item(b"newtaskhashes", self.handle_newtaskhashes)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600388 self.handle_item(b"runtask", self.handle_runtask)
389 self.handle_item(b"finishnow", self.handle_finishnow)
390 self.handle_item(b"ping", self.handle_ping)
391 self.handle_item(b"quit", self.handle_quit)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500392
393 for pipe in self.build_pipes:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500394 if self.build_pipes[pipe].input in ready:
395 self.build_pipes[pipe].read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500396 if len(self.build_pids):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500397 while self.process_waitpid():
398 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500399
400
401 def handle_item(self, item, func):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600402 if self.queue.startswith(b"<" + item + b">"):
403 index = self.queue.find(b"</" + item + b">")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500404 while index != -1:
405 func(self.queue[(len(item) + 2):index])
406 self.queue = self.queue[(index + len(item) + 3):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600407 index = self.queue.find(b"</" + item + b">")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500408
409 def handle_cookercfg(self, data):
410 self.cookercfg = pickle.loads(data)
411 self.databuilder = bb.cookerdata.CookerDataBuilder(self.cookercfg, worker=True)
412 self.databuilder.parseBaseConfiguration()
413 self.data = self.databuilder.data
414
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500415 def handle_extraconfigdata(self, data):
416 self.extraconfigdata = pickle.loads(data)
417
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500418 def handle_workerdata(self, data):
419 self.workerdata = pickle.loads(data)
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500420 bb.build.verboseShellLogging = self.workerdata["build_verbose_shell"]
421 bb.build.verboseStdoutLogging = self.workerdata["build_verbose_stdout"]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500422 bb.msg.loggerDefaultLogLevel = self.workerdata["logdefaultlevel"]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500423 bb.msg.loggerDefaultDomains = self.workerdata["logdefaultdomain"]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600424 for mc in self.databuilder.mcdata:
425 self.databuilder.mcdata[mc].setVar("PRSERV_HOST", self.workerdata["prhost"])
Brad Bishopa34c0302019-09-23 22:34:48 -0400426 self.databuilder.mcdata[mc].setVar("BB_HASHSERVE", self.workerdata["hashservaddr"])
Brad Bishop08902b02019-08-20 09:16:51 -0400427
428 def handle_newtaskhashes(self, data):
429 self.workerdata["newhashes"] = pickle.loads(data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500430
431 def handle_ping(self, _):
432 workerlog_write("Handling ping\n")
433
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600434 logger.warning("Pong from bitbake-worker!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435
436 def handle_quit(self, data):
437 workerlog_write("Handling quit\n")
438
439 global normalexit
440 normalexit = True
441 sys.exit(0)
442
443 def handle_runtask(self, data):
Brad Bishop19323692019-04-05 15:28:33 -0400444 fn, task, taskname, taskhash, unihash, quieterrors, appends, taskdepdata, dry_run_exec = pickle.loads(data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445 workerlog_write("Handling runtask %s %s %s\n" % (task, fn, taskname))
446
Brad Bishop19323692019-04-05 15:28:33 -0400447 pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.databuilder, self.workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, self.extraconfigdata, quieterrors, dry_run_exec)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500448
449 self.build_pids[pid] = task
450 self.build_pipes[pid] = runQueueWorkerPipe(pipein, pipeout)
451
452 def process_waitpid(self):
453 """
454 Return none is there are no processes awaiting result collection, otherwise
455 collect the process exit codes and close the information pipe.
456 """
457 try:
458 pid, status = os.waitpid(-1, os.WNOHANG)
459 if pid == 0 or os.WIFSTOPPED(status):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500460 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500461 except OSError:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500462 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500463
464 workerlog_write("Exit code of %s for pid %s\n" % (status, pid))
465
466 if os.WIFEXITED(status):
467 status = os.WEXITSTATUS(status)
468 elif os.WIFSIGNALED(status):
469 # Per shell conventions for $?, when a process exits due to
470 # a signal, we return an exit code of 128 + SIGNUM
471 status = 128 + os.WTERMSIG(status)
472
473 task = self.build_pids[pid]
474 del self.build_pids[pid]
475
476 self.build_pipes[pid].close()
477 del self.build_pipes[pid]
478
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600479 worker_fire_prepickled(b"<exitcode>" + pickle.dumps((task, status)) + b"</exitcode>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500480
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500481 return True
482
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483 def handle_finishnow(self, _):
484 if self.build_pids:
485 logger.info("Sending SIGTERM to remaining %s tasks", len(self.build_pids))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600486 for k, v in iter(self.build_pids.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500487 try:
488 os.kill(-k, signal.SIGTERM)
489 os.waitpid(-1, 0)
490 except:
491 pass
492 for pipe in self.build_pipes:
493 self.build_pipes[pipe].read()
494
495try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600496 worker = BitbakeWorker(os.fdopen(sys.stdin.fileno(), 'rb'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500497 if not profiling:
498 worker.serve()
499 else:
500 profname = "profile-worker.log"
501 prof = profile.Profile()
502 try:
503 profile.Profile.runcall(prof, worker.serve)
504 finally:
505 prof.dump_stats(profname)
506 bb.utils.process_profilelog(profname)
507except BaseException as e:
508 if not normalexit:
509 import traceback
510 sys.stderr.write(traceback.format_exc())
511 sys.stderr.write(str(e))
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500512
513worker_thread_exit = True
514worker_thread.join()
515
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500516workerlog_write("exitting")
517sys.exit(0)