aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2024-02-24 21:09:48 -0800
committerSam James <sam@gentoo.org>2024-02-25 08:24:59 +0000
commit92615cd37d7a1efce923c474e455f59fe61a589c (patch)
treeb98713b2c8ba81f3777aff4a933bb387f782412a
parentdbapi: Fix TypeError when passing Exception to warnings.warn (diff)
downloadportage-92615cd37d7a1efce923c474e455f59fe61a589c.tar.gz
portage-92615cd37d7a1efce923c474e455f59fe61a589c.tar.bz2
portage-92615cd37d7a1efce923c474e455f59fe61a589c.zip
_start_proc: Prevent premature ForkProcess garbage collection
In order to prevent the constructed ForkProcess instance from being prematurely garbage collected, return a reference to the caller inside of a _GCProtector object, preventing messages reported in bug 925456 like this: [ERROR] Task was destroyed but it is pending! Fixes: a69c1b853a47 ("process.spawn: Use multiprocessing.Process for returnproc") Bug: https://bugs.gentoo.org/925456 Signed-off-by: Zac Medico <zmedico@gentoo.org> Closes: https://github.com/gentoo/portage/pull/1284 Signed-off-by: Sam James <sam@gentoo.org>
-rw-r--r--lib/portage/process.py41
1 files changed, 39 insertions, 2 deletions
diff --git a/lib/portage/process.py b/lib/portage/process.py
index d16262e75..cc9ed7bf7 100644
--- a/lib/portage/process.py
+++ b/lib/portage/process.py
@@ -36,6 +36,7 @@ portage.proxy.lazyimport.lazyimport(
from portage.const import BASH_BINARY, SANDBOX_BINARY, FAKEROOT_BINARY
from portage.exception import CommandNotFound
+from portage.proxy.objectproxy import ObjectProxy
from portage.util._ctypes import find_library, LoadLibrary, ctypes
try:
@@ -1493,8 +1494,44 @@ def _start_proc(
proc.start()
# ForkProcess conveniently holds a MultiprocessingProcess
- # instance that is suitable to return here.
- return proc._proc
+ # instance that is suitable to return here, but use _GCProtector
+ # to protect the ForkProcess instance from being garbage collected
+ # and triggering messages like this (bug 925456):
+ # [ERROR] Task was destroyed but it is pending!
+ return _GCProtector(proc._proc, proc.async_wait)
+
+
+class _GCProtector(ObjectProxy):
+ """
+ Proxy a target object, and also hold a reference to something
+ extra in order to protect it from garbage collection. Override
+ the wait method to first call target's wait method and then
+ wait for extra (a coroutine function) before returning the result.
+ """
+
+ __slots__ = ("_extra", "_target")
+
+ def __init__(self, target, extra):
+ super().__init__()
+ object.__setattr__(self, "_target", target)
+ object.__setattr__(self, "_extra", extra)
+
+ def _get_target(self):
+ return object.__getattribute__(self, "_target")
+
+ def __getattribute__(self, attr):
+ if attr == "wait":
+ return object.__getattribute__(self, attr)
+ return getattr(object.__getattribute__(self, "_target"), attr)
+
+ async def wait(self):
+ """
+ Wrap the target's wait method to also wait for an extra
+ coroutine function.
+ """
+ result = await object.__getattribute__(self, "_target").wait()
+ await object.__getattribute__(self, "_extra")()
+ return result
def find_binary(binary):