Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions Lib/test/_test_eintr.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import socket
import subprocess
import sys
import textwrap
import time
import unittest

Expand Down Expand Up @@ -492,29 +493,31 @@ def test_devpoll(self):
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
Expand Down