diff options
author | Richard Purdie <rpurdie@linux.intel.com> | 2010-08-16 16:37:29 +0100 |
---|---|---|
committer | Richard Purdie <rpurdie@linux.intel.com> | 2010-08-19 22:36:25 +0100 |
commit | b6bfe1420517aa5aa190e17dca40ea70f09effd9 (patch) | |
tree | 2591a26f18290e8d929517df71f24645394c57fb | |
parent | a45e1d54e19d4cd728e90df929b212e41ef70d4b (diff) | |
download | poky-b6bfe1420517aa5aa190e17dca40ea70f09effd9.tar.gz |
bitbake: Switch to use subprocess for forking tasks and FAKEROOTENV to run shell and python under a fakeroot environment
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
-rwxr-xr-x | bitbake/bin/bitbake-runtask | 77 | ||||
-rw-r--r-- | bitbake/lib/bb/build.py | 64 | ||||
-rw-r--r-- | bitbake/lib/bb/cooker.py | 7 | ||||
-rw-r--r-- | bitbake/lib/bb/data.py | 9 | ||||
-rw-r--r-- | bitbake/lib/bb/event.py | 11 | ||||
-rw-r--r-- | bitbake/lib/bb/msg.py | 11 | ||||
-rw-r--r-- | bitbake/lib/bb/runqueue.py | 134 |
7 files changed, 201 insertions, 112 deletions
diff --git a/bitbake/bin/bitbake-runtask b/bitbake/bin/bitbake-runtask new file mode 100755 index 0000000000..417f3949cd --- /dev/null +++ b/bitbake/bin/bitbake-runtask | |||
@@ -0,0 +1,77 @@ | |||
1 | #!/usr/bin/env python | ||
2 | |||
3 | import os | ||
4 | import sys | ||
5 | import warnings | ||
6 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib')) | ||
7 | |||
8 | class BBConfiguration(object): | ||
9 | """ | ||
10 | Manages build options and configurations for one run | ||
11 | """ | ||
12 | |||
13 | def __init__(self): | ||
14 | setattr(self, "data", {}) | ||
15 | setattr(self, "file", []) | ||
16 | setattr(self, "cmd", None) | ||
17 | |||
18 | _warnings_showwarning = warnings.showwarning | ||
19 | def _showwarning(message, category, filename, lineno, file=None, line=None): | ||
20 | """Display python warning messages using bb.msg""" | ||
21 | if file is not None: | ||
22 | if _warnings_showwarning is not None: | ||
23 | _warnings_showwarning(message, category, filename, lineno, file, line) | ||
24 | else: | ||
25 | s = warnings.formatwarning(message, category, filename, lineno) | ||
26 | s = s.split("\n")[0] | ||
27 | bb.msg.warn(None, s) | ||
28 | |||
29 | warnings.showwarning = _showwarning | ||
30 | warnings.simplefilter("ignore", DeprecationWarning) | ||
31 | |||
32 | import bb.event | ||
33 | |||
34 | # Need to map our I/O correctly. Currently stdout is a pipe to | ||
35 | # the server expecting events. We save this and map stdout to stderr. | ||
36 | |||
37 | eventfd = os.dup(sys.stdout.fileno()) | ||
38 | bb.event.worker_pipe = os.fdopen(eventfd, 'w', 0) | ||
39 | # Replace those fds with our own | ||
40 | os.dup2(sys.stderr.fileno(), sys.stdout.fileno()) | ||
41 | |||
42 | # Save out the PID so that the event can include it the | ||
43 | # events | ||
44 | bb.event.worker_pid = os.getpid() | ||
45 | bb.event.usestdout = False | ||
46 | |||
47 | |||
48 | import bb.cooker | ||
49 | |||
50 | cooker = bb.cooker.BBCooker(BBConfiguration(), None) | ||
51 | buildfile = sys.argv[1] | ||
52 | taskname = sys.argv[2] | ||
53 | |||
54 | cooker.parseConfiguration() | ||
55 | |||
56 | cooker.bb_cache = bb.cache.init(cooker) | ||
57 | cooker.status = bb.cache.CacheData() | ||
58 | |||
59 | (fn, cls) = cooker.bb_cache.virtualfn2realfn(buildfile) | ||
60 | buildfile = cooker.matchFile(fn) | ||
61 | fn = cooker.bb_cache.realfn2virtual(buildfile, cls) | ||
62 | |||
63 | cooker.buildSetVars() | ||
64 | |||
65 | # Load data into the cache for fn and parse the loaded cache data | ||
66 | the_data = cooker.bb_cache.loadDataFull(fn, cooker.get_file_appends(fn), cooker.configuration.data) | ||
67 | cooker.bb_cache.setData(fn, buildfile, the_data) | ||
68 | cooker.bb_cache.handle_data(fn, cooker.status) | ||
69 | |||
70 | if taskname.endswith("_setscene"): | ||
71 | the_data.setVarFlag(taskname, "quieterrors", "1") | ||
72 | |||
73 | ret = 0 | ||
74 | if sys.argv[3] != "True": | ||
75 | ret = bb.build.exec_task(taskname, the_data) | ||
76 | sys.exit(ret) | ||
77 | |||
diff --git a/bitbake/lib/bb/build.py b/bitbake/lib/bb/build.py index 0bf0154cb4..77af92abee 100644 --- a/bitbake/lib/bb/build.py +++ b/bitbake/lib/bb/build.py | |||
@@ -44,12 +44,6 @@ class FuncFailed(Exception): | |||
44 | Second paramter is a logfile (optional) | 44 | Second paramter is a logfile (optional) |
45 | """ | 45 | """ |
46 | 46 | ||
47 | class EventException(Exception): | ||
48 | """Exception which is associated with an Event.""" | ||
49 | |||
50 | def __init__(self, msg, event): | ||
51 | self.args = msg, event | ||
52 | |||
53 | class TaskBase(event.Event): | 47 | class TaskBase(event.Event): |
54 | """Base class for task events""" | 48 | """Base class for task events""" |
55 | 49 | ||
@@ -80,7 +74,7 @@ class TaskFailed(TaskBase): | |||
80 | self.msg = msg | 74 | self.msg = msg |
81 | TaskBase.__init__(self, t, d) | 75 | TaskBase.__init__(self, t, d) |
82 | 76 | ||
83 | class InvalidTask(TaskBase): | 77 | class TaskInvalid(TaskBase): |
84 | """Invalid Task""" | 78 | """Invalid Task""" |
85 | 79 | ||
86 | # functions | 80 | # functions |
@@ -94,7 +88,7 @@ def exec_func(func, d, dirs = None): | |||
94 | return | 88 | return |
95 | 89 | ||
96 | flags = data.getVarFlags(func, d) | 90 | flags = data.getVarFlags(func, d) |
97 | for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot']: | 91 | for item in ['deps', 'check', 'interactive', 'python', 'cleandirs', 'dirs', 'lockfiles', 'fakeroot', 'task']: |
98 | if not item in flags: | 92 | if not item in flags: |
99 | flags[item] = None | 93 | flags[item] = None |
100 | 94 | ||
@@ -138,7 +132,7 @@ def exec_func(func, d, dirs = None): | |||
138 | # Handle logfiles | 132 | # Handle logfiles |
139 | si = file('/dev/null', 'r') | 133 | si = file('/dev/null', 'r') |
140 | try: | 134 | try: |
141 | if bb.msg.debug_level['default'] > 0 or ispython: | 135 | if bb.msg.debug_level['default'] > 0 and not ispython: |
142 | so = os.popen("tee \"%s\"" % logfile, "w") | 136 | so = os.popen("tee \"%s\"" % logfile, "w") |
143 | else: | 137 | else: |
144 | so = file(logfile, 'w') | 138 | so = file(logfile, 'w') |
@@ -158,6 +152,8 @@ def exec_func(func, d, dirs = None): | |||
158 | os.dup2(so.fileno(), oso[1]) | 152 | os.dup2(so.fileno(), oso[1]) |
159 | os.dup2(se.fileno(), ose[1]) | 153 | os.dup2(se.fileno(), ose[1]) |
160 | 154 | ||
155 | bb.event.useStdout = True | ||
156 | |||
161 | locks = [] | 157 | locks = [] |
162 | lockfiles = flags['lockfiles'] | 158 | lockfiles = flags['lockfiles'] |
163 | if lockfiles: | 159 | if lockfiles: |
@@ -183,6 +179,8 @@ def exec_func(func, d, dirs = None): | |||
183 | for lock in locks: | 179 | for lock in locks: |
184 | bb.utils.unlockfile(lock) | 180 | bb.utils.unlockfile(lock) |
185 | 181 | ||
182 | bb.event.useStdout = False | ||
183 | |||
186 | # Restore the backup fds | 184 | # Restore the backup fds |
187 | os.dup2(osi[0], osi[1]) | 185 | os.dup2(osi[0], osi[1]) |
188 | os.dup2(oso[0], oso[1]) | 186 | os.dup2(oso[0], oso[1]) |
@@ -221,6 +219,7 @@ def exec_func_python(func, d, runfile, logfile): | |||
221 | raise | 219 | raise |
222 | raise FuncFailed("Function %s failed" % func, logfile) | 220 | raise FuncFailed("Function %s failed" % func, logfile) |
223 | 221 | ||
222 | |||
224 | def exec_func_shell(func, d, runfile, logfile, flags): | 223 | def exec_func_shell(func, d, runfile, logfile, flags): |
225 | """Execute a shell BB 'function' Returns true if execution was successful. | 224 | """Execute a shell BB 'function' Returns true if execution was successful. |
226 | 225 | ||
@@ -251,12 +250,11 @@ def exec_func_shell(func, d, runfile, logfile, flags): | |||
251 | raise FuncFailed("Function not specified for exec_func_shell") | 250 | raise FuncFailed("Function not specified for exec_func_shell") |
252 | 251 | ||
253 | # execute function | 252 | # execute function |
254 | if flags['fakeroot']: | 253 | if flags['fakeroot'] and not flags['task']: |
255 | maybe_fakeroot = "PATH=\"%s\" %s " % (bb.data.getVar("PATH", d, 1), bb.data.getVar("FAKEROOT", d, 1) or "fakeroot") | 254 | bb.fatal("Function %s specifies fakeroot but isn't a task?!" % func) |
256 | else: | 255 | |
257 | maybe_fakeroot = '' | ||
258 | lang_environment = "LC_ALL=C " | 256 | lang_environment = "LC_ALL=C " |
259 | ret = os.system('%s%ssh -e %s' % (lang_environment, maybe_fakeroot, runfile)) | 257 | ret = os.system('%ssh -e %s' % (lang_environment, runfile)) |
260 | 258 | ||
261 | if ret == 0: | 259 | if ret == 0: |
262 | return | 260 | return |
@@ -273,7 +271,13 @@ def exec_task(task, d): | |||
273 | 271 | ||
274 | # Check whther this is a valid task | 272 | # Check whther this is a valid task |
275 | if not data.getVarFlag(task, 'task', d): | 273 | if not data.getVarFlag(task, 'task', d): |
276 | raise EventException("No such task", InvalidTask(task, d)) | 274 | event.fire(TaskInvalid(task, d), d) |
275 | bb.msg.error(bb.msg.domain.Build, "No such task: %s" % task) | ||
276 | return 1 | ||
277 | |||
278 | quieterr = False | ||
279 | if d.getVarFlag(task, "quieterrors") is not None: | ||
280 | quieterr = True | ||
277 | 281 | ||
278 | try: | 282 | try: |
279 | bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task) | 283 | bb.msg.debug(1, bb.msg.domain.Build, "Executing task %s" % task) |
@@ -292,6 +296,11 @@ def exec_task(task, d): | |||
292 | for func in postfuncs: | 296 | for func in postfuncs: |
293 | exec_func(func, localdata) | 297 | exec_func(func, localdata) |
294 | event.fire(TaskSucceeded(task, localdata), localdata) | 298 | event.fire(TaskSucceeded(task, localdata), localdata) |
299 | |||
300 | # make stamp, or cause event and raise exception | ||
301 | if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d): | ||
302 | make_stamp(task, d) | ||
303 | |||
295 | except FuncFailed as message: | 304 | except FuncFailed as message: |
296 | # Try to extract the optional logfile | 305 | # Try to extract the optional logfile |
297 | try: | 306 | try: |
@@ -299,14 +308,22 @@ def exec_task(task, d): | |||
299 | except: | 308 | except: |
300 | logfile = None | 309 | logfile = None |
301 | msg = message | 310 | msg = message |
302 | bb.msg.note(1, bb.msg.domain.Build, "Task failed: %s" % message ) | 311 | if not quieterr: |
303 | failedevent = TaskFailed(msg, logfile, task, d) | 312 | bb.msg.error(bb.msg.domain.Build, "Task failed: %s" % message ) |
304 | event.fire(failedevent, d) | 313 | failedevent = TaskFailed(msg, logfile, task, d) |
305 | raise EventException("Function failed in task: %s" % message, failedevent) | 314 | event.fire(failedevent, d) |
306 | 315 | return 1 | |
307 | # make stamp, or cause event and raise exception | 316 | |
308 | if not data.getVarFlag(task, 'nostamp', d) and not data.getVarFlag(task, 'selfstamp', d): | 317 | except Exception: |
309 | make_stamp(task, d) | 318 | from traceback import format_exc |
319 | if not quieterr: | ||
320 | bb.msg.error(bb.msg.domain.Build, "Build of %s failed" % (task)) | ||
321 | bb.msg.error(bb.msg.domain.Build, format_exc()) | ||
322 | failedevent = TaskFailed("Task Failed", None, task, d) | ||
323 | event.fire(failedevent, d) | ||
324 | return 1 | ||
325 | |||
326 | return 0 | ||
310 | 327 | ||
311 | def extract_stamp(d, fn): | 328 | def extract_stamp(d, fn): |
312 | """ | 329 | """ |
@@ -380,6 +397,7 @@ def add_tasks(tasklist, d): | |||
380 | getTask('rdeptask') | 397 | getTask('rdeptask') |
381 | getTask('recrdeptask') | 398 | getTask('recrdeptask') |
382 | getTask('nostamp') | 399 | getTask('nostamp') |
400 | getTask('fakeroot') | ||
383 | task_deps['parents'][task] = [] | 401 | task_deps['parents'][task] = [] |
384 | for dep in flags['deps']: | 402 | for dep in flags['deps']: |
385 | dep = data.expand(dep, d) | 403 | dep = data.expand(dep, d) |
diff --git a/bitbake/lib/bb/cooker.py b/bitbake/lib/bb/cooker.py index a1620b0162..3a25956625 100644 --- a/bitbake/lib/bb/cooker.py +++ b/bitbake/lib/bb/cooker.py | |||
@@ -70,12 +70,16 @@ class BBCooker: | |||
70 | self.cache = None | 70 | self.cache = None |
71 | self.bb_cache = None | 71 | self.bb_cache = None |
72 | 72 | ||
73 | self.server = server.BitBakeServer(self) | 73 | if server: |
74 | self.server = server.BitBakeServer(self) | ||
74 | 75 | ||
75 | self.configuration = configuration | 76 | self.configuration = configuration |
76 | 77 | ||
77 | self.configuration.data = bb.data.init() | 78 | self.configuration.data = bb.data.init() |
78 | 79 | ||
80 | if not server: | ||
81 | bb.data.setVar("BB_WORKERCONTEXT", "1", self.configuration.data) | ||
82 | |||
79 | bb.data.inheritFromOS(self.configuration.data) | 83 | bb.data.inheritFromOS(self.configuration.data) |
80 | 84 | ||
81 | self.parseConfigurationFiles(self.configuration.file) | 85 | self.parseConfigurationFiles(self.configuration.file) |
@@ -544,7 +548,6 @@ class BBCooker: | |||
544 | 548 | ||
545 | bb.event.fire(bb.event.ConfigParsed(), self.configuration.data) | 549 | bb.event.fire(bb.event.ConfigParsed(), self.configuration.data) |
546 | 550 | ||
547 | |||
548 | except IOError as e: | 551 | except IOError as e: |
549 | bb.msg.fatal(bb.msg.domain.Parsing, "Error when parsing %s: %s" % (files, str(e))) | 552 | bb.msg.fatal(bb.msg.domain.Parsing, "Error when parsing %s: %s" % (files, str(e))) |
550 | except bb.parse.ParseError as details: | 553 | except bb.parse.ParseError as details: |
diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py index 636983edcc..9e37f5e32d 100644 --- a/bitbake/lib/bb/data.py +++ b/bitbake/lib/bb/data.py | |||
@@ -229,6 +229,15 @@ def emit_env(o=sys.__stdout__, d = init(), all=False): | |||
229 | for key in keys: | 229 | for key in keys: |
230 | emit_var(key, o, d, all and not isfunc) and o.write('\n') | 230 | emit_var(key, o, d, all and not isfunc) and o.write('\n') |
231 | 231 | ||
232 | def export_vars(d): | ||
233 | keys = (key for key in d.keys() if d.getVarFlag(key, "export")) | ||
234 | ret = {} | ||
235 | for k in keys: | ||
236 | v = d.getVar(k, True) | ||
237 | if v: | ||
238 | ret[k] = v | ||
239 | return ret | ||
240 | |||
232 | def update_data(d): | 241 | def update_data(d): |
233 | """Performs final steps upon the datastore, including application of overrides""" | 242 | """Performs final steps upon the datastore, including application of overrides""" |
234 | d.finalize() | 243 | d.finalize() |
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py index 7731649eff..f5ba6eab3c 100644 --- a/bitbake/lib/bb/event.py +++ b/bitbake/lib/bb/event.py | |||
@@ -31,6 +31,7 @@ import pickle | |||
31 | # the runqueue forks off. | 31 | # the runqueue forks off. |
32 | worker_pid = 0 | 32 | worker_pid = 0 |
33 | worker_pipe = None | 33 | worker_pipe = None |
34 | useStdout = True | ||
34 | 35 | ||
35 | class Event: | 36 | class Event: |
36 | """Base class for events""" | 37 | """Base class for events""" |
@@ -102,15 +103,12 @@ def fire(event, d): | |||
102 | 103 | ||
103 | def worker_fire(event, d): | 104 | def worker_fire(event, d): |
104 | data = "<event>" + pickle.dumps(event) + "</event>" | 105 | data = "<event>" + pickle.dumps(event) + "</event>" |
105 | try: | 106 | worker_pipe.write(data) |
106 | if os.write(worker_pipe, data) != len (data): | 107 | worker_pipe.flush() |
107 | print("Error sending event to server (short write)") | ||
108 | except OSError: | ||
109 | sys.exit(1) | ||
110 | 108 | ||
111 | def fire_from_worker(event, d): | 109 | def fire_from_worker(event, d): |
112 | if not event.startswith("<event>") or not event.endswith("</event>"): | 110 | if not event.startswith("<event>") or not event.endswith("</event>"): |
113 | print("Error, not an event") | 111 | print("Error, not an event %s" % event) |
114 | return | 112 | return |
115 | event = pickle.loads(event[7:-8]) | 113 | event = pickle.loads(event[7:-8]) |
116 | fire_ui_handlers(event, d) | 114 | fire_ui_handlers(event, d) |
@@ -140,6 +138,7 @@ def remove(name, handler): | |||
140 | def register_UIHhandler(handler): | 138 | def register_UIHhandler(handler): |
141 | bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 | 139 | bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 |
142 | _ui_handlers[_ui_handler_seq] = handler | 140 | _ui_handlers[_ui_handler_seq] = handler |
141 | bb.event.useStdout = False | ||
143 | return _ui_handler_seq | 142 | return _ui_handler_seq |
144 | 143 | ||
145 | def unregister_UIHhandler(handlerNum): | 144 | def unregister_UIHhandler(handlerNum): |
diff --git a/bitbake/lib/bb/msg.py b/bitbake/lib/bb/msg.py index 8d2bcce452..5bb30e8dd3 100644 --- a/bitbake/lib/bb/msg.py +++ b/bitbake/lib/bb/msg.py | |||
@@ -109,7 +109,7 @@ def debug(level, msgdomain, msg, fn = None): | |||
109 | 109 | ||
110 | if debug_level[msgdomain] >= level: | 110 | if debug_level[msgdomain] >= level: |
111 | bb.event.fire(MsgDebug(msg), None) | 111 | bb.event.fire(MsgDebug(msg), None) |
112 | if not bb.event._ui_handlers: | 112 | if bb.event.useStdout: |
113 | print('DEBUG: %s' % (msg)) | 113 | print('DEBUG: %s' % (msg)) |
114 | 114 | ||
115 | def note(level, msgdomain, msg, fn = None): | 115 | def note(level, msgdomain, msg, fn = None): |
@@ -118,17 +118,18 @@ def note(level, msgdomain, msg, fn = None): | |||
118 | 118 | ||
119 | if level == 1 or verbose or debug_level[msgdomain] >= 1: | 119 | if level == 1 or verbose or debug_level[msgdomain] >= 1: |
120 | bb.event.fire(MsgNote(msg), None) | 120 | bb.event.fire(MsgNote(msg), None) |
121 | if not bb.event._ui_handlers: | 121 | if bb.event.useStdout: |
122 | print('NOTE: %s' % (msg)) | 122 | print('NOTE: %s' % (msg)) |
123 | 123 | ||
124 | def warn(msgdomain, msg, fn = None): | 124 | def warn(msgdomain, msg, fn = None): |
125 | bb.event.fire(MsgWarn(msg), None) | 125 | bb.event.fire(MsgWarn(msg), None) |
126 | if not bb.event._ui_handlers: | 126 | if bb.event.useStdout: |
127 | print('WARNING: %s' % (msg)) | 127 | print('WARNING: %s' % (msg)) |
128 | 128 | ||
129 | def error(msgdomain, msg, fn = None): | 129 | def error(msgdomain, msg, fn = None): |
130 | bb.event.fire(MsgError(msg), None) | 130 | bb.event.fire(MsgError(msg), None) |
131 | print('ERROR: %s' % (msg)) | 131 | if bb.event.useStdout: |
132 | print('ERROR: %s' % (msg)) | ||
132 | 133 | ||
133 | def fatal(msgdomain, msg, fn = None): | 134 | def fatal(msgdomain, msg, fn = None): |
134 | bb.event.fire(MsgFatal(msg), None) | 135 | bb.event.fire(MsgFatal(msg), None) |
@@ -137,5 +138,5 @@ def fatal(msgdomain, msg, fn = None): | |||
137 | 138 | ||
138 | def plain(msg, fn = None): | 139 | def plain(msg, fn = None): |
139 | bb.event.fire(MsgPlain(msg), None) | 140 | bb.event.fire(MsgPlain(msg), None) |
140 | if not bb.event._ui_handlers: | 141 | if bb.event.useStdout: |
141 | print(msg) | 142 | print(msg) |
diff --git a/bitbake/lib/bb/runqueue.py b/bitbake/lib/bb/runqueue.py index 9127f248d5..b2d5fc01ab 100644 --- a/bitbake/lib/bb/runqueue.py +++ b/bitbake/lib/bb/runqueue.py | |||
@@ -23,6 +23,7 @@ Handles preparation and execution of a queue of tasks | |||
23 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 23 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
24 | 24 | ||
25 | import bb, os, sys | 25 | import bb, os, sys |
26 | import subprocess | ||
26 | from bb import msg, data, event | 27 | from bb import msg, data, event |
27 | import signal | 28 | import signal |
28 | import stat | 29 | import stat |
@@ -937,6 +938,7 @@ class RunQueueExecute: | |||
937 | self.runq_complete = [] | 938 | self.runq_complete = [] |
938 | self.build_pids = {} | 939 | self.build_pids = {} |
939 | self.build_pipes = {} | 940 | self.build_pipes = {} |
941 | self.build_procs = {} | ||
940 | self.failed_fnids = [] | 942 | self.failed_fnids = [] |
941 | 943 | ||
942 | def runqueue_process_waitpid(self): | 944 | def runqueue_process_waitpid(self): |
@@ -944,19 +946,22 @@ class RunQueueExecute: | |||
944 | Return none is there are no processes awaiting result collection, otherwise | 946 | Return none is there are no processes awaiting result collection, otherwise |
945 | collect the process exit codes and close the information pipe. | 947 | collect the process exit codes and close the information pipe. |
946 | """ | 948 | """ |
947 | result = os.waitpid(-1, os.WNOHANG) | 949 | for pid in self.build_procs.keys(): |
948 | if result[0] is 0 and result[1] is 0: | 950 | proc = self.build_procs[pid] |
949 | return None | 951 | proc.poll() |
950 | task = self.build_pids[result[0]] | 952 | if proc.returncode is not None: |
951 | del self.build_pids[result[0]] | 953 | task = self.build_pids[pid] |
952 | self.build_pipes[result[0]].close() | 954 | del self.build_pids[pid] |
953 | del self.build_pipes[result[0]] | 955 | self.build_pipes[pid].close() |
954 | if result[1] != 0: | 956 | del self.build_pipes[pid] |
955 | self.task_fail(task, result[1]) | 957 | del self.build_procs[pid] |
956 | else: | 958 | if proc.returncode != 0: |
957 | self.task_complete(task) | 959 | self.task_fail(task, proc.returncode) |
958 | self.stats.taskCompleted() | 960 | else: |
959 | bb.event.fire(runQueueTaskCompleted(task, self.stats, self.rq), self.cfgData) | 961 | self.task_complete(task) |
962 | self.stats.taskCompleted() | ||
963 | bb.event.fire(runQueueTaskCompleted(task, self.stats, self.rq), self.cfgData) | ||
964 | |||
960 | 965 | ||
961 | def finish_now(self): | 966 | def finish_now(self): |
962 | if self.stats.active: | 967 | if self.stats.active: |
@@ -990,31 +995,8 @@ class RunQueueExecute: | |||
990 | def fork_off_task(self, fn, task, taskname): | 995 | def fork_off_task(self, fn, task, taskname): |
991 | sys.stdout.flush() | 996 | sys.stdout.flush() |
992 | sys.stderr.flush() | 997 | sys.stderr.flush() |
993 | try: | ||
994 | pipein, pipeout = os.pipe() | ||
995 | pid = os.fork() | ||
996 | except OSError as e: | ||
997 | bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror)) | ||
998 | if pid == 0: | ||
999 | os.close(pipein) | ||
1000 | # Save out the PID so that the event can include it the | ||
1001 | # events | ||
1002 | bb.event.worker_pid = os.getpid() | ||
1003 | bb.event.worker_pipe = pipeout | ||
1004 | |||
1005 | self.rq.state = runQueueChildProcess | ||
1006 | # Make the child the process group leader | ||
1007 | os.setpgid(0, 0) | ||
1008 | # No stdin | ||
1009 | newsi = os.open('/dev/null', os.O_RDWR) | ||
1010 | os.dup2(newsi, sys.stdin.fileno()) | ||
1011 | # Stdout to a logfile | ||
1012 | #logout = data.expand("${TMPDIR}/log/stdout.%s" % os.getpid(), self.cfgData, True) | ||
1013 | #mkdirhier(os.path.dirname(logout)) | ||
1014 | #newso = open(logout, 'w') | ||
1015 | #os.dup2(newso.fileno(), sys.stdout.fileno()) | ||
1016 | #os.dup2(newso.fileno(), sys.stderr.fileno()) | ||
1017 | 998 | ||
999 | try: | ||
1018 | bb.event.fire(runQueueTaskStarted(task, self.stats, self.rq), self.cfgData) | 1000 | bb.event.fire(runQueueTaskStarted(task, self.stats, self.rq), self.cfgData) |
1019 | bb.msg.note(1, bb.msg.domain.RunQueue, | 1001 | bb.msg.note(1, bb.msg.domain.RunQueue, |
1020 | "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.stats.active + self.stats.failed + 1, | 1002 | "Running task %d of %d (ID: %s, %s)" % (self.stats.completed + self.stats.active + self.stats.failed + 1, |
@@ -1022,26 +1004,25 @@ class RunQueueExecute: | |||
1022 | task, | 1004 | task, |
1023 | self.rqdata.get_user_idstring(task))) | 1005 | self.rqdata.get_user_idstring(task))) |
1024 | 1006 | ||
1025 | bb.data.setVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", self, self.cooker.configuration.data) | 1007 | the_data = self.cooker.bb_cache.loadDataFull(fn, self.cooker.get_file_appends(fn), self.cooker.configuration.data) |
1026 | bb.data.setVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY2", fn, self.cooker.configuration.data) | 1008 | |
1027 | try: | 1009 | env = bb.data.export_vars(the_data) |
1028 | the_data = self.cooker.bb_cache.loadDataFull(fn, self.cooker.get_file_appends(fn), self.cooker.configuration.data) | 1010 | |
1029 | 1011 | taskdep = self.rqdata.dataCache.task_deps[fn] | |
1030 | if not self.cooker.configuration.dry_run: | 1012 | if 'fakeroot' in taskdep and taskname in taskdep['fakeroot']: |
1031 | bb.build.exec_task(taskname, the_data) | 1013 | envvars = the_data.getVar("FAKEROOTENV", True).split() |
1032 | os._exit(0) | 1014 | for var in envvars: |
1033 | 1015 | comps = var.split("=") | |
1034 | except bb.build.EventException as e: | 1016 | env[comps[0]] = comps[1] |
1035 | event = e.args[1] | 1017 | |
1036 | bb.msg.error(bb.msg.domain.Build, "%s event exception, aborting" % bb.event.getName(event)) | 1018 | proc = subprocess.Popen(["bitbake-runtask", fn, taskname, str(self.cooker.configuration.dry_run)], env=env, stdout=subprocess.PIPE, stdin=subprocess.PIPE) |
1037 | os._exit(1) | 1019 | pipein = proc.stdout |
1038 | except Exception: | 1020 | pipeout = proc.stdin |
1039 | from traceback import format_exc | 1021 | pid = proc.pid |
1040 | bb.msg.error(bb.msg.domain.Build, "Build of %s %s failed" % (fn, taskname)) | 1022 | except OSError as e: |
1041 | bb.msg.error(bb.msg.domain.Build, format_exc()) | 1023 | bb.msg.fatal(bb.msg.domain.RunQueue, "fork failed: %d (%s)" % (e.errno, e.strerror)) |
1042 | os._exit(1) | 1024 | |
1043 | os._exit(0) | 1025 | return proc |
1044 | return pid, pipein, pipeout | ||
1045 | 1026 | ||
1046 | class RunQueueExecuteTasks(RunQueueExecute): | 1027 | class RunQueueExecuteTasks(RunQueueExecute): |
1047 | def __init__(self, rq): | 1028 | def __init__(self, rq): |
@@ -1153,10 +1134,11 @@ class RunQueueExecuteTasks(RunQueueExecute): | |||
1153 | self.task_skip(task) | 1134 | self.task_skip(task) |
1154 | continue | 1135 | continue |
1155 | 1136 | ||
1156 | pid, pipein, pipeout = self.fork_off_task(fn, task, taskname) | 1137 | proc = self.fork_off_task(fn, task, taskname) |
1157 | 1138 | ||
1158 | self.build_pids[pid] = task | 1139 | self.build_pids[proc.pid] = task |
1159 | self.build_pipes[pid] = runQueuePipe(pipein, pipeout, self.cfgData) | 1140 | self.build_procs[proc.pid] = proc |
1141 | self.build_pipes[proc.pid] = runQueuePipe(proc.stdout, proc.stdin, self.cfgData) | ||
1160 | self.runq_running[task] = 1 | 1142 | self.runq_running[task] = 1 |
1161 | self.stats.taskActive() | 1143 | self.stats.taskActive() |
1162 | if self.stats.active < self.number_tasks: | 1144 | if self.stats.active < self.number_tasks: |
@@ -1356,10 +1338,11 @@ class RunQueueExecuteScenequeue(RunQueueExecute): | |||
1356 | self.task_skip(task) | 1338 | self.task_skip(task) |
1357 | return True | 1339 | return True |
1358 | 1340 | ||
1359 | pid, pipein, pipeout = self.fork_off_task(fn, realtask, taskname) | 1341 | proc = self.fork_off_task(fn, realtask, taskname) |
1360 | 1342 | ||
1361 | self.build_pids[pid] = task | 1343 | self.build_pids[proc.pid] = task |
1362 | self.build_pipes[pid] = runQueuePipe(pipein, pipeout, self.cfgData) | 1344 | self.build_procs[proc.pid] = proc |
1345 | self.build_pipes[proc.pid] = runQueuePipe(proc.stdout, proc.stdin, self.cfgData) | ||
1363 | self.runq_running[task] = 1 | 1346 | self.runq_running[task] = 1 |
1364 | self.stats.taskActive() | 1347 | self.stats.taskActive() |
1365 | if self.stats.active < self.number_tasks: | 1348 | if self.stats.active < self.number_tasks: |
@@ -1384,7 +1367,6 @@ class RunQueueExecuteScenequeue(RunQueueExecute): | |||
1384 | self.rq.state = runQueueRunInit | 1367 | self.rq.state = runQueueRunInit |
1385 | return True | 1368 | return True |
1386 | 1369 | ||
1387 | |||
1388 | class TaskFailure(Exception): | 1370 | class TaskFailure(Exception): |
1389 | """ | 1371 | """ |
1390 | Exception raised when a task in a runqueue fails | 1372 | Exception raised when a task in a runqueue fails |
@@ -1437,14 +1419,14 @@ class runQueueTaskCompleted(runQueueEvent): | |||
1437 | runQueueEvent.__init__(self, task, stats, rq) | 1419 | runQueueEvent.__init__(self, task, stats, rq) |
1438 | self.message = "Task %s completed (%s)" % (task, self.taskstring) | 1420 | self.message = "Task %s completed (%s)" % (task, self.taskstring) |
1439 | 1421 | ||
1440 | def check_stamp_fn(fn, taskname, d): | 1422 | #def check_stamp_fn(fn, taskname, d): |
1441 | rq = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", d) | 1423 | # rq = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY", d) |
1442 | fn = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY2", d) | 1424 | # fn = bb.data.getVar("__RUNQUEUE_DO_NOT_USE_EXTERNALLY2", d) |
1443 | fnid = rq.rqdata.taskData.getfn_id(fn) | 1425 | # fnid = rq.rqdata.taskData.getfn_id(fn) |
1444 | taskid = rq.get_task_id(fnid, taskname) | 1426 | # taskid = rq.get_task_id(fnid, taskname) |
1445 | if taskid is not None: | 1427 | # if taskid is not None: |
1446 | return rq.check_stamp_task(taskid) | 1428 | # return rq.check_stamp_task(taskid) |
1447 | return None | 1429 | # return None |
1448 | 1430 | ||
1449 | class runQueuePipe(): | 1431 | class runQueuePipe(): |
1450 | """ | 1432 | """ |
@@ -1452,7 +1434,7 @@ class runQueuePipe(): | |||
1452 | """ | 1434 | """ |
1453 | def __init__(self, pipein, pipeout, d): | 1435 | def __init__(self, pipein, pipeout, d): |
1454 | self.fd = pipein | 1436 | self.fd = pipein |
1455 | os.close(pipeout) | 1437 | pipeout.close() |
1456 | fcntl.fcntl(self.fd, fcntl.F_SETFL, fcntl.fcntl(self.fd, fcntl.F_GETFL) | os.O_NONBLOCK) | 1438 | fcntl.fcntl(self.fd, fcntl.F_SETFL, fcntl.fcntl(self.fd, fcntl.F_GETFL) | os.O_NONBLOCK) |
1457 | self.queue = "" | 1439 | self.queue = "" |
1458 | self.d = d | 1440 | self.d = d |
@@ -1460,8 +1442,8 @@ class runQueuePipe(): | |||
1460 | def read(self): | 1442 | def read(self): |
1461 | start = len(self.queue) | 1443 | start = len(self.queue) |
1462 | try: | 1444 | try: |
1463 | self.queue = self.queue + os.read(self.fd, 1024) | 1445 | self.queue = self.queue + self.fd.read(1024) |
1464 | except OSError: | 1446 | except IOError: |
1465 | pass | 1447 | pass |
1466 | end = len(self.queue) | 1448 | end = len(self.queue) |
1467 | index = self.queue.find("</event>") | 1449 | index = self.queue.find("</event>") |
@@ -1476,4 +1458,4 @@ class runQueuePipe(): | |||
1476 | continue | 1458 | continue |
1477 | if len(self.queue) > 0: | 1459 | if len(self.queue) > 0: |
1478 | print("Warning, worker left partial message") | 1460 | print("Warning, worker left partial message") |
1479 | os.close(self.fd) | 1461 | self.fd.close() |