Skip to main content

dope_kqueue/
lib.rs

1#![cfg(any(
2    target_os = "macos",
3    target_os = "freebsd",
4    target_os = "netbsd",
5    target_os = "openbsd",
6    target_os = "dragonfly"
7))]
8#![allow(clippy::missing_safety_doc)]
9
10mod driver_config;
11mod errno;
12
13pub mod driver;
14
15use std::future::Future;
16use std::io;
17use std::os::fd::{AsRawFd, RawFd};
18use std::pin::Pin;
19use std::task::{Context, Poll};
20
21use dope_core::Fd;
22use dope_core::addr::SockAddr;
23use dope_core::driver::DriverOps;
24use dope_core::submit::{RecvMsgPacket, SendMsgPacket, SubmitOps};
25
26pub use driver::{
27    CurrentSlot, Driver, ProvidedBuf, ProvidedRing, Request, Token, current, current_driver_mut,
28    set_current,
29};
30pub use driver_config::DriverConfig;
31pub use errno::Errno;
32
33pub fn new_driver(cfg: DriverConfig) -> io::Result<Driver> {
34    Driver::new(cfg)
35}
36
37#[derive(Clone, Copy, Debug, Default)]
38pub struct KqueueBackend;
39
40impl dope_core::driver::Backend for KqueueBackend {
41    type Driver = driver::Driver;
42    type Config = DriverConfig;
43    type RecvMsgOut = driver::RecvMsgOut;
44    type ProvidedBuf = driver::ProvidedBuf;
45
46    fn new_driver(cfg: Self::Config) -> io::Result<Self::Driver> {
47        Driver::new(cfg)
48    }
49}
50
51thread_local! {
52    static AUX: std::cell::Cell<Option<dope_core::driver::ExternalDispatch<KqueueBackend>>> =
53        const { std::cell::Cell::new(None) };
54}
55
56impl dope_core::driver::CompletionBackend for KqueueBackend {
57    type Token = driver::Token;
58
59    fn current_slot() -> Option<dope_core::driver::CurrentSlot<Self>> {
60        driver::current()
61    }
62
63    fn set_slot(slot: Option<dope_core::driver::CurrentSlot<Self>>) {
64        driver::set_current(slot);
65    }
66
67    fn install_external(
68        aux: Option<dope_core::driver::ExternalDispatch<Self>>,
69    ) -> Option<dope_core::driver::ExternalDispatch<Self>> {
70        AUX.with(|c| c.replace(aux))
71    }
72
73    fn current_external() -> Option<dope_core::driver::ExternalDispatch<Self>> {
74        AUX.with(|c| c.get())
75    }
76
77    fn drive_with<R: dope_core::driver::CompletionRouter<Self>>(
78        driver: &mut Self::Driver,
79        router: &mut R,
80    ) -> io::Result<bool> {
81        driver.drive_with(router)
82    }
83
84    fn dispatch_completions<R: dope_core::driver::CompletionRouter<Self>>(
85        driver: &mut Self::Driver,
86        router: &mut R,
87    ) {
88        driver.dispatch_completions(router)
89    }
90}
91
92impl SubmitOps for &mut Driver {
93    fn submit_accept(
94        self,
95        fd: Fd,
96    ) -> impl Future<Output = io::Result<(RawFd, SockAddr)>> + 'static {
97        let raw = fd.as_raw_fd();
98        driver::Sock::set_nonblocking(raw);
99        AcceptFuture::new(raw)
100    }
101
102    fn submit_read<B>(self, fd: Fd, buf: B) -> impl Future<Output = (io::Result<u32>, B)> + 'static
103    where
104        B: AsMut<[u8]> + Unpin + 'static,
105    {
106        let raw = fd.as_raw_fd();
107        async move {
108            let mut buf = buf;
109            let slice = buf.as_mut();
110            let n = unsafe { libc::read(raw, slice.as_mut_ptr().cast(), slice.len()) };
111            (Errno::syscall_result(n), buf)
112        }
113    }
114
115    fn submit_send_raw<B>(
116        self,
117        fd: Fd,
118        buf: B,
119        len: usize,
120    ) -> impl Future<Output = (io::Result<u32>, B)> + 'static
121    where
122        B: AsRef<[u8]> + Unpin + 'static,
123    {
124        let raw = fd.as_raw_fd();
125        async move {
126            let bytes = buf.as_ref();
127            let n = len.min(bytes.len());
128            let r = unsafe { libc::send(raw, bytes.as_ptr().cast(), n, 0) };
129            (Errno::syscall_result(r), buf)
130        }
131    }
132
133    fn submit_sendmsg_raw<P>(
134        self,
135        fd: Fd,
136        packet: P,
137    ) -> impl Future<Output = (io::Result<u32>, P)> + 'static
138    where
139        P: SendMsgPacket + Unpin + 'static,
140    {
141        let req = self.try_submit_sendmsg_raw(fd, packet);
142        Request::await_or_err(req)
143    }
144
145    fn submit_recvmsg_raw<P>(
146        self,
147        fd: Fd,
148        packet: P,
149    ) -> impl Future<Output = (io::Result<u32>, P)> + 'static
150    where
151        P: RecvMsgPacket + Unpin + 'static,
152    {
153        let raw = fd.as_raw_fd();
154        async move {
155            let mut packet = packet;
156            let msg = packet.msg_mut_ptr();
157            let n = unsafe { libc::recvmsg(raw, msg, 0) };
158            (Errno::syscall_result(n), packet)
159        }
160    }
161}
162
163enum AcceptState {
164    Idle,
165    Waiting(Request<()>),
166    Done,
167}
168
169pub struct AcceptFuture {
170    fd: RawFd,
171    state: AcceptState,
172}
173
174impl AcceptFuture {
175    fn new(fd: RawFd) -> Self {
176        Self {
177            fd,
178            state: AcceptState::Idle,
179        }
180    }
181
182    fn try_accept(&mut self) -> Option<io::Result<(RawFd, SockAddr)>> {
183        let mut addr = SockAddr::empty();
184        let r = unsafe { libc::accept(self.fd, addr.addr_mut_ptr(), addr.addr_len_ptr()) };
185        if r >= 0 {
186            return Some(Ok((r as RawFd, addr)));
187        }
188        let err = io::Error::last_os_error();
189        if matches!(err.raw_os_error(), Some(libc::EAGAIN)) {
190            return None;
191        }
192        Some(Err(err))
193    }
194}
195
196impl Future for AcceptFuture {
197    type Output = io::Result<(RawFd, SockAddr)>;
198
199    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
200        let me = self.get_mut();
201        loop {
202            match &mut me.state {
203                AcceptState::Done => panic!("AcceptFuture polled after completion"),
204                AcceptState::Idle => {
205                    if let Some(out) = me.try_accept() {
206                        me.state = AcceptState::Done;
207                        return Poll::Ready(out);
208                    }
209                    let driver = driver::current_driver_mut();
210                    let req = driver.register_read_oneshot(me.fd);
211                    me.state = AcceptState::Waiting(req);
212                }
213                AcceptState::Waiting(req) => match Pin::new(req).poll(cx) {
214                    Poll::Pending => {
215                        return Poll::Pending;
216                    }
217                    Poll::Ready((res, _flags, _)) => {
218                        res?;
219                        me.state = AcceptState::Idle;
220                    }
221                },
222            }
223        }
224    }
225}