summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Doc/library/os.rst96
-rw-r--r--Doc/whatsnew/3.10.rst4
-rw-r--r--Lib/test/test_os.py86
-rw-r--r--Misc/NEWS.d/next/Library/2020-06-17-12-24-26.bpo-41001.5mi7b0.rst2
-rw-r--r--Modules/clinic/posixmodule.c.h142
-rw-r--r--Modules/posixmodule.c91
-rwxr-xr-xconfigure33
-rw-r--r--configure.ac14
-rw-r--r--pyconfig.h.in6
9 files changed, 471 insertions, 3 deletions
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index 3ffcfa0..6c7ae0c 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -3276,6 +3276,102 @@ features:
.. versionadded:: 3.8
+.. function:: eventfd(initval[, flags=os.EFD_CLOEXEC])
+
+ Create and return an event file descriptor. The file descriptors supports
+ raw :func:`read` and :func:`write` with a buffer size of 8,
+ :func:`~select.select`, :func:`~select.poll` and similar. See man page
+ :manpage:`eventfd(2)` for more information. By default, the
+ new file descriptor is :ref:`non-inheritable <fd_inheritance>`.
+
+ *initval* is the initial value of the event counter. The initial value
+ must be an 32 bit unsigned integer. Please note that the initial value is
+ limited to a 32 bit unsigned int although the event counter is an unsigned
+ 64 bit integer with a maximum value of 2\ :sup:`64`\ -\ 2.
+
+ *flags* can be constructed from :const:`EFD_CLOEXEC`,
+ :const:`EFD_NONBLOCK`, and :const:`EFD_SEMAPHORE`.
+
+ If :const:`EFD_SEMAPHORE` is specified and the event counter is non-zero,
+ :func:`eventfd_read` returns 1 and decrements the counter by one.
+
+ If :const:`EFD_SEMAPHORE` is not specified and the event counter is
+ non-zero, :func:`eventfd_read` returns the current event counter value and
+ resets the counter to zero.
+
+ If the event counter is zero and :const:`EFD_NONBLOCK` is not
+ specified, :func:`eventfd_read` blocks.
+
+ :func:`eventfd_write` increments the event counter. Write blocks if the
+ write operation would increment the counter to a value larger than
+ 2\ :sup:`64`\ -\ 2.
+
+ Example::
+
+ import os
+
+ # semaphore with start value '1'
+ fd = os.eventfd(1, os.EFD_SEMAPHORE | os.EFC_CLOEXEC)
+ try:
+ # acquire semaphore
+ v = os.eventfd_read(fd)
+ try:
+ do_work()
+ finally:
+ # release semaphore
+ os.eventfd_write(fd, v)
+ finally:
+ os.close(fd)
+
+ .. availability:: Linux 2.6.27 or newer with glibc 2.8 or newer.
+
+ .. versionadded:: 3.10
+
+.. function:: eventfd_read(fd)
+
+ Read value from an :func:`eventfd` file descriptor and return a 64 bit
+ unsigned int. The function does not verify that *fd* is an :func:`eventfd`.
+
+ .. availability:: See :func:`eventfd`
+
+ .. versionadded:: 3.10
+
+.. function:: eventfd_write(fd, value)
+
+ Add value to an :func:`eventfd` file descriptor. *value* must be a 64 bit
+ unsigned int. The function does not verify that *fd* is an :func:`eventfd`.
+
+ .. availability:: See :func:`eventfd`
+
+ .. versionadded:: 3.10
+
+.. data:: EFD_CLOEXEC
+
+ Set close-on-exec flag for new :func:`eventfd` file descriptor.
+
+ .. availability:: See :func:`eventfd`
+
+ .. versionadded:: 3.10
+
+.. data:: EFD_NONBLOCK
+
+ Set :const:`O_NONBLOCK` status flag for new :func:`eventfd` file
+ descriptor.
+
+ .. availability:: See :func:`eventfd`
+
+ .. versionadded:: 3.10
+
+.. data:: EFD_SEMAPHORE
+
+ Provide semaphore-like semantics for reads from a :func:`eventfd` file
+ descriptor. On read the internal counter is decremented by one.
+
+ .. availability:: Linux 2.6.30 or newer with glibc 2.8 or newer.
+
+ .. versionadded:: 3.10
+
+
Linux extended attributes
~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 4d77200..c1ce5f3 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -229,6 +229,10 @@ os
Added :func:`os.cpu_count()` support for VxWorks RTOS.
(Contributed by Peixing Xin in :issue:`41440`.)
+Added a new function :func:`os.eventfd` and related helpers to wrap the
+``eventfd2`` syscall on Linux.
+(Contributed by Christian Heimes in :issue:`41001`.)
+
py_compile
----------
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):
diff --git a/Misc/NEWS.d/next/Library/2020-06-17-12-24-26.bpo-41001.5mi7b0.rst b/Misc/NEWS.d/next/Library/2020-06-17-12-24-26.bpo-41001.5mi7b0.rst
new file mode 100644
index 0000000..34ecfbf
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-06-17-12-24-26.bpo-41001.5mi7b0.rst
@@ -0,0 +1,2 @@
+Add func:`os.eventfd` to provide a low level interface for Linux's event
+notification file descriptor.
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index df680d5..f5826e3 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -7620,6 +7620,134 @@ exit:
#endif /* defined(HAVE_MEMFD_CREATE) */
+#if defined(HAVE_EVENTFD)
+
+PyDoc_STRVAR(os_eventfd__doc__,
+"eventfd($module, /, initval, flags=EFD_CLOEXEC)\n"
+"--\n"
+"\n"
+"Creates and returns an event notification file descriptor.");
+
+#define OS_EVENTFD_METHODDEF \
+ {"eventfd", (PyCFunction)(void(*)(void))os_eventfd, METH_FASTCALL|METH_KEYWORDS, os_eventfd__doc__},
+
+static PyObject *
+os_eventfd_impl(PyObject *module, unsigned int initval, int flags);
+
+static PyObject *
+os_eventfd(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = {"initval", "flags", NULL};
+ static _PyArg_Parser _parser = {NULL, _keywords, "eventfd", 0};
+ PyObject *argsbuf[2];
+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
+ unsigned int initval;
+ int flags = EFD_CLOEXEC;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (!_PyLong_UnsignedInt_Converter(args[0], &initval)) {
+ goto exit;
+ }
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ flags = _PyLong_AsInt(args[1]);
+ if (flags == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+skip_optional_pos:
+ return_value = os_eventfd_impl(module, initval, flags);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(HAVE_EVENTFD) */
+
+#if defined(HAVE_EVENTFD)
+
+PyDoc_STRVAR(os_eventfd_read__doc__,
+"eventfd_read($module, /, fd)\n"
+"--\n"
+"\n"
+"Read eventfd value");
+
+#define OS_EVENTFD_READ_METHODDEF \
+ {"eventfd_read", (PyCFunction)(void(*)(void))os_eventfd_read, METH_FASTCALL|METH_KEYWORDS, os_eventfd_read__doc__},
+
+static PyObject *
+os_eventfd_read_impl(PyObject *module, int fd);
+
+static PyObject *
+os_eventfd_read(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = {"fd", NULL};
+ static _PyArg_Parser _parser = {NULL, _keywords, "eventfd_read", 0};
+ PyObject *argsbuf[1];
+ int fd;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (!_PyLong_FileDescriptor_Converter(args[0], &fd)) {
+ goto exit;
+ }
+ return_value = os_eventfd_read_impl(module, fd);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(HAVE_EVENTFD) */
+
+#if defined(HAVE_EVENTFD)
+
+PyDoc_STRVAR(os_eventfd_write__doc__,
+"eventfd_write($module, /, fd, value)\n"
+"--\n"
+"\n"
+"Write eventfd value.");
+
+#define OS_EVENTFD_WRITE_METHODDEF \
+ {"eventfd_write", (PyCFunction)(void(*)(void))os_eventfd_write, METH_FASTCALL|METH_KEYWORDS, os_eventfd_write__doc__},
+
+static PyObject *
+os_eventfd_write_impl(PyObject *module, int fd, unsigned long long value);
+
+static PyObject *
+os_eventfd_write(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = {"fd", "value", NULL};
+ static _PyArg_Parser _parser = {NULL, _keywords, "eventfd_write", 0};
+ PyObject *argsbuf[2];
+ int fd;
+ unsigned long long value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (!_PyLong_FileDescriptor_Converter(args[0], &fd)) {
+ goto exit;
+ }
+ if (!_PyLong_UnsignedLongLong_Converter(args[1], &value)) {
+ goto exit;
+ }
+ return_value = os_eventfd_write_impl(module, fd, value);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(HAVE_EVENTFD) */
+
#if (defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL))
PyDoc_STRVAR(os_get_terminal_size__doc__,
@@ -8884,6 +9012,18 @@ exit:
#define OS_MEMFD_CREATE_METHODDEF
#endif /* !defined(OS_MEMFD_CREATE_METHODDEF) */
+#ifndef OS_EVENTFD_METHODDEF
+ #define OS_EVENTFD_METHODDEF
+#endif /* !defined(OS_EVENTFD_METHODDEF) */
+
+#ifndef OS_EVENTFD_READ_METHODDEF
+ #define OS_EVENTFD_READ_METHODDEF
+#endif /* !defined(OS_EVENTFD_READ_METHODDEF) */
+
+#ifndef OS_EVENTFD_WRITE_METHODDEF
+ #define OS_EVENTFD_WRITE_METHODDEF
+#endif /* !defined(OS_EVENTFD_WRITE_METHODDEF) */
+
#ifndef OS_GET_TERMINAL_SIZE_METHODDEF
#define OS_GET_TERMINAL_SIZE_METHODDEF
#endif /* !defined(OS_GET_TERMINAL_SIZE_METHODDEF) */
@@ -8919,4 +9059,4 @@ exit:
#ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF
#define OS_WAITSTATUS_TO_EXITCODE_METHODDEF
#endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */
-/*[clinic end generated code: output=936f33448cd66ccb input=a9049054013a1b77]*/
+/*[clinic end generated code: output=49b7ed768242ef7c input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 6b51d8a..0764453 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -518,6 +518,11 @@ extern char *ctermid_r(char *);
# include <linux/memfd.h>
#endif
+/* eventfd() */
+#ifdef HAVE_SYS_EVENTFD_H
+# include <sys/eventfd.h>
+#endif
+
#ifdef _Py_MEMORY_SANITIZER
# include <sanitizer/msan_interface.h>
#endif
@@ -12859,6 +12864,79 @@ os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags)
}
#endif
+#ifdef HAVE_EVENTFD
+/*[clinic input]
+os.eventfd
+
+ initval: unsigned_int
+ flags: int(c_default="EFD_CLOEXEC") = EFD_CLOEXEC
+
+Creates and returns an event notification file descriptor.
+[clinic start generated code]*/
+
+static PyObject *
+os_eventfd_impl(PyObject *module, unsigned int initval, int flags)
+/*[clinic end generated code: output=ce9c9bbd1446f2de input=66203e3c50c4028b]*/
+
+{
+ /* initval is limited to uint32_t, internal counter is uint64_t */
+ int fd;
+ Py_BEGIN_ALLOW_THREADS
+ fd = eventfd(initval, flags);
+ Py_END_ALLOW_THREADS
+ if (fd == -1) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ return PyLong_FromLong(fd);
+}
+
+/*[clinic input]
+os.eventfd_read
+
+ fd: fildes
+
+Read eventfd value
+[clinic start generated code]*/
+
+static PyObject *
+os_eventfd_read_impl(PyObject *module, int fd)
+/*[clinic end generated code: output=8f2c7b59a3521fd1 input=110f8b57fa596afe]*/
+{
+ eventfd_t value;
+ int result;
+ Py_BEGIN_ALLOW_THREADS
+ result = eventfd_read(fd, &value);
+ Py_END_ALLOW_THREADS
+ if (result == -1) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ return PyLong_FromUnsignedLongLong(value);
+}
+
+/*[clinic input]
+os.eventfd_write
+
+ fd: fildes
+ value: unsigned_long_long
+
+Write eventfd value.
+[clinic start generated code]*/
+
+static PyObject *
+os_eventfd_write_impl(PyObject *module, int fd, unsigned long long value)
+/*[clinic end generated code: output=bebd9040bbf987f5 input=156de8555be5a949]*/
+{
+ int result;
+ Py_BEGIN_ALLOW_THREADS
+ result = eventfd_write(fd, value);
+ Py_END_ALLOW_THREADS
+ if (result == -1) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ Py_RETURN_NONE;
+}
+#endif /* HAVE_EVENTFD */
+
/* Terminal size querying */
PyDoc_STRVAR(TerminalSize_docstring,
@@ -14619,6 +14697,9 @@ static PyMethodDef posix_methods[] = {
OS_FSPATH_METHODDEF
OS_GETRANDOM_METHODDEF
OS_MEMFD_CREATE_METHODDEF
+ OS_EVENTFD_METHODDEF
+ OS_EVENTFD_READ_METHODDEF
+ OS_EVENTFD_WRITE_METHODDEF
OS__ADD_DLL_DIRECTORY_METHODDEF
OS__REMOVE_DLL_DIRECTORY_METHODDEF
OS_WAITSTATUS_TO_EXITCODE_METHODDEF
@@ -15127,6 +15208,12 @@ all_ins(PyObject *m)
#ifdef MFD_HUGE_16GB
if (PyModule_AddIntMacro(m, MFD_HUGE_16GB)) return -1;
#endif
+#endif /* HAVE_MEMFD_CREATE */
+
+#ifdef HAVE_EVENTFD
+ if (PyModule_AddIntMacro(m, EFD_CLOEXEC)) return -1;
+ if (PyModule_AddIntMacro(m, EFD_NONBLOCK)) return -1;
+ if (PyModule_AddIntMacro(m, EFD_SEMAPHORE)) return -1;
#endif
#if defined(__APPLE__)
@@ -15220,6 +15307,10 @@ static const struct have_function {
int (*probe)(void);
} have_functions[] = {
+#ifdef HAVE_EVENTFD
+ {"HAVE_EVENTFD", NULL},
+#endif
+
#ifdef HAVE_FACCESSAT
{ "HAVE_FACCESSAT", probe_faccessat },
#endif
diff --git a/configure b/configure
index 68d692d..b8b056e 100755
--- a/configure
+++ b/configure
@@ -8032,7 +8032,8 @@ sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
-sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h sys/mman.h
+sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h \
+sys/mman.h sys/eventfd.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -12098,6 +12099,36 @@ $as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for eventfd" >&5
+$as_echo_n "checking for eventfd... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_SYS_EVENTFD_H
+#include <sys/eventfd.h>
+#endif
+
+int
+main ()
+{
+int x = eventfd(0, EFD_CLOEXEC)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_EVENTFD 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
# On some systems (eg. FreeBSD 5), we would find a definition of the
# functions ctermid_r, setgroups in the library, but no prototype
# (e.g. because we use _XOPEN_SOURCE). See whether we can take their
diff --git a/configure.ac b/configure.ac
index 1edafc3..e499cb4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2210,7 +2210,8 @@ sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
-sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h sys/mman.h)
+sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h \
+sys/mman.h sys/eventfd.h)
AC_HEADER_DIRENT
AC_HEADER_MAJOR
@@ -3803,6 +3804,17 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
[AC_MSG_RESULT(no)
])
+AC_MSG_CHECKING(for eventfd)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#ifdef HAVE_SYS_EVENTFD_H
+#include <sys/eventfd.h>
+#endif
+]], [[int x = eventfd(0, EFD_CLOEXEC)]])],
+ [AC_DEFINE(HAVE_EVENTFD, 1, Define if you have the 'eventfd' function.)
+ AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(no)
+])
+
# On some systems (eg. FreeBSD 5), we would find a definition of the
# functions ctermid_r, setgroups in the library, but no prototype
# (e.g. because we use _XOPEN_SOURCE). See whether we can take their
diff --git a/pyconfig.h.in b/pyconfig.h.in
index d71ad3f..8a5e945 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -308,6 +308,9 @@
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
+/* Define if you have the 'eventfd' function. */
+#undef HAVE_EVENTFD
+
/* Define to 1 if you have the `execv' function. */
#undef HAVE_EXECV
@@ -1119,6 +1122,9 @@
/* Define to 1 if you have the <sys/epoll.h> header file. */
#undef HAVE_SYS_EPOLL_H
+/* Define to 1 if you have the <sys/eventfd.h> header file. */
+#undef HAVE_SYS_EVENTFD_H
+
/* Define to 1 if you have the <sys/event.h> header file. */
#undef HAVE_SYS_EVENT_H