Files @ 2c1fa43903ac
Branch filter:

Location: CSY/reowolf/src/runtime2/poll/mod.rs

2c1fa43903ac 3.1 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
MH
Several unfinished attempts at introducing polling
use libc::{self, c_int};

use std::{io, ptr, time};

pub(crate) type FileDescriptor = c_int;

pub(crate) trait AsFileDescriptor {
    fn as_file_descriptor(&self) -> FileDescriptor;

}
pub(crate) struct UserData(u64);

#[inline]
pub(crate) fn register_polling<F: AsFileDescriptor>(
    poller: &Poller, entity: F, user: UserData, read: bool, write: bool
) -> io::Result<()> {
    let file_descriptor = entity.as_file_descriptor();
    return poller.register(file_descriptor, user, read, write);
}

#[inline]
pub(crate) fn unregister_polling<F: AsFileDescriptor>(
    poller: &Poller, entity: F
) -> io::Result<()> {
    let file_descriptor = entity.as_file_descriptor();
    return poller.unregister(file_descriptor);
}

#[cfg(unix)]
pub(crate) struct Poller {
    handle: c_int,
    events: Vec<libc::epoll_event>
}

// All of this is gleaned from the `mio` crate.
#[cfg(unix)]
impl Poller {
    pub fn new(event_capacity: usize) -> io::Result<Self> {
        assert!(event_capacity < i32::MAX as usize); // because of argument to `epoll_wait`.
        let handle = syscall_result(unsafe{ libc::epoll_create1(libc::EPOLL_CLOEXEC) })?;

        return Ok(Self{
            handle,
            events: Vec::with_capacity(event_capacity),
        })
    }

    fn register(&self, fd: FileDescriptor, user: UserData, read: bool, write: bool) -> io::Result<()> {
        let mut event = libc::epoll_event{
            events: Self::events_from_rw_flags(read, write),
            u64: user.0,
        };
        syscall_result(unsafe{
            libc::epoll_ctl(self.handle, libc::EPOLL_CTL_ADD, fd, &mut event)
        })?;

        return Ok(());
    }

    fn unregister(&self, fd: FileDescriptor) -> io::Result<()> {
        syscall_result(unsafe{
            libc::epoll_ctl(self.handle, libc::EPOLL_CTL_DEL, fd, ptr::null_mut())
        })?;

        return Ok(());
    }

    pub fn wait(&mut self, timeout: time::Duration) -> io::Result<()> {
        // See `mio` for the reason. Works around a linux bug
        #[cfg(target_pointer_width = "32")]
        const MAX_TIMEOUT: u128 = 1789569;
        #[cfg(not(target_pointer_width = "32"))]
        const MAX_TIMEOUT: u128 = c_int::MAX as u128;

        let mut timeout_millis = timeout.as_millis();
        if timeout_millis > MAX_TIMEOUT {
            timeout_millis = -1; // effectively infinite
        }

        let num_events = syscall_result(unsafe{
            libc::epoll_wait(self.handle, self.events.as_mut(), self.events.capacity() as i32, timeout_millis)
        })?;

        unsafe{
            debug_assert!(num_events >= 0);
            self.events.set_len(num_events as usize);
        }

        return Ok(());
    }

    fn events_from_rw_flags(read: bool, write: bool) -> u32 {
        let mut events = libc::EPOLLET;
        if read {
            events |= libc::EPOLLIN | libc::EPOLLRDHUP;
        }
        if write {
            events |= libc::EPOLLOUT;
        }

        return events as u32;
    }
}

#[inline]
fn syscall_result(result: c_int) -> io::Result<c_int> {
    if result < 0 {
        return Err(io::Error::last_os_error());
    } else {
        return Ok(result);
    }
}

#[cfg(not(unix))]
struct Poller {

}