commit:     7d7ef237f3dddcf450fedab5aabfd57d1fb3406d
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Feb  6 01:35:25 2024 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Wed Feb  7 00:36:56 2024 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=7d7ef237

ForkProcess: Handle BrokenPipeError in _send_fd_pipes

Convert _send_fd_pipes BrokenPipeError to asyncio.CancelledError,
in order to gracefully handle a concurrently terminated child
process as in testAsynchronousLockWaitCancel. Even if the child
terminated abnormally, then there is no harm in suppressing the
exception here, since the child error should have gone to stderr.

Bug: https://bugs.gentoo.org/923852
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/portage/util/_async/ForkProcess.py | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/lib/portage/util/_async/ForkProcess.py 
b/lib/portage/util/_async/ForkProcess.py
index cb240d0712..ebcbd94107 100644
--- a/lib/portage/util/_async/ForkProcess.py
+++ b/lib/portage/util/_async/ForkProcess.py
@@ -153,15 +153,24 @@ class ForkProcess(SpawnProcess):
         This performs blocking IO, intended for invocation via run_in_executor.
         """
         fd_list = list(set(self._fd_pipes.values()))
-        self._files.connection.send(
-            (self._fd_pipes, fd_list),
-        )
-        for fd in fd_list:
-            multiprocessing.reduction.send_handle(
-                self._files.connection,
-                fd,
-                self.pid,
+        try:
+            self._files.connection.send(
+                (self._fd_pipes, fd_list),
             )
+            for fd in fd_list:
+                multiprocessing.reduction.send_handle(
+                    self._files.connection,
+                    fd,
+                    self.pid,
+                )
+        except BrokenPipeError as e:
+            # This case is triggered by testAsynchronousLockWaitCancel
+            # when the test case terminates the child process while
+            # this thread is still sending the fd_pipes (bug 923852).
+            # Even if the child terminated abnormally, then there is
+            # no harm in suppressing the exception here, since the
+            # child error should have gone to stderr.
+            raise asyncio.CancelledError from e
 
         # self._fd_pipes contains duplicates that must be closed.
         for fd in fd_list:

Reply via email to