summaryrefslogtreecommitdiff
path: root/linuxnamespaces
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2024-02-16 15:20:00 +0100
committerHelmut Grohne <helmut@subdivi.de>2024-02-16 15:20:00 +0100
commit12f32219ff6a7e0eef6b914589d47066480404de (patch)
tree790ae738e5a0b2117143d5cec508ec4b37ea2a7d /linuxnamespaces
parentd8ecc510108426fba8f9a53e0d5fa54d5942e75f (diff)
downloadpython-linuxnamespaces-12f32219ff6a7e0eef6b914589d47066480404de.tar.gz
add an async read method to EventFD
Adding an async write does not work for values larger than 1, because the fd becomes writable once a value of 1 can be written, but a larger value might still cause EAGAIN putting us into a busy loop. Hitting the limit with writing ones is implausible, so async code can just use the synchronous write method.
Diffstat (limited to 'linuxnamespaces')
-rw-r--r--linuxnamespaces/syscalls.py31
1 files changed, 31 insertions, 0 deletions
diff --git a/linuxnamespaces/syscalls.py b/linuxnamespaces/syscalls.py
index 338e602..06b5025 100644
--- a/linuxnamespaces/syscalls.py
+++ b/linuxnamespaces/syscalls.py
@@ -5,9 +5,11 @@
for Linux namespaces including the new mount API.
"""
+import asyncio
import ctypes
import dataclasses
import enum
+import errno
import os
import typing
@@ -419,6 +421,35 @@ class EventFD:
call_libc("eventfd_read", self.fd, ctypes.byref(cvalue))
return cvalue.value
+ def __handle_readable(self, fd: int, fut: asyncio.Future[int]) -> None:
+ """Internal helper of aread."""
+ try:
+ if fd != self.fd:
+ raise RuntimeError("EventFD file descriptor changed")
+ try:
+ result = self.read()
+ except OSError as err:
+ if err.errno == errno.EAGAIN:
+ return
+ raise
+ except Exception as exc:
+ fut.get_loop().remove_reader(fd)
+ fut.set_exception(exc)
+ else:
+ fut.get_loop().remove_reader(fd)
+ fut.set_result(result)
+
+ def aread(self) -> typing.Awaitable[int]:
+ """Decrease the value of the eventfd asynchronously. It mst have been
+ constructed using EventFDFlags.NONBLOCK.
+ """
+ if self.fd < 0:
+ raise ValueError("attempt to read from closed eventfd")
+ loop = asyncio.get_running_loop()
+ fut: asyncio.Future[int] = loop.create_future()
+ loop.add_reader(self.fd, self.__handle_readable, self.fd, fut)
+ return fut
+
def write(self, value: int = 1) -> None:
"""Add the given value to the eventfd using eventfd_write."""
if self.fd < 0: