Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH 1/3] Add cached portage.getpid() function
Date: Sat, 08 Aug 2020 04:13:27
Message-Id: 20200808040857.77352-2-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH 0/3] sqlite: fork safety (bug 736334) by Zac Medico
1 Since getpid is a syscall, cache results, and update them
2 via an after fork hook.
3
4 Signed-off-by: Zac Medico <zmedico@g.o>
5 ---
6 lib/portage/__init__.py | 14 +++++++++++
7 .../tests/process/test_AsyncFunction.py | 24 +++++++++++++++++++
8 2 files changed, 38 insertions(+)
9
10 diff --git a/lib/portage/__init__.py b/lib/portage/__init__.py
11 index 916c93510..52902ba7d 100644
12 --- a/lib/portage/__init__.py
13 +++ b/lib/portage/__init__.py
14 @@ -14,6 +14,7 @@ try:
15 if not hasattr(errno, 'ESTALE'):
16 # ESTALE may not be defined on some systems, such as interix.
17 errno.ESTALE = -1
18 + import multiprocessing.util
19 import re
20 import types
21 import platform
22 @@ -368,6 +369,19 @@ _internal_caller = False
23
24 _sync_mode = False
25
26 +def _fork_watcher(_fork_watcher):
27 + _fork_watcher.current_pid = _os.getpid()
28 +
29 +_fork_watcher(_fork_watcher)
30 +
31 +multiprocessing.util.register_after_fork(_fork_watcher, _fork_watcher)
32 +
33 +def getpid():
34 + """
35 + Cached version of os.getpid(). ForkProcess updates the cache.
36 + """
37 + return _fork_watcher.current_pid
38 +
39 def _get_stdin():
40 """
41 Buggy code in python's multiprocessing/process.py closes sys.stdin
42 diff --git a/lib/portage/tests/process/test_AsyncFunction.py b/lib/portage/tests/process/test_AsyncFunction.py
43 index 55857026d..3b360e02f 100644
44 --- a/lib/portage/tests/process/test_AsyncFunction.py
45 +++ b/lib/portage/tests/process/test_AsyncFunction.py
46 @@ -3,6 +3,7 @@
47
48 import sys
49
50 +import portage
51 from portage import os
52 from portage.tests import TestCase
53 from portage.util._async.AsyncFunction import AsyncFunction
54 @@ -36,3 +37,26 @@ class AsyncFunctionTestCase(TestCase):
55 def testAsyncFunctionStdin(self):
56 loop = asyncio._wrap_loop()
57 loop.run_until_complete(self._testAsyncFunctionStdin(loop))
58 +
59 + def _test_getpid_fork(self):
60 + """
61 + Verify that portage.getpid() cache is updated in a forked child process.
62 + """
63 + loop = asyncio._wrap_loop()
64 + proc = AsyncFunction(scheduler=loop, target=portage.getpid)
65 + proc.start()
66 + proc.wait()
67 + self.assertEqual(proc.pid, proc.result)
68 +
69 + def test_getpid_fork(self):
70 + self._test_getpid_fork()
71 +
72 + def test_getpid_double_fork(self):
73 + """
74 + Verify that portage.getpid() cache is updated correctly after
75 + two forks.
76 + """
77 + loop = asyncio._wrap_loop()
78 + proc = AsyncFunction(scheduler=loop, target=self._test_getpid_fork)
79 + proc.start()
80 + self.assertEqual(proc.wait(), 0)
81 --
82 2.25.3

Replies