public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/ebuild/, lib/portage/, lib/_emerge/
@ 2024-02-04  8:11 Zac Medico
  0 siblings, 0 replies; only message in thread
From: Zac Medico @ 2024-02-04  8:11 UTC (permalink / raw
  To: gentoo-commits

commit:     052a4076cdf29fde8481646c636190d9db35f0ff
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Feb  4 08:08:01 2024 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Feb  4 08:10:12 2024 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=052a4076

Revert "process.spawn: Use multiprocessing.Process for returnproc"

This reverts commit 305612d1b04aa06d3d1a1c8b51d046a644742fd5.
It triggered a "Bad file descriptor" during the instprep
phase as reported in bug 923755.

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

 lib/_emerge/SpawnProcess.py                        |  4 +-
 lib/portage/process.py                             | 72 ++++------------------
 lib/portage/tests/ebuild/test_doebuild_fd_pipes.py |  6 +-
 3 files changed, 15 insertions(+), 67 deletions(-)

diff --git a/lib/_emerge/SpawnProcess.py b/lib/_emerge/SpawnProcess.py
index 5e582e3322..7f4a23892b 100644
--- a/lib/_emerge/SpawnProcess.py
+++ b/lib/_emerge/SpawnProcess.py
@@ -224,9 +224,7 @@ class SpawnProcess(SubProcess):
         got_pty, master_fd, slave_fd = _create_pty_or_pipe(copy_term_size=stdout_pipe)
         return (master_fd, slave_fd)
 
-    def _spawn(
-        self, args: list[str], **kwargs
-    ) -> portage.process.MultiprocessingProcess:
+    def _spawn(self, args: list[str], **kwargs) -> portage.process.Process:
         spawn_func = portage.process.spawn
 
         if self._selinux_type is not None:

diff --git a/lib/portage/process.py b/lib/portage/process.py
index d64ffa924f..01426179d7 100644
--- a/lib/portage/process.py
+++ b/lib/portage/process.py
@@ -19,7 +19,7 @@ import warnings
 
 from dataclasses import dataclass
 from functools import lru_cache
-from typing import Any, Optional, Callable, Union
+from typing import Any, Optional, Callable
 
 from portage import os
 from portage import _encodings
@@ -28,7 +28,6 @@ import portage
 
 portage.proxy.lazyimport.lazyimport(
     globals(),
-    "portage.util._async.ForkProcess:ForkProcess",
     "portage.util._eventloop.global_event_loop:global_event_loop",
     "portage.util.futures:asyncio",
     "portage.util:dump_traceback,writemsg,writemsg_level",
@@ -297,19 +296,12 @@ class AbstractProcess:
 
 class Process(AbstractProcess):
     """
-    An object that wraps OS processes which do not have an
-    associated multiprocessing.Process instance. Ultimately,
-    we need to stop using os.fork() to create these processes
-    because it is unsafe for threaded processes as discussed
-    in https://github.com/python/cpython/issues/84559.
-
-    Note that if subprocess.Popen is used without pass_fds
-    or preexec_fn parameters, then it avoids using os.fork()
-    by instead using posix_spawn. This approach is not used
-    by spawn because it needs to execute python code prior
-    to exec, so it instead uses multiprocessing.Process,
-    which only uses os.fork() when the multiprocessing start
-    method is fork.
+    An object that wraps OS processes created by spawn.
+    In the future, spawn will return objects of a different type
+    but with a compatible interface to this class, in order
+    to encapsulate implementation-dependent objects like
+    multiprocessing.Process which are designed to manage
+    the process lifecycle and need to persist until it exits.
     """
 
     def __init__(self, pid: int):
@@ -469,7 +461,7 @@ def spawn(
     unshare_mount=False,
     unshare_pid=False,
     warn_on_large_env=False,
-) -> Union[int, MultiprocessingProcess, list[int]]:
+):
     """
     Spawns a given command.
 
@@ -487,8 +479,8 @@ def spawn(
     @param returnpid: Return the Process IDs for a successful spawn.
     NOTE: This requires the caller clean up all the PIDs, otherwise spawn will clean them.
     @type returnpid: Boolean
-    @param returnproc: Return a MultiprocessingProcess instance (conflicts with logfile parameter).
-    NOTE: This requires the caller to asynchronously wait for the MultiprocessingProcess instance.
+    @param returnproc: Return a Process object for a successful spawn (conflicts with logfile parameter).
+    NOTE: This requires the caller to asynchronously wait for the Process.
     @type returnproc: Boolean
     @param uid: User ID to spawn as; useful for dropping privilages
     @type uid: Integer
@@ -631,9 +623,7 @@ def spawn(
     # fork, so that the result is cached in the main process.
     bool(groups)
 
-    start_func = _start_proc if returnproc else _start_fork
-
-    pid = start_func(
+    pid = _start_fork(
         _exec_wrapper,
         args=(
             binary,
@@ -659,10 +649,6 @@ def spawn(
         close_fds=close_fds,
     )
 
-    if returnproc:
-        # _start_proc returns a MultiprocessingProcess instance.
-        return pid
-
     if not isinstance(pid, int):
         raise AssertionError(f"fork returned non-integer: {repr(pid)}")
 
@@ -684,6 +670,8 @@ def spawn(
                 stacklevel=1,
             )
         return mypids
+    if returnproc:
+        return Process(mypids[0])
 
     # Otherwise we clean them up.
     while mypids:
@@ -1382,40 +1370,6 @@ def _start_fork(
     return pid
 
 
-def _start_proc(
-    target: Callable[..., None],
-    args: Optional[tuple[Any, ...]] = (),
-    kwargs: Optional[dict[str, Any]] = {},
-    fd_pipes: Optional[dict[int, int]] = None,
-    close_fds: Optional[bool] = False,
-) -> MultiprocessingProcess:
-    """
-    Execute the target function using multiprocess.Process.
-    If the close_fds parameter is True then NotImplementedError
-    is raised, since it is risky to forcefully close file
-    descriptors that have references (bug 374335), and PEP 446
-    should ensure that any relevant file descriptors are
-    non-inheritable and therefore automatically closed on exec.
-    """
-    if close_fds:
-        raise NotImplementedError(
-            "close_fds is not supported (since file descriptors are non-inheritable by default for exec)"
-        )
-
-    proc = ForkProcess(
-        scheduler=global_event_loop(),
-        target=target,
-        args=args,
-        kwargs=kwargs,
-        fd_pipes=fd_pipes,
-    )
-    proc.start()
-
-    # ForkProcess conveniently holds a MultiprocessingProcess
-    # instance that is suitable to return here.
-    return proc._proc
-
-
 def find_binary(binary):
     """
     Given a binary name, find the binary in PATH

diff --git a/lib/portage/tests/ebuild/test_doebuild_fd_pipes.py b/lib/portage/tests/ebuild/test_doebuild_fd_pipes.py
index c3b47d4e89..678486ed16 100644
--- a/lib/portage/tests/ebuild/test_doebuild_fd_pipes.py
+++ b/lib/portage/tests/ebuild/test_doebuild_fd_pipes.py
@@ -1,4 +1,4 @@
-# Copyright 2013-2024 Gentoo Authors
+# Copyright 2013-2023 Gentoo Authors
 # Distributed under the terms of the GNU General Public License v2
 
 import multiprocessing
@@ -167,10 +167,6 @@ class DoebuildFdPipesTestCase(TestCase):
     @staticmethod
     def _doebuild(db, pw, *args, **kwargs):
         QueryCommand._db = db
-        # Somehow pw.fileno() is inheritable when doebuild is
-        # implemented with os.fork(), but not when it is implemented
-        # with multiprocessing.Process.
-        os.set_inheritable(pw.fileno(), True)
         kwargs["fd_pipes"] = {
             DoebuildFdPipesTestCase.output_fd: pw.fileno(),
         }


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2024-02-04  8:11 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-04  8:11 [gentoo-commits] proj/portage:master commit in: lib/portage/tests/ebuild/, lib/portage/, lib/_emerge/ Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox