commit:     ba33bc425363977eaf549a087b2469720a79e2a4
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Thu Feb  8 06:46:04 2024 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Fri Feb  9 08:19:00 2024 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=ba33bc42

check_locale: Use multiprocessing.Process instead of os.fork()

Since os.fork() is unsafe in threaded processes, use
multiprocessing.Process instead. This way the fork will be
eliminated when the default multiprocessing start method
changes to "spawn".

TODO: Make async version of check_locale and call it from
EbuildPhase instead of config.environ(), since it's bad to
synchronously wait for the process in the main event loop
thread where config.environ() tends to be called.

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

 lib/portage/util/locale.py | 56 +++++++++++++++++++++++++++-------------------
 1 file changed, 33 insertions(+), 23 deletions(-)

diff --git a/lib/portage/util/locale.py b/lib/portage/util/locale.py
index a620dbd544..b5da8d949b 100644
--- a/lib/portage/util/locale.py
+++ b/lib/portage/util/locale.py
@@ -9,7 +9,8 @@ locale.
 
 import locale
 import logging
-import os
+import multiprocessing
+import sys
 import textwrap
 import traceback
 
@@ -96,6 +97,24 @@ def _check_locale(silent):
     return True
 
 
+def _set_and_check_locale(silent, env, mylocale):
+    try:
+        if env is not None:
+            try:
+                locale.setlocale(locale.LC_CTYPE, mylocale)
+            except locale.Error:
+                sys.exit(2)
+
+        ret = _check_locale(silent)
+        if ret is None:
+            sys.exit(2)
+        else:
+            sys.exit(0 if ret else 1)
+    except Exception:
+        traceback.print_exc()
+        sys.exit(2)
+
+
 def check_locale(silent=False, env=None):
     """
     Check whether the locale is sane. Returns True if it is, prints
@@ -116,29 +135,20 @@ def check_locale(silent=False, env=None):
         except KeyError:
             pass
 
-    pid = os.fork()
-    if pid == 0:
-        try:
-            if env is not None:
-                try:
-                    locale.setlocale(locale.LC_CTYPE, 
portage._native_string(mylocale))
-                except locale.Error:
-                    os._exit(2)
-
-            ret = _check_locale(silent)
-            if ret is None:
-                os._exit(2)
-            else:
-                os._exit(0 if ret else 1)
-        except Exception:
-            traceback.print_exc()
-            os._exit(2)
-
-    pid2, ret = os.waitpid(pid, 0)
-    assert pid == pid2
+    # TODO: Make async version of check_locale and call it from
+    # EbuildPhase instead of config.environ(), since it's bad to
+    # synchronously wait for the process in the main event loop
+    # thread where config.environ() tends to be called.
+    proc = multiprocessing.Process(
+        target=_set_and_check_locale,
+        args=(silent, env, None if env is None else 
portage._native_string(mylocale)),
+    )
+    proc.start()
+    proc.join()
+
     pyret = None
-    if os.WIFEXITED(ret):
-        ret = os.WEXITSTATUS(ret)
+    if proc.exitcode >= 0:
+        ret = proc.exitcode
         if ret != 2:
             pyret = ret == 0
 

Reply via email to