diff options
author | Zac Medico <zmedico@gentoo.org> | 2024-02-24 21:09:48 -0800 |
---|---|---|
committer | Sam James <sam@gentoo.org> | 2024-02-25 08:24:59 +0000 |
commit | 92615cd37d7a1efce923c474e455f59fe61a589c (patch) | |
tree | b98713b2c8ba81f3777aff4a933bb387f782412a | |
parent | dbapi: Fix TypeError when passing Exception to warnings.warn (diff) | |
download | portage-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.py | 41 |
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): |