commit:     6b08846736ebf8a224f8aad2a5b17baf66fec1e0
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Aug  8 02:19:31 2020 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Aug  9 00:48:12 2020 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=6b088467

Add cached portage.getpid() function

Since getpid is a syscall, cache results, and update them
via an after fork hook.

Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>

 lib/portage/__init__.py                         | 16 ++++++++++++++++
 lib/portage/tests/process/test_AsyncFunction.py | 24 ++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/lib/portage/__init__.py b/lib/portage/__init__.py
index 916c93510..4d4b590a8 100644
--- a/lib/portage/__init__.py
+++ b/lib/portage/__init__.py
@@ -14,6 +14,7 @@ try:
        if not hasattr(errno, 'ESTALE'):
                # ESTALE may not be defined on some systems, such as interix.
                errno.ESTALE = -1
+       import multiprocessing.util
        import re
        import types
        import platform
@@ -368,6 +369,21 @@ _internal_caller = False
 
 _sync_mode = False
 
+class _ForkWatcher:
+       @staticmethod
+       def hook(_ForkWatcher):
+               _ForkWatcher.current_pid = _os.getpid()
+
+_ForkWatcher.hook(_ForkWatcher)
+
+multiprocessing.util.register_after_fork(_ForkWatcher, _ForkWatcher.hook)
+
+def getpid():
+       """
+       Cached version of os.getpid(). ForkProcess updates the cache.
+       """
+       return _ForkWatcher.current_pid
+
 def _get_stdin():
        """
        Buggy code in python's multiprocessing/process.py closes sys.stdin

diff --git a/lib/portage/tests/process/test_AsyncFunction.py 
b/lib/portage/tests/process/test_AsyncFunction.py
index 55857026d..3b360e02f 100644
--- a/lib/portage/tests/process/test_AsyncFunction.py
+++ b/lib/portage/tests/process/test_AsyncFunction.py
@@ -3,6 +3,7 @@
 
 import sys
 
+import portage
 from portage import os
 from portage.tests import TestCase
 from portage.util._async.AsyncFunction import AsyncFunction
@@ -36,3 +37,26 @@ class AsyncFunctionTestCase(TestCase):
        def testAsyncFunctionStdin(self):
                loop = asyncio._wrap_loop()
                loop.run_until_complete(self._testAsyncFunctionStdin(loop))
+
+       def _test_getpid_fork(self):
+               """
+               Verify that portage.getpid() cache is updated in a forked child 
process.
+               """
+               loop = asyncio._wrap_loop()
+               proc = AsyncFunction(scheduler=loop, target=portage.getpid)
+               proc.start()
+               proc.wait()
+               self.assertEqual(proc.pid, proc.result)
+
+       def test_getpid_fork(self):
+               self._test_getpid_fork()
+
+       def test_getpid_double_fork(self):
+               """
+               Verify that portage.getpid() cache is updated correctly after
+               two forks.
+               """
+               loop = asyncio._wrap_loop()
+               proc = AsyncFunction(scheduler=loop, 
target=self._test_getpid_fork)
+               proc.start()
+               self.assertEqual(proc.wait(), 0)

Reply via email to