blob: 6ead2da6d1e2116f005ccb95a088dedd65acd996 [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
Andrew Geissler5199d832021-09-24 16:47:35 -05009warnings.simplefilter("default")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
11from bb import fetch2
12import logging
13import bb
14import select
15import errno
16import signal
Patrick Williamsc0f7c042017-02-23 20:41:17 -060017import pickle
Brad Bishop37a0e4d2017-12-04 01:01:44 -050018import traceback
19import queue
Patrick Williamsf1e5d692016-03-30 15:21:19 -050020from multiprocessing import Lock
Brad Bishop37a0e4d2017-12-04 01:01:44 -050021from threading import Thread
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022
Patrick Williamsc0f7c042017-02-23 20:41:17 -060023if sys.getfilesystemencoding() != "utf-8":
Brad Bishopd7bf8c12018-02-25 22:55:05 -050024 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 -060025
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026# Users shouldn't be running this code directly
27if len(sys.argv) != 2 or not sys.argv[1].startswith("decafbad"):
28 print("bitbake-worker is meant for internal execution by bitbake itself, please don't use it standalone.")
29 sys.exit(1)
30
31profiling = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050032if sys.argv[1].startswith("decafbadbad"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050033 profiling = True
34 try:
35 import cProfile as profile
36 except:
37 import profile
38
39# Unbuffer stdout to avoid log truncation in the event
40# of an unorderly exit as well as to provide timely
41# updates to log files for use with tail
42try:
43 if sys.stdout.name == '<stdout>':
Patrick Williamsc0f7c042017-02-23 20:41:17 -060044 import fcntl
45 fl = fcntl.fcntl(sys.stdout.fileno(), fcntl.F_GETFL)
46 fl |= os.O_SYNC
47 fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, fl)
48 #sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049except:
50 pass
51
52logger = logging.getLogger("BitBake")
53
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054worker_pipe = sys.stdout.fileno()
55bb.utils.nonblockingfd(worker_pipe)
Patrick Williamsf1e5d692016-03-30 15:21:19 -050056# Need to guard against multiprocessing being used in child processes
57# and multiple processes trying to write to the parent at the same time
58worker_pipe_lock = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050059
60handler = bb.event.LogHandler()
61logger.addHandler(handler)
62
63if 0:
64 # Code to write out a log file of all events passing through the worker
65 logfilename = "/tmp/workerlogfile"
66 format_str = "%(levelname)s: %(message)s"
67 conlogformat = bb.msg.BBLogFormatter(format_str)
68 consolelog = logging.FileHandler(logfilename)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 consolelog.setFormatter(conlogformat)
70 logger.addHandler(consolelog)
71
Brad Bishop37a0e4d2017-12-04 01:01:44 -050072worker_queue = queue.Queue()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050073
74def worker_fire(event, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060075 data = b"<event>" + pickle.dumps(event) + b"</event>"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076 worker_fire_prepickled(data)
77
78def worker_fire_prepickled(event):
79 global worker_queue
80
Brad Bishop37a0e4d2017-12-04 01:01:44 -050081 worker_queue.put(event)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050082
Brad Bishop37a0e4d2017-12-04 01:01:44 -050083#
84# We can end up with write contention with the cooker, it can be trying to send commands
85# and we can be trying to send event data back. Therefore use a separate thread for writing
86# back data to cooker.
87#
88worker_thread_exit = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089
Brad Bishop37a0e4d2017-12-04 01:01:44 -050090def worker_flush(worker_queue):
91 worker_queue_int = b""
92 global worker_pipe, worker_thread_exit
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093
Brad Bishop37a0e4d2017-12-04 01:01:44 -050094 while True:
95 try:
96 worker_queue_int = worker_queue_int + worker_queue.get(True, 1)
97 except queue.Empty:
98 pass
99 while (worker_queue_int or not worker_queue.empty()):
100 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500101 (_, ready, _) = select.select([], [worker_pipe], [], 1)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500102 if not worker_queue.empty():
103 worker_queue_int = worker_queue_int + worker_queue.get()
104 written = os.write(worker_pipe, worker_queue_int)
105 worker_queue_int = worker_queue_int[written:]
106 except (IOError, OSError) as e:
107 if e.errno != errno.EAGAIN and e.errno != errno.EPIPE:
108 raise
109 if worker_thread_exit and worker_queue.empty() and not worker_queue_int:
110 return
111
112worker_thread = Thread(target=worker_flush, args=(worker_queue,))
113worker_thread.start()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500114
115def worker_child_fire(event, d):
116 global worker_pipe
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500117 global worker_pipe_lock
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500118
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600119 data = b"<event>" + pickle.dumps(event) + b"</event>"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120 try:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500121 worker_pipe_lock.acquire()
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600122 while(len(data)):
123 written = worker_pipe.write(data)
124 data = data[written:]
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500125 worker_pipe_lock.release()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500126 except IOError:
127 sigterm_handler(None, None)
128 raise
129
130bb.event.worker_fire = worker_fire
131
132lf = None
133#lf = open("/tmp/workercommandlog", "w+")
134def workerlog_write(msg):
135 if lf:
136 lf.write(msg)
137 lf.flush()
138
139def sigterm_handler(signum, frame):
140 signal.signal(signal.SIGTERM, signal.SIG_DFL)
141 os.killpg(0, signal.SIGTERM)
142 sys.exit()
143
Brad Bishop19323692019-04-05 15:28:33 -0400144def 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 -0500145 # We need to setup the environment BEFORE the fork, since
146 # a fork() or exec*() activates PSEUDO...
147
148 envbackup = {}
149 fakeenv = {}
150 umask = None
151
152 taskdep = workerdata["taskdeps"][fn]
153 if 'umask' in taskdep and taskname in taskdep['umask']:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600154 umask = taskdep['umask'][taskname]
155 elif workerdata["umask"]:
156 umask = workerdata["umask"]
157 if umask:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500158 # umask might come in as a number or text string..
159 try:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600160 umask = int(umask, 8)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161 except TypeError:
Andrew Geissler9b4d8b02021-02-19 12:26:16 -0600162 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500164 dry_run = cfg.dry_run or dry_run_exec
165
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500166 # 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 -0500167 if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not dry_run:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500168 envvars = (workerdata["fakerootenv"][fn] or "").split()
169 for key, value in (var.split('=') for var in envvars):
170 envbackup[key] = os.environ.get(key)
171 os.environ[key] = value
172 fakeenv[key] = value
173
174 fakedirs = (workerdata["fakerootdirs"][fn] or "").split()
175 for p in fakedirs:
176 bb.utils.mkdirhier(p)
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600177 logger.debug2('Running %s:%s under fakeroot, fakedirs: %s' %
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178 (fn, taskname, ', '.join(fakedirs)))
179 else:
180 envvars = (workerdata["fakerootnoenv"][fn] or "").split()
181 for key, value in (var.split('=') for var in envvars):
182 envbackup[key] = os.environ.get(key)
183 os.environ[key] = value
184 fakeenv[key] = value
185
186 sys.stdout.flush()
187 sys.stderr.flush()
188
189 try:
190 pipein, pipeout = os.pipe()
191 pipein = os.fdopen(pipein, 'rb', 4096)
192 pipeout = os.fdopen(pipeout, 'wb', 0)
193 pid = os.fork()
194 except OSError as e:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600195 logger.critical("fork failed: %d (%s)" % (e.errno, e.strerror))
196 sys.exit(1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500197
198 if pid == 0:
199 def child():
200 global worker_pipe
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500201 global worker_pipe_lock
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500202 pipein.close()
203
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500204 bb.utils.signal_on_parent_exit("SIGTERM")
205
206 # Save out the PID so that the event can include it the
207 # events
208 bb.event.worker_pid = os.getpid()
209 bb.event.worker_fire = worker_child_fire
210 worker_pipe = pipeout
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500211 worker_pipe_lock = Lock()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500212
213 # Make the child the process group leader and ensure no
214 # child process will be controlled by the current terminal
215 # This ensures signals sent to the controlling terminal like Ctrl+C
216 # don't stop the child processes.
217 os.setsid()
Brad Bishop1d80a2e2019-11-15 16:35:03 -0500218
219 signal.signal(signal.SIGTERM, sigterm_handler)
220 # Let SIGHUP exit as SIGTERM
221 signal.signal(signal.SIGHUP, sigterm_handler)
222
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500223 # No stdin
224 newsi = os.open(os.devnull, os.O_RDWR)
225 os.dup2(newsi, sys.stdin.fileno())
226
227 if umask:
228 os.umask(umask)
229
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500230 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600231 bb_cache = bb.cache.NoCache(databuilder)
232 (realfn, virtual, mc) = bb.cache.virtualfn2realfn(fn)
233 the_data = databuilder.mcdata[mc]
234 the_data.setVar("BB_WORKERCONTEXT", "1")
235 the_data.setVar("BB_TASKDEPDATA", taskdepdata)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500236 if cfg.limited_deps:
237 the_data.setVar("BB_LIMITEDDEPS", "1")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600238 the_data.setVar("BUILDNAME", workerdata["buildname"])
239 the_data.setVar("DATE", workerdata["date"])
240 the_data.setVar("TIME", workerdata["time"])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500241 for varname, value in extraconfigdata.items():
242 the_data.setVar(varname, value)
243
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600244 bb.parse.siggen.set_taskdata(workerdata["sigdata"])
Brad Bishop08902b02019-08-20 09:16:51 -0400245 if "newhashes" in workerdata:
246 bb.parse.siggen.set_taskhashes(workerdata["newhashes"])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600247 ret = 0
248
249 the_data = bb_cache.loadDataFull(fn, appends)
Brad Bishop19323692019-04-05 15:28:33 -0400250 the_data.setVar('BB_TASKHASH', taskhash)
251 the_data.setVar('BB_UNIHASH', unihash)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500252
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500253 bb.utils.set_process_name("%s:%s" % (the_data.getVar("PN"), taskname.replace("do_", "")))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500254
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500255 # exported_vars() returns a generator which *cannot* be passed to os.environ.update()
256 # successfully. We also need to unset anything from the environment which shouldn't be there
257 exports = bb.data.exported_vars(the_data)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600258
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500259 bb.utils.empty_environment()
260 for e, v in exports:
261 os.environ[e] = v
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600262
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500263 for e in fakeenv:
264 os.environ[e] = fakeenv[e]
265 the_data.setVar(e, fakeenv[e])
266 the_data.setVarFlag(e, 'export', "1")
267
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500268 task_exports = the_data.getVarFlag(taskname, 'exports')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600269 if task_exports:
270 for e in task_exports.split():
271 the_data.setVarFlag(e, 'export', '1')
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500272 v = the_data.getVar(e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600273 if v is not None:
274 os.environ[e] = v
275
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500276 if quieterrors:
277 the_data.setVarFlag(taskname, "quieterrors", "1")
278
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500279 except Exception:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280 if not quieterrors:
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500281 logger.critical(traceback.format_exc())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500282 os._exit(1)
283 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500284 if dry_run:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500285 return 0
286 return bb.build.exec_task(fn, taskname, the_data, cfg.profile)
287 except:
288 os._exit(1)
289 if not profiling:
290 os._exit(child())
291 else:
292 profname = "profile-%s.log" % (fn.replace("/", "-") + "-" + taskname)
293 prof = profile.Profile()
294 try:
295 ret = profile.Profile.runcall(prof, child)
296 finally:
297 prof.dump_stats(profname)
298 bb.utils.process_profilelog(profname)
299 os._exit(ret)
300 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600301 for key, value in iter(envbackup.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500302 if value is None:
303 del os.environ[key]
304 else:
305 os.environ[key] = value
306
307 return pid, pipein, pipeout
308
309class runQueueWorkerPipe():
310 """
311 Abstraction for a pipe between a worker thread and the worker server
312 """
313 def __init__(self, pipein, pipeout):
314 self.input = pipein
315 if pipeout:
316 pipeout.close()
317 bb.utils.nonblockingfd(self.input)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600318 self.queue = b""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500319
320 def read(self):
321 start = len(self.queue)
322 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600323 self.queue = self.queue + (self.input.read(102400) or b"")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500324 except (OSError, IOError) as e:
325 if e.errno != errno.EAGAIN:
326 raise
327
328 end = len(self.queue)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600329 index = self.queue.find(b"</event>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500330 while index != -1:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600331 msg = self.queue[:index+8]
332 assert msg.startswith(b"<event>") and msg.count(b"<event>") == 1
333 worker_fire_prepickled(msg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500334 self.queue = self.queue[index+8:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600335 index = self.queue.find(b"</event>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500336 return (end > start)
337
338 def close(self):
339 while self.read():
340 continue
341 if len(self.queue) > 0:
342 print("Warning, worker child left partial message: %s" % self.queue)
343 self.input.close()
344
345normalexit = False
346
347class BitbakeWorker(object):
348 def __init__(self, din):
349 self.input = din
350 bb.utils.nonblockingfd(self.input)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600351 self.queue = b""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500352 self.cookercfg = None
353 self.databuilder = None
354 self.data = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500355 self.extraconfigdata = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500356 self.build_pids = {}
357 self.build_pipes = {}
358
359 signal.signal(signal.SIGTERM, self.sigterm_exception)
360 # Let SIGHUP exit as SIGTERM
361 signal.signal(signal.SIGHUP, self.sigterm_exception)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500362 if "beef" in sys.argv[1]:
363 bb.utils.set_process_name("Worker (Fakeroot)")
364 else:
365 bb.utils.set_process_name("Worker")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500366
367 def sigterm_exception(self, signum, stackframe):
368 if signum == signal.SIGTERM:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500369 bb.warn("Worker received SIGTERM, shutting down...")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500370 elif signum == signal.SIGHUP:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500371 bb.warn("Worker received SIGHUP, shutting down...")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500372 self.handle_finishnow(None)
373 signal.signal(signal.SIGTERM, signal.SIG_DFL)
374 os.kill(os.getpid(), signal.SIGTERM)
375
376 def serve(self):
377 while True:
378 (ready, _, _) = select.select([self.input] + [i.input for i in self.build_pipes.values()], [] , [], 1)
379 if self.input in ready:
380 try:
381 r = self.input.read()
382 if len(r) == 0:
383 # EOF on pipe, server must have terminated
384 self.sigterm_exception(signal.SIGTERM, None)
385 self.queue = self.queue + r
386 except (OSError, IOError):
387 pass
388 if len(self.queue):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600389 self.handle_item(b"cookerconfig", self.handle_cookercfg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500390 self.handle_item(b"extraconfigdata", self.handle_extraconfigdata)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600391 self.handle_item(b"workerdata", self.handle_workerdata)
Brad Bishop08902b02019-08-20 09:16:51 -0400392 self.handle_item(b"newtaskhashes", self.handle_newtaskhashes)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600393 self.handle_item(b"runtask", self.handle_runtask)
394 self.handle_item(b"finishnow", self.handle_finishnow)
395 self.handle_item(b"ping", self.handle_ping)
396 self.handle_item(b"quit", self.handle_quit)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500397
398 for pipe in self.build_pipes:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500399 if self.build_pipes[pipe].input in ready:
400 self.build_pipes[pipe].read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500401 if len(self.build_pids):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500402 while self.process_waitpid():
403 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500404
405
406 def handle_item(self, item, func):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600407 if self.queue.startswith(b"<" + item + b">"):
408 index = self.queue.find(b"</" + item + b">")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500409 while index != -1:
410 func(self.queue[(len(item) + 2):index])
411 self.queue = self.queue[(index + len(item) + 3):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600412 index = self.queue.find(b"</" + item + b">")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500413
414 def handle_cookercfg(self, data):
415 self.cookercfg = pickle.loads(data)
416 self.databuilder = bb.cookerdata.CookerDataBuilder(self.cookercfg, worker=True)
417 self.databuilder.parseBaseConfiguration()
418 self.data = self.databuilder.data
419
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500420 def handle_extraconfigdata(self, data):
421 self.extraconfigdata = pickle.loads(data)
422
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500423 def handle_workerdata(self, data):
424 self.workerdata = pickle.loads(data)
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500425 bb.build.verboseShellLogging = self.workerdata["build_verbose_shell"]
426 bb.build.verboseStdoutLogging = self.workerdata["build_verbose_stdout"]
Andrew Geissler82c905d2020-04-13 13:39:40 -0500427 bb.msg.loggerDefaultLogLevel = self.workerdata["logdefaultlevel"]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500428 bb.msg.loggerDefaultDomains = self.workerdata["logdefaultdomain"]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600429 for mc in self.databuilder.mcdata:
430 self.databuilder.mcdata[mc].setVar("PRSERV_HOST", self.workerdata["prhost"])
Brad Bishopa34c0302019-09-23 22:34:48 -0400431 self.databuilder.mcdata[mc].setVar("BB_HASHSERVE", self.workerdata["hashservaddr"])
Brad Bishop08902b02019-08-20 09:16:51 -0400432
433 def handle_newtaskhashes(self, data):
434 self.workerdata["newhashes"] = pickle.loads(data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435
436 def handle_ping(self, _):
437 workerlog_write("Handling ping\n")
438
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600439 logger.warning("Pong from bitbake-worker!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500440
441 def handle_quit(self, data):
442 workerlog_write("Handling quit\n")
443
444 global normalexit
445 normalexit = True
446 sys.exit(0)
447
448 def handle_runtask(self, data):
Brad Bishop19323692019-04-05 15:28:33 -0400449 fn, task, taskname, taskhash, unihash, quieterrors, appends, taskdepdata, dry_run_exec = pickle.loads(data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500450 workerlog_write("Handling runtask %s %s %s\n" % (task, fn, taskname))
451
Brad Bishop19323692019-04-05 15:28:33 -0400452 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 -0500453
454 self.build_pids[pid] = task
455 self.build_pipes[pid] = runQueueWorkerPipe(pipein, pipeout)
456
457 def process_waitpid(self):
458 """
459 Return none is there are no processes awaiting result collection, otherwise
460 collect the process exit codes and close the information pipe.
461 """
462 try:
463 pid, status = os.waitpid(-1, os.WNOHANG)
464 if pid == 0 or os.WIFSTOPPED(status):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500465 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466 except OSError:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500467 return False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500468
469 workerlog_write("Exit code of %s for pid %s\n" % (status, pid))
470
471 if os.WIFEXITED(status):
472 status = os.WEXITSTATUS(status)
473 elif os.WIFSIGNALED(status):
474 # Per shell conventions for $?, when a process exits due to
475 # a signal, we return an exit code of 128 + SIGNUM
476 status = 128 + os.WTERMSIG(status)
477
478 task = self.build_pids[pid]
479 del self.build_pids[pid]
480
481 self.build_pipes[pid].close()
482 del self.build_pipes[pid]
483
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600484 worker_fire_prepickled(b"<exitcode>" + pickle.dumps((task, status)) + b"</exitcode>")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500485
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500486 return True
487
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500488 def handle_finishnow(self, _):
489 if self.build_pids:
490 logger.info("Sending SIGTERM to remaining %s tasks", len(self.build_pids))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600491 for k, v in iter(self.build_pids.items()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500492 try:
493 os.kill(-k, signal.SIGTERM)
494 os.waitpid(-1, 0)
495 except:
496 pass
497 for pipe in self.build_pipes:
498 self.build_pipes[pipe].read()
499
500try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600501 worker = BitbakeWorker(os.fdopen(sys.stdin.fileno(), 'rb'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500502 if not profiling:
503 worker.serve()
504 else:
505 profname = "profile-worker.log"
506 prof = profile.Profile()
507 try:
508 profile.Profile.runcall(prof, worker.serve)
509 finally:
510 prof.dump_stats(profname)
511 bb.utils.process_profilelog(profname)
512except BaseException as e:
513 if not normalexit:
514 import traceback
515 sys.stderr.write(traceback.format_exc())
516 sys.stderr.write(str(e))
Andrew Geissler5199d832021-09-24 16:47:35 -0500517finally:
518 worker_thread_exit = True
519 worker_thread.join()
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500520
Andrew Geisslerd159c7f2021-09-02 21:05:58 -0500521workerlog_write("exiting")
Andrew Geissler5199d832021-09-24 16:47:35 -0500522if not normalexit:
523 sys.exit(1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500524sys.exit(0)