summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2024-07-10 15:02:26 (GMT)
committerGitHub <noreply@github.com>2024-07-10 15:02:26 (GMT)
commit0113c56a203c3569013c6d08486ccce2e9b7016b (patch)
treecaf51fd30596b6bb93fb4c136f36b23ff6a212f8
parent0504f45b795d508014031ff0884160ddd86e44a1 (diff)
downloadcpython-0113c56a203c3569013c6d08486ccce2e9b7016b.zip
cpython-0113c56a203c3569013c6d08486ccce2e9b7016b.tar.gz
cpython-0113c56a203c3569013c6d08486ccce2e9b7016b.tar.bz2
[3.13] gh-107851: Fix spurious failures in fcntl eintr tests (GH-121556) (#121585)
On heavily loaded machines, the subprocess may finish its sleep before the parent process manages to synchronize with it via a failed lock. This leads to errors like: Exception: failed to sync child in 300.3 sec Use pipes instead to mutually synchronize between parent and child. (cherry picked from commit af9f6de6ea930b607f948f2c91a87fe4ca9d64db) Co-authored-by: Sam Gross <colesbury@gmail.com>
-rw-r--r--Lib/test/_test_eintr.py37
1 files changed, 20 insertions, 17 deletions
diff --git a/Lib/test/_test_eintr.py b/Lib/test/_test_eintr.py
index 15586f1..493932d 100644
--- a/Lib/test/_test_eintr.py
+++ b/Lib/test/_test_eintr.py
@@ -18,6 +18,7 @@ import signal
import socket
import subprocess
import sys
+import textwrap
import time
import unittest
@@ -492,29 +493,31 @@ class SelectEINTRTest(EINTRBaseTest):
self.check_elapsed_time(dt)
-class FNTLEINTRTest(EINTRBaseTest):
+class FCNTLEINTRTest(EINTRBaseTest):
def _lock(self, lock_func, lock_name):
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
- code = '\n'.join((
- "import fcntl, time",
- "with open('%s', 'wb') as f:" % os_helper.TESTFN,
- " fcntl.%s(f, fcntl.LOCK_EX)" % lock_name,
- " time.sleep(%s)" % self.sleep_time))
- start_time = time.monotonic()
- proc = self.subprocess(code)
+ rd1, wr1 = os.pipe()
+ rd2, wr2 = os.pipe()
+ for fd in (rd1, wr1, rd2, wr2):
+ self.addCleanup(os.close, fd)
+ code = textwrap.dedent(f"""
+ import fcntl, os, time
+ with open('{os_helper.TESTFN}', 'wb') as f:
+ fcntl.{lock_name}(f, fcntl.LOCK_EX)
+ os.write({wr1}, b"ok")
+ _ = os.read({rd2}, 2) # wait for parent process
+ time.sleep({self.sleep_time})
+ """)
+ proc = self.subprocess(code, pass_fds=[wr1, rd2])
with kill_on_error(proc):
with open(os_helper.TESTFN, 'wb') as f:
# synchronize the subprocess
+ ok = os.read(rd1, 2)
+ self.assertEqual(ok, b"ok")
+
+ # notify the child that the parent is ready
start_time = time.monotonic()
- for _ in support.sleeping_retry(support.LONG_TIMEOUT, error=False):
- try:
- lock_func(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
- lock_func(f, fcntl.LOCK_UN)
- except BlockingIOError:
- break
- else:
- dt = time.monotonic() - start_time
- raise Exception("failed to sync child in %.1f sec" % dt)
+ os.write(wr2, b"go")
# the child locked the file just a moment ago for 'sleep_time' seconds
# that means that the lock below will block for 'sleep_time' minus some