Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2732046

Browse files
committed
Add eventfd_read/write, fix value type
The ``eventfd_read`` and ``eventfd_write`` functions are convenient wrappers that perform proper read/write and conversion from/to uint64_t. Signed-off-by: Christian Heimes <[email protected]>
1 parent 019a9fb commit 2732046

4 files changed

Lines changed: 236 additions & 56 deletions

File tree

Doc/library/os.rst

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,52 +3278,67 @@ features:
32783278

32793279
.. function:: eventfd(initval[, flags=os.EFD_CLOEXEC])
32803280

3281-
Create and return a file descriptor for event notification. An eventfd can
3282-
be used to implement an event wait/notify mechanisum. See man page
3283-
:manpage:`eventfd(2)` for more information. By default, the new file
3284-
descriptor is :ref:`non-inheritable <fd_inheritance>`.
3281+
Create and return an event file descriptor. The file descriptors supports
3282+
raw :func:`read` and :func:`write` with a buffer size of 8,
3283+
:func:`~select.select`, :func:`~select.poll` and similar. By default, the
3284+
new file descriptor is :ref:`non-inheritable <fd_inheritance>`.
32853285

3286-
The *initval* is limited to an unsigned 32-bit integer. The Kernel object
3287-
holds an unsigned 64-bit integer with a maximum value of 2**64 - 2. The
3288-
input value to :func:`~os.write` and output value of :func:~os.read` are
3289-
are unsigned 64-bit integers (8 bytes) in native byte order. Eventfds
3290-
support waiting for I/O completion with :mod:`select` module.
3286+
If :const:`EFD_SEMAPHORE` is specified and the event counter is non-zero,
3287+
:func:`eventfd_read` returns 1 and decrements the counter by one.
32913288

3292-
Example::
3289+
If :const:`EFD_SEMAPHORE` is not specified and the event counter is
3290+
non-zero, :func:`eventfd_read` returns the current event counter value and
3291+
resets the counter to zero.
3292+
3293+
If the event counter is zero, :func:`eventfd_read` blocks.
32933294

3294-
import os
3295-
import struct
3295+
:func:`eventfd_write` increments the event counter.
32963296

3297-
format = "@Q" # native uint64_t
3298-
size = struct.calcsize(format) # 8 bytes
3297+
*initval* is the initial value of the event counter. It must be an
3298+
unsigned integer between 0 and 2\ :sup:`64`\ -\ 2.
32993299

3300-
# semaphore with start value '1'
3301-
fd = os.eventfd(1, os.EFD_SEMAPHORE | os.EFC_CLOEXEC)
3302-
try:
3303-
# acquire semaphore
3304-
v = os.read(fd, size)
3305-
try:
3306-
assert v == struct.pack(format, 1)
3307-
do_work()
3308-
finally:
3309-
# release semaphore
3310-
os.write(fd, v)
3311-
finally:
3312-
os.close(fd)
3300+
*flags* can be constructed from :const:`EFD_CLOEXEC`,
3301+
:const:`EFD_NONBLOCK`, and :const:`EFD_SEMAPHORE`.
33133302

3314-
.. availability:: Linux 2.27 or newer with glibc 2.8 or newer.
3303+
.. availability:: Linux 2.6.27 or newer with glibc 2.8 or newer.
33153304

33163305
.. versionadded:: 3.10
33173306

3307+
.. function:: eventfd_read(fd)
3308+
3309+
Read value from an :func:`eventfd` file descriptor and return
3310+
an unsigned integer between 0 and 2\ :sup:`64`\ -\ 2. The function does
3311+
not verify that *fd* is an :func:`eventfd`.
3312+
3313+
.. versionadded:: 3.10
3314+
3315+
.. function:: eventfd_write(fd, value)
3316+
3317+
Add value to an :func:`eventfd` file descriptor. *value* must be
3318+
an unsigned integer between 0 and 2\ :sup:`64`\ -\ 2. The function does
3319+
not verify that *fd* is an :func:`eventfd`.
3320+
3321+
.. versionadded:: 3.10
33183322

33193323
.. data:: EFD_CLOEXEC
3320-
EFD_NONBLOCK
3321-
EFD_SEMAPHORE
33223324

3323-
These flags can be passed to :func:`eventfd`.
3325+
Set close-on-exec flag for new :func:`eventfd` file descriptor.
3326+
3327+
.. versionadded:: 3.10
3328+
3329+
.. data:: EFD_NONBLOCK
3330+
3331+
Set :const:`O_NONBLOCK` status flag for new :func:`eventfd` file
3332+
descriptor.
3333+
3334+
.. versionadded:: 3.10
3335+
3336+
.. data:: EFD_SEMAPHORE
3337+
3338+
Provide semaphore-like semantics for reads from a :func:`eventfd` file
3339+
descriptor. On read the internal counter is decremented by one.
33243340

3325-
.. availability:: Linux 2.27 or newer with glibc 2.8 or newer. The
3326-
``EFD_SEMAPHORE`` flag is available since Linux 2.30.
3341+
.. availability:: Linux 2.6.30 or newer
33273342

33283343
.. versionadded:: 3.10
33293344

Lib/test/test_os.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3530,45 +3530,64 @@ def test_memfd_create(self):
35303530

35313531

35323532
@unittest.skipUnless(hasattr(os, 'eventfd'), 'requires os.eventfd')
3533-
@support.requires_linux_version(2, 30)
3533+
@support.requires_linux_version(2, 6, 30)
35343534
class EventfdTests(unittest.TestCase):
3535-
fmt = "@Q" # native uint64_t
3536-
size = 8 # read/write 8 bytes
3537-
3538-
def pack(self, value):
3539-
return struct.pack(self.fmt, value)
3540-
35413535
def test_eventfd_initval(self):
3536+
def pack(value):
3537+
"""Pack as native uint64_t
3538+
"""
3539+
return struct.pack("@Q", value)
3540+
size = 8 # read/write 8 bytes
35423541
initval = 42
35433542
fd = os.eventfd(initval)
35443543
self.assertNotEqual(fd, -1)
35453544
self.addCleanup(os.close, fd)
35463545
self.assertFalse(os.get_inheritable(fd))
35473546

3548-
res = os.read(fd, self.size)
3549-
self.assertEqual(res, self.pack(initval))
3547+
# test with raw read/write
3548+
res = os.read(fd, size)
3549+
self.assertEqual(res, pack(initval))
3550+
3551+
os.write(fd, pack(23))
3552+
res = os.read(fd, size)
3553+
self.assertEqual(res, pack(23))
3554+
3555+
os.write(fd, pack(40))
3556+
os.write(fd, pack(2))
3557+
res = os.read(fd, size)
3558+
self.assertEqual(res, pack(42))
35503559

3551-
os.write(fd, struct.pack(self.fmt, 23))
3552-
res = os.read(fd, self.size)
3553-
self.assertEqual(res, self.pack(23))
3560+
# test with eventfd_read/eventfd_write
3561+
os.eventfd_write(fd, 20)
3562+
os.eventfd_write(fd, 3)
3563+
res = os.eventfd_read(fd)
3564+
self.assertEqual(res, 23)
35543565

35553566
def test_eventfd_semaphore(self):
35563567
initval = 2
3557-
one = self.pack(1)
3558-
35593568
flags = os.EFD_CLOEXEC | os.EFD_SEMAPHORE | os.EFD_NONBLOCK
35603569
fd = os.eventfd(initval, flags)
35613570
self.assertNotEqual(fd, -1)
35623571
self.addCleanup(os.close, fd)
35633572

35643573
# semaphore starts has initval 2, two reads return '1'
3565-
res = os.read(fd, self.size)
3566-
self.assertEqual(res, one)
3567-
res = os.read(fd, self.size)
3568-
self.assertEqual(res, one)
3574+
res = os.eventfd_read(fd)
3575+
self.assertEqual(res, 1)
3576+
res = os.eventfd_read(fd)
3577+
self.assertEqual(res, 1)
35693578
# third read would block
35703579
with self.assertRaises(BlockingIOError):
3571-
os.read(fd, self.size)
3580+
os.eventfd_read(fd)
3581+
with self.assertRaises(BlockingIOError):
3582+
os.read(fd, 8)
3583+
3584+
# increase semaphore counter, read one
3585+
os.eventfd_write(fd, 1)
3586+
res = os.eventfd_read(fd)
3587+
self.assertEqual(res, 1)
3588+
# next read would block, too
3589+
with self.assertRaises(BlockingIOError):
3590+
os.eventfd_read(fd)
35723591

35733592

35743593
class OSErrorTests(unittest.TestCase):

Modules/clinic/posixmodule.c.h

Lines changed: 91 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12871,13 +12871,18 @@ os.eventfd
1287112871
initval: unsigned_int
1287212872
flags: int(c_default="EFD_CLOEXEC") = EFD_CLOEXEC
1287312873
12874+
Creates and returns an event notification file descriptor.
1287412875
[clinic start generated code]*/
1287512876

1287612877
static PyObject *
1287712878
os_eventfd_impl(PyObject *module, unsigned int initval, int flags)
12878-
/*[clinic end generated code: output=ce9c9bbd1446f2de input=93c05fbffd6a8d33]*/
12879+
/*[clinic end generated code: output=ce9c9bbd1446f2de input=66203e3c50c4028b]*/
1287912880
{
1288012881
int fd;
12882+
if (initval > (PY_ULLONG_MAX - 1)) {
12883+
PyErr_SetString(PyExc_OverflowError, "initval too large");
12884+
return NULL;
12885+
}
1288112886
Py_BEGIN_ALLOW_THREADS
1288212887
fd = eventfd(initval, flags);
1288312888
Py_END_ALLOW_THREADS
@@ -12886,7 +12891,57 @@ os_eventfd_impl(PyObject *module, unsigned int initval, int flags)
1288612891
}
1288712892
return PyLong_FromLong(fd);
1288812893
}
12889-
#endif
12894+
12895+
/*[clinic input]
12896+
os.eventfd_read
12897+
12898+
fd: fildes
12899+
12900+
Read eventfd value
12901+
[clinic start generated code]*/
12902+
12903+
static PyObject *
12904+
os_eventfd_read_impl(PyObject *module, int fd)
12905+
/*[clinic end generated code: output=8f2c7b59a3521fd1 input=110f8b57fa596afe]*/
12906+
{
12907+
eventfd_t value;
12908+
int result;
12909+
Py_BEGIN_ALLOW_THREADS
12910+
result = eventfd_read(fd, &value);
12911+
Py_END_ALLOW_THREADS
12912+
if (result == -1) {
12913+
return PyErr_SetFromErrno(PyExc_OSError);
12914+
}
12915+
return PyLong_FromUnsignedLongLong(value);
12916+
}
12917+
12918+
/*[clinic input]
12919+
os.eventfd_write
12920+
12921+
fd: fildes
12922+
value: unsigned_long_long
12923+
12924+
Write eventfd value
12925+
[clinic start generated code]*/
12926+
12927+
static PyObject *
12928+
os_eventfd_write_impl(PyObject *module, int fd, unsigned long long value)
12929+
/*[clinic end generated code: output=bebd9040bbf987f5 input=82da3dd0d6e62f28]*/
12930+
{
12931+
int result;
12932+
if (value > (PY_ULLONG_MAX - 1)) {
12933+
PyErr_SetString(PyExc_OverflowError, "value too large");
12934+
return NULL;
12935+
}
12936+
Py_BEGIN_ALLOW_THREADS
12937+
result = eventfd_write(fd, value);
12938+
Py_END_ALLOW_THREADS
12939+
if (result == -1) {
12940+
return PyErr_SetFromErrno(PyExc_OSError);
12941+
}
12942+
Py_RETURN_NONE;
12943+
}
12944+
#endif /* HAVE_EVENTFD */
1289012945

1289112946
/* Terminal size querying */
1289212947

@@ -14649,6 +14704,8 @@ static PyMethodDef posix_methods[] = {
1464914704
OS_GETRANDOM_METHODDEF
1465014705
OS_MEMFD_CREATE_METHODDEF
1465114706
OS_EVENTFD_METHODDEF
14707+
OS_EVENTFD_READ_METHODDEF
14708+
OS_EVENTFD_WRITE_METHODDEF
1465214709
OS__ADD_DLL_DIRECTORY_METHODDEF
1465314710
OS__REMOVE_DLL_DIRECTORY_METHODDEF
1465414711
OS_WAITSTATUS_TO_EXITCODE_METHODDEF

0 commit comments

Comments
 (0)