From 6474ae30e5c9e1efa161a0d8c306a24ef1a55ed6 Mon Sep 17 00:00:00 2001 From: Drew DeVault <sir@cmpwn.com> Date: Wed, 30 Nov 2022 13:04:59 +0100 Subject: [PATCH] ev::read, ev::write: initial support --- ev/+linux/file.ha | 31 +++++++++++++++++++++++++++++++ ev/+linux/io.ha | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ev/+linux/types.ha | 16 ++-------------- diff --git a/ev/+linux/file.ha b/ev/+linux/file.ha index 1844a2af8c903ad594472f769b3d25ea3c2b5dda..a4ef4e35ff5dae63e340ba4ceb9678b8c790ec9f 100644 --- a/ev/+linux/file.ha +++ b/ev/+linux/file.ha @@ -2,8 +2,24 @@ use errors; use io; use rt; +export type op = enum { + NONE, + READV, + WRITEV, +}; + export type file = struct { fd: io::file, + ev: *loop, + // Pending operation on this file object + op: op, + callback: nullable *void, + + // Operation-specific data + vbuf: rt::iovec, + union { + vec: []rt::iovec, + }, }; // Registers a file descriptor with an event loop. @@ -13,6 +29,9 @@ fd: io::file, ) (*file | errors::error) = { const file = alloc(file { fd = fd, + ev = loop, + op = op::NONE, + ... }); let ev = rt::epoll_event { @@ -39,3 +58,15 @@ // was never registered, so assert on error. rt::epoll_ctl(loop.fd, rt::EPOLL_CTL_DEL, file.fd, null)!; free(file); }; + +// Modifies the epoll events for a given file. For internal use. +fn filemod(file: *file, events: u32) void = { + let ev = rt::epoll_event { + events = events, + ... + }; + ev.data.ptr = file; + // This can only fail under conditions associated with EPOLLEXCLUSIVE, + // which we do not support. + rt::epoll_ctl(file.ev.fd, rt::EPOLL_CTL_MOD, file.fd, &ev)!; +}; diff --git a/ev/+linux/io.ha b/ev/+linux/io.ha new file mode 100644 index 0000000000000000000000000000000000000000..3c72ee857910c88ac9259a4884899e761131e924 --- /dev/null +++ b/ev/+linux/io.ha @@ -0,0 +1,62 @@ +use io; +use rt; + +// A callback for a [[read]] or [[readv]] operation. +export type readcb = *fn(file: *file, result: (size | io::EOF | io::error)) void; + +// Schedules a read operation on a file object. +export fn read( + file: *file, + cb: *readcb, + buf: []u8, +) req = { + file.vbuf = io::mkvector(buf); + // XXX: Bit of a hack to avoid allocating a slice + const vec = (&file.vbuf: *[*]io::vector)[..1]; + return readv(file, cb, vec...); +}; + +// Schedules a vectored read operation on a file object. +export fn readv( + file: *file, + cb: *readcb, + vec: io::vector... +) req = { + assert(file.op == op::NONE); + file.op = op::READV; + file.callback = cb; + file.vec = vec; + filemod(file, rt::EPOLLOUT); + return req { ... }; +}; + +// A callback for a [[write]] or [[writev]] operation. +export type writecb = *fn(file: *file, result: (size | io::error)) void; + +// Schedules a write operation on a file object. +export fn write( + file: *file, + cb: *writecb, + buf: []u8, +) req = { + file.vbuf = io::mkvector(buf); + // XXX: Bit of a hack to avoid allocating a slice + const vec = (&file.vbuf: *[*]io::vector)[..1]; + return writev(file, cb, vec...); +}; + +// Schedules a vectored read operation on a file object. +export fn writev( + file: *file, + cb: *writecb, + vec: io::vector... +) req = { + // XXX: Should we support both pending reads and writes at the same + // time? (yes) + assert(file.op == op::NONE); + file.op = op::WRITEV; + file.callback = cb; + file.vec = vec; + filemod(file, rt::EPOLLOUT); + return req { ... }; +}; diff --git a/ev/+linux/types.ha b/ev/+linux/types.ha index c6713c6a7227677a13cd1423693724b31626b39e..067ce7bf41b5de538d0cf6c18c48ac6ab12641ab 100644 --- a/ev/+linux/types.ha +++ b/ev/+linux/types.ha @@ -1,15 +1,3 @@ -// 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, +export type req = struct { + placeholder: uint, }; -// TODO: Add less portable flags like EPOLLWAKEUP -- 2.48.1