1
0
mirror of https://git.yoctoproject.org/poky synced 2026-05-31 00:39:46 +00:00

bitbake: cooker/process: Fix signal handling lockups

If a parser process is terminated while holding a write lock, then it
will lead to a deadlock (see
https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Process.terminate).

With SIGTERM, we don't want to terminate holding the lock. We also don't
want a SIGINT to cause a partial write to the event stream.

I tried using signal masks to avoid this but it doesn't work, see
https://bugs.python.org/issue47139

Instead, add a signal handler and catch the calls around the critical section.
We also need a thread lock to ensure other threads in the same process don't
handle the signal until all the threads are not in the lock.

(Bitbake rev: a40efaa5556a188dfe46c8d060adde37dc400dcd)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Richard Purdie
2022-03-29 15:17:10 +01:00
parent c0ff6c75ee
commit 928bcb10a4
2 changed files with 46 additions and 4 deletions
+20 -2
View File
@@ -20,6 +20,7 @@ import os
import sys
import time
import select
import signal
import socket
import subprocess
import errno
@@ -737,11 +738,28 @@ class ConnectionWriter(object):
# Why bb.event needs this I have no idea
self.event = self
def send(self, obj):
obj = multiprocessing.reduction.ForkingPickler.dumps(obj)
def _send(self, obj):
with self.wlock:
self.writer.send_bytes(obj)
def send(self, obj):
obj = multiprocessing.reduction.ForkingPickler.dumps(obj)
# See notes/code in CookerParser
# We must not terminate holding this lock else processes will hang.
# For SIGTERM, raising afterwards avoids this.
# For SIGINT, we don't want to have written partial data to the pipe.
# pthread_sigmask block/unblock would be nice but doesn't work, https://bugs.python.org/issue47139
process = multiprocessing.current_process()
if process and hasattr(process, "queue_signals"):
with process.signal_threadlock:
process.queue_signals = True
self._send(obj)
process.queue_signals = False
for sig in process.signal_received.pop():
process.handle_sig(sig, None)
else:
self._send(obj)
def fileno(self):
return self.writer.fileno()