summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2020-11-13 18:48:52 (GMT)
committerGitHub <noreply@github.com>2020-11-13 18:48:52 (GMT)
commitcd9fed6afba6f3ad2e7ef723501c739551a95fa8 (patch)
treecf6114ff87b83e0a3fabdbbf59d06eb10e55b6db /Lib
parentbbeb2d266d6fc1ca9778726d0397d9d6f7a946e3 (diff)
downloadcpython-cd9fed6afba6f3ad2e7ef723501c739551a95fa8.zip
cpython-cd9fed6afba6f3ad2e7ef723501c739551a95fa8.tar.gz
cpython-cd9fed6afba6f3ad2e7ef723501c739551a95fa8.tar.bz2
bpo-41001: Add os.eventfd() (#20930)
Co-authored-by: Kyle Stanley <aeros167@gmail.com>
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_os.py86
1 files changed, 86 insertions, 0 deletions
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 5126c84..501b4a9 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -15,10 +15,12 @@ import locale
import mmap
import os
import pickle
+import select
import shutil
import signal
import socket
import stat
+import struct
import subprocess
import sys
import sysconfig
@@ -59,6 +61,7 @@ try:
except ImportError:
INT_MAX = PY_SSIZE_T_MAX = sys.maxsize
+
from test.support.script_helper import assert_python_ok
from test.support import unix_shell
from test.support.os_helper import FakePath
@@ -3528,6 +3531,89 @@ class MemfdCreateTests(unittest.TestCase):
self.assertFalse(os.get_inheritable(fd2))
+@unittest.skipUnless(hasattr(os, 'eventfd'), 'requires os.eventfd')
+@support.requires_linux_version(2, 6, 30)
+class EventfdTests(unittest.TestCase):
+ def test_eventfd_initval(self):
+ def pack(value):
+ """Pack as native uint64_t
+ """
+ return struct.pack("@Q", value)
+ size = 8 # read/write 8 bytes
+ initval = 42
+ fd = os.eventfd(initval)
+ self.assertNotEqual(fd, -1)
+ self.addCleanup(os.close, fd)
+ self.assertFalse(os.get_inheritable(fd))
+
+ # test with raw read/write
+ res = os.read(fd, size)
+ self.assertEqual(res, pack(initval))
+
+ os.write(fd, pack(23))
+ res = os.read(fd, size)
+ self.assertEqual(res, pack(23))
+
+ os.write(fd, pack(40))
+ os.write(fd, pack(2))
+ res = os.read(fd, size)
+ self.assertEqual(res, pack(42))
+
+ # test with eventfd_read/eventfd_write
+ os.eventfd_write(fd, 20)
+ os.eventfd_write(fd, 3)
+ res = os.eventfd_read(fd)
+ self.assertEqual(res, 23)
+
+ def test_eventfd_semaphore(self):
+ initval = 2
+ flags = os.EFD_CLOEXEC | os.EFD_SEMAPHORE | os.EFD_NONBLOCK
+ fd = os.eventfd(initval, flags)
+ self.assertNotEqual(fd, -1)
+ self.addCleanup(os.close, fd)
+
+ # semaphore starts has initval 2, two reads return '1'
+ res = os.eventfd_read(fd)
+ self.assertEqual(res, 1)
+ res = os.eventfd_read(fd)
+ self.assertEqual(res, 1)
+ # third read would block
+ with self.assertRaises(BlockingIOError):
+ os.eventfd_read(fd)
+ with self.assertRaises(BlockingIOError):
+ os.read(fd, 8)
+
+ # increase semaphore counter, read one
+ os.eventfd_write(fd, 1)
+ res = os.eventfd_read(fd)
+ self.assertEqual(res, 1)
+ # next read would block, too
+ with self.assertRaises(BlockingIOError):
+ os.eventfd_read(fd)
+
+ def test_eventfd_select(self):
+ flags = os.EFD_CLOEXEC | os.EFD_NONBLOCK
+ fd = os.eventfd(0, flags)
+ self.assertNotEqual(fd, -1)
+ self.addCleanup(os.close, fd)
+
+ # counter is zero, only writeable
+ rfd, wfd, xfd = select.select([fd], [fd], [fd], 0)
+ self.assertEqual((rfd, wfd, xfd), ([], [fd], []))
+
+ # counter is non-zero, read and writeable
+ os.eventfd_write(fd, 23)
+ rfd, wfd, xfd = select.select([fd], [fd], [fd], 0)
+ self.assertEqual((rfd, wfd, xfd), ([fd], [fd], []))
+ self.assertEqual(os.eventfd_read(fd), 23)
+
+ # counter at max, only readable
+ os.eventfd_write(fd, (2**64) - 2)
+ rfd, wfd, xfd = select.select([fd], [fd], [fd], 0)
+ self.assertEqual((rfd, wfd, xfd), ([fd], [], []))
+ os.eventfd_read(fd)
+
+
class OSErrorTests(unittest.TestCase):
def setUp(self):
class Str(str):