diff options
author | Helmut Grohne <helmut@subdivi.de> | 2024-02-16 15:20:00 +0100 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2024-02-16 15:20:00 +0100 |
commit | 12f32219ff6a7e0eef6b914589d47066480404de (patch) | |
tree | 790ae738e5a0b2117143d5cec508ec4b37ea2a7d /linuxnamespaces | |
parent | d8ecc510108426fba8f9a53e0d5fa54d5942e75f (diff) | |
download | python-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.py | 31 |
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: |