1 |
This is needed for Windows Subsystem for Linux (WSL), as well as |
2 |
older versions of PyPy. |
3 |
|
4 |
X-Gentoo-bug: 595146 |
5 |
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=595146 |
6 |
--- |
7 |
pym/portage/locks.py | 59 +++++++++++++++++++++++++++++++++++++++++++++------- |
8 |
1 file changed, 52 insertions(+), 7 deletions(-) |
9 |
|
10 |
diff --git a/pym/portage/locks.py b/pym/portage/locks.py |
11 |
index 42ff1e3..a4564cf 100644 |
12 |
--- a/pym/portage/locks.py |
13 |
+++ b/pym/portage/locks.py |
14 |
@@ -8,8 +8,9 @@ __all__ = ["lockdir", "unlockdir", "lockfile", "unlockfile", \ |
15 |
|
16 |
import errno |
17 |
import fcntl |
18 |
-import platform |
19 |
+import multiprocessing |
20 |
import sys |
21 |
+import tempfile |
22 |
import time |
23 |
import warnings |
24 |
|
25 |
@@ -27,17 +28,61 @@ if sys.hexversion >= 0x3000000: |
26 |
|
27 |
HARDLINK_FD = -2 |
28 |
_HARDLINK_POLL_LATENCY = 3 # seconds |
29 |
-_default_lock_fn = fcntl.lockf |
30 |
- |
31 |
-if platform.python_implementation() == 'PyPy': |
32 |
- # workaround for https://bugs.pypy.org/issue747 |
33 |
- _default_lock_fn = fcntl.flock |
34 |
|
35 |
# Used by emerge in order to disable the "waiting for lock" message |
36 |
# so that it doesn't interfere with the status display. |
37 |
_quiet = False |
38 |
|
39 |
|
40 |
+_lock_fn = None |
41 |
+ |
42 |
+ |
43 |
+def _get_lock_fn(): |
44 |
+ """ |
45 |
+ Returns fcntl.lockf if proven to work, and otherwise returns fcntl.flock. |
46 |
+ On some platforms fcntl.lockf is known to be broken. |
47 |
+ """ |
48 |
+ global _lock_fn |
49 |
+ if _lock_fn is not None: |
50 |
+ return _lock_fn |
51 |
+ |
52 |
+ def _test_lock(fd, lock_path): |
53 |
+ os.close(fd) |
54 |
+ try: |
55 |
+ with open(lock_path, 'a') as f: |
56 |
+ fcntl.lockf(f.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB) |
57 |
+ except EnvironmentError as e: |
58 |
+ if e.errno == errno.EAGAIN: |
59 |
+ # Parent process holds lock, as expected. |
60 |
+ sys.exit(0) |
61 |
+ |
62 |
+ # Something went wrong. |
63 |
+ sys.exit(1) |
64 |
+ |
65 |
+ fd, lock_path = tempfile.mkstemp() |
66 |
+ try: |
67 |
+ try: |
68 |
+ fcntl.lockf(fd, fcntl.LOCK_EX) |
69 |
+ except EnvironmentError: |
70 |
+ pass |
71 |
+ else: |
72 |
+ proc = multiprocessing.Process(target=_test_lock, |
73 |
+ args=(fd, lock_path)) |
74 |
+ proc.start() |
75 |
+ proc.join() |
76 |
+ if proc.exitcode == os.EX_OK: |
77 |
+ # Use fcntl.lockf becase the test passed. |
78 |
+ _lock_fn = fcntl.lockf |
79 |
+ return _lock_fn |
80 |
+ finally: |
81 |
+ os.close(fd) |
82 |
+ os.unlink(lock_path) |
83 |
+ |
84 |
+ # Fall back to fcntl.flock. |
85 |
+ _lock_fn = fcntl.flock |
86 |
+ return _lock_fn |
87 |
+ |
88 |
+ |
89 |
_open_fds = set() |
90 |
|
91 |
def _close_fds(): |
92 |
@@ -146,7 +191,7 @@ def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, |
93 |
|
94 |
# try for a non-blocking lock, if it's held, throw a message |
95 |
# we're waiting on lockfile and use a blocking attempt. |
96 |
- locking_method = portage._eintr_func_wrapper(_default_lock_fn) |
97 |
+ locking_method = portage._eintr_func_wrapper(_get_lock_fn()) |
98 |
try: |
99 |
if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: |
100 |
raise IOError(errno.ENOSYS, "Function not implemented") |
101 |
-- |
102 |
2.7.4 |