diff options
| author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-07-10 15:02:26 (GMT) |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-10 15:02:26 (GMT) |
| commit | 0113c56a203c3569013c6d08486ccce2e9b7016b (patch) | |
| tree | caf51fd30596b6bb93fb4c136f36b23ff6a212f8 | |
| parent | 0504f45b795d508014031ff0884160ddd86e44a1 (diff) | |
| download | cpython-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.py | 37 |
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 |
