From 9729050e12100f0e01daf936a4766772ac82b85d Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 30 Nov 2022 12:49:49 +0100 Subject: [PATCH] ev::file: initial commit --- ev/+linux/file.ha | 41 +++++++++++++++++++++++++++++++++++++++++ ev/+linux/loop.ha | 10 +++++----- ev/+linux/types.ha | 15 +++++++++++++++ diff --git a/ev/+linux/file.ha b/ev/+linux/file.ha new file mode 100644 index 0000000000000000000000000000000000000000..1844a2af8c903ad594472f769b3d25ea3c2b5dda --- /dev/null +++ b/ev/+linux/file.ha @@ -0,0 +1,41 @@ +use errors; +use io; +use rt; + +export type file = struct { + fd: io::file, +}; + +// Registers a file descriptor with an event loop. +export fn register( + loop: *loop, + fd: io::file, +) (*file | errors::error) = { + const file = alloc(file { + fd = fd, + }); + + let ev = rt::epoll_event { + events = 0, + ... + }; + ev.data.ptr = file; + match (rt::epoll_ctl(loop.fd, rt::EPOLL_CTL_ADD, fd, &ev)) { + case void => + yield; + case let err: rt::errno => + return errors::errno(err); + }; + + return file; +}; + +// Unregisters a file object with an event loop and frees resources associated +// with it. Does not close the underlying file descriptor. +export fn unregister(loop: *loop, file: *file) void = { + // The only way that this could fail is in the event of a use-after-free + // or if the user fucks around and constructs a custom [[file]] which + // was never registered, so assert on error. + rt::epoll_ctl(loop.fd, rt::EPOLL_CTL_DEL, file.fd, null)!; + free(file); +}; diff --git a/ev/+linux/loop.ha b/ev/+linux/loop.ha index 0e52d8b5dbddbd764947cefa5cfb8fad2d1d43fd..f3492ffaa4d2a8d5c341d4fb3f4c8782bc6acbf2 100644 --- a/ev/+linux/loop.ha +++ b/ev/+linux/loop.ha @@ -5,7 +5,7 @@ use time; use types; export type loop = struct { - epoll: io::file, + fd: io::file, events: []rt::epoll_event, }; @@ -20,7 +20,7 @@ return errors::errno(err); }; return loop { - epoll = fd, + fd = fd, events = [], }; }; @@ -28,7 +28,7 @@ // Frees resources associated with an event loop. Must only be called once per // event loop object. export fn loop_finish(loop: *loop) void = { - io::close(loop.epoll)!; + io::close(loop.fd)!; }; // Returns an [[io::file]] for this event loop which can be polled on when @@ -36,7 +36,7 @@ // events are available for processing, for chaining together different event // loops. The exact semantics of this function are platform-specific, and it may // not be available for all implementations. export fn loop_file(loop: *loop) io::file = { - return loop.epoll; + return loop.fd; }; // Dispatches the event loop. A duration of -1 specifies an indefinite timeout, @@ -65,7 +65,7 @@ // TODO: Deal with signals const maxev = len(loop.events); assert(maxev <= types::INT_MAX: size, "ev::dispatch: too many events"); const events = rt::epoll_pwait( - loop.epoll, + loop.fd, &loop.events[0], maxev: int, millis, diff --git a/ev/+linux/types.ha b/ev/+linux/types.ha new file mode 100644 index 0000000000000000000000000000000000000000..c6713c6a7227677a13cd1423693724b31626b39e --- /dev/null +++ b/ev/+linux/types.ha @@ -0,0 +1,15 @@ +// Defines events which are available for monitoring. +export type event = enum u32 { + // Read operations are available + IN = 0x00000001, + // Write operations are available + OUT = 0x00000004, + // An error condition has been reported + ERR = 0x00000008, + // There is exceptional data available in the file descriptor; + // equivalent to [[unix::poll::event::POLLPRI]] + PRI = 0x00000002, + // A hang-up event has occured + HUP = 0x00000010, +}; +// TODO: Add less portable flags like EPOLLWAKEUP -- 2.48.1