diff options
author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-09-29 09:28:24 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-10-01 07:43:38 +0100 |
commit | 1e467b333fe164a71404f3e3f6974440ce00e90f (patch) | |
tree | 781cb96d168c2734ff2e2b57ba9383c8cfadbea7 /bitbake | |
parent | e5b9c2a9f2b9ad354d246b20d7252957dd5ebb42 (diff) | |
download | poky-1e467b333fe164a71404f3e3f6974440ce00e90f.tar.gz |
bitbake: bitbake-worker: Guard against multiprocessing corruption of event data
In the forked child, we may use multiprocessing. There is only one event
pipe to the worker controlling process and if we're unlucky, multiple
processes can write to it at once corrupting the data by intermixing it.
We don't see this often but when we do, its quite puzzling. I suspect it
only happens in tasks which use multiprocessng (do_rootfs, do_package)
and is much more likely to happen when we have long messages, usually many
times PAGE_SIZE since PAGE_SIZE writes are atomic. This makes it much more
likely within do_roofs, when for example a subprocess lists the contents
of a rootfs.
To fix this, we give each child a Lock() object and use this to serialise
writes to the controlling worker.
(Bitbake rev: 3cb55bdf06148943960e438291f9a562857340a3)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rwxr-xr-x | bitbake/bin/bitbake-worker | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/bitbake/bin/bitbake-worker b/bitbake/bin/bitbake-worker index af17b874aa..3390f637e3 100755 --- a/bitbake/bin/bitbake-worker +++ b/bitbake/bin/bitbake-worker | |||
@@ -10,6 +10,7 @@ import bb | |||
10 | import select | 10 | import select |
11 | import errno | 11 | import errno |
12 | import signal | 12 | import signal |
13 | from multiprocessing import Lock | ||
13 | 14 | ||
14 | # Users shouldn't be running this code directly | 15 | # Users shouldn't be running this code directly |
15 | if len(sys.argv) != 2 or not sys.argv[1].startswith("decafbad"): | 16 | if len(sys.argv) != 2 or not sys.argv[1].startswith("decafbad"): |
@@ -44,6 +45,9 @@ except ImportError: | |||
44 | 45 | ||
45 | worker_pipe = sys.stdout.fileno() | 46 | worker_pipe = sys.stdout.fileno() |
46 | bb.utils.nonblockingfd(worker_pipe) | 47 | bb.utils.nonblockingfd(worker_pipe) |
48 | # Need to guard against multiprocessing being used in child processes | ||
49 | # and multiple processes trying to write to the parent at the same time | ||
50 | worker_pipe_lock = None | ||
47 | 51 | ||
48 | handler = bb.event.LogHandler() | 52 | handler = bb.event.LogHandler() |
49 | logger.addHandler(handler) | 53 | logger.addHandler(handler) |
@@ -85,10 +89,13 @@ def worker_flush(): | |||
85 | 89 | ||
86 | def worker_child_fire(event, d): | 90 | def worker_child_fire(event, d): |
87 | global worker_pipe | 91 | global worker_pipe |
92 | global worker_pipe_lock | ||
88 | 93 | ||
89 | data = "<event>" + pickle.dumps(event) + "</event>" | 94 | data = "<event>" + pickle.dumps(event) + "</event>" |
90 | try: | 95 | try: |
96 | worker_pipe_lock.acquire() | ||
91 | worker_pipe.write(data) | 97 | worker_pipe.write(data) |
98 | worker_pipe_lock.release() | ||
92 | except IOError: | 99 | except IOError: |
93 | sigterm_handler(None, None) | 100 | sigterm_handler(None, None) |
94 | raise | 101 | raise |
@@ -157,6 +164,7 @@ def fork_off_task(cfg, data, workerdata, fn, task, taskname, appends, taskdepdat | |||
157 | if pid == 0: | 164 | if pid == 0: |
158 | def child(): | 165 | def child(): |
159 | global worker_pipe | 166 | global worker_pipe |
167 | global worker_pipe_lock | ||
160 | pipein.close() | 168 | pipein.close() |
161 | 169 | ||
162 | signal.signal(signal.SIGTERM, sigterm_handler) | 170 | signal.signal(signal.SIGTERM, sigterm_handler) |
@@ -169,6 +177,7 @@ def fork_off_task(cfg, data, workerdata, fn, task, taskname, appends, taskdepdat | |||
169 | bb.event.worker_pid = os.getpid() | 177 | bb.event.worker_pid = os.getpid() |
170 | bb.event.worker_fire = worker_child_fire | 178 | bb.event.worker_fire = worker_child_fire |
171 | worker_pipe = pipeout | 179 | worker_pipe = pipeout |
180 | worker_pipe_lock = Lock() | ||
172 | 181 | ||
173 | # Make the child the process group leader and ensure no | 182 | # Make the child the process group leader and ensure no |
174 | # child process will be controlled by the current terminal | 183 | # child process will be controlled by the current terminal |