Skip to content

Commit

Permalink
Initial support for Solaris even port API:
Browse files Browse the repository at this point in the history
  • Loading branch information
psumbera committed Nov 18, 2019
1 parent ac0515c commit f6284af
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 2 deletions.
167 changes: 167 additions & 0 deletions src/sys/unix/selector/evport.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use crate::{Interests, Token};

use libc::{POLLIN, POLLOUT};
use log::error;
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use std::{cmp, io, ptr};

/// Unique id for use as `SelectorId`.
#[cfg(debug_assertions)]
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);

#[derive(Debug)]
pub struct Selector {
#[cfg(debug_assertions)]
id: usize,
ep: RawFd,
}

impl Selector {
pub fn new() -> io::Result<Selector> {
syscall!(port_create()).map(|ep| Selector {
#[cfg(debug_assertions)]
id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
ep,
})
}

#[cfg(debug_assertions)]
pub fn id(&self) -> usize {
self.id
}

pub fn try_clone(&self) -> io::Result<Selector> {
return syscall!(dup(self.ep)).map(|ep| Selector {
// It's the same selector, so we use the same id.
#[cfg(debug_assertions)]
id: 0,
ep,
})
}

pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
let timeout = timeout.map(|to| libc::timespec {
tv_sec: cmp::min(to.as_secs(), libc::time_t::max_value() as u64) as libc::time_t,
// `Duration::subsec_nanos` is guaranteed to be less than one
// billion (the number of nanoseconds in a second), making the
// cast to i32 safe. The cast itself is needed for platforms
// where C's long is only 32 bits.
tv_nsec: libc::c_long::from(to.subsec_nanos() as i32),
});
let timeout = timeout
.as_ref()
.map(|s| s as *const _)
.unwrap_or(ptr::null_mut());

let mut nget = 1 as u32;

events.clear();
syscall!(port_getn(self.ep, events.as_mut_ptr(), events.capacity() as u32, &mut nget as *mut u32, timeout))
.map(|_| {
// This is safe because `epoll_wait` ensures that `n_events` are
// assigned.
unsafe { events.set_len(nget as usize) };
})
}

pub fn register(&self, fd: RawFd, token: Token, interests: Interests) -> io::Result<()> {

// PORT_SOURCE_FD is 4
syscall!(port_associate(self.ep, 4, fd as usize, interests_to_evport(interests), usize::from(token) as *mut libc::c_void)).map(|_| ())
}

pub fn reregister(&self, fd: RawFd, token: Token, interests: Interests) -> io::Result<()> {

// PORT_SOURCE_FD is 4
syscall!(port_associate(self.ep, 4, fd as usize, interests_to_evport(interests), usize::from(token) as *mut libc::c_void)).map(|_| ())
}

pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
// PORT_SOURCE_FD is 4
syscall!(port_dissociate(self.ep, 4, fd as usize)).map(|_| ())
}
}

fn interests_to_evport(interests: Interests) -> i32 {
let mut kind = 0;

if interests.is_readable() {
kind = kind | POLLIN;
}

if interests.is_writable() {
kind |= POLLOUT;
}

kind as i32
}

impl AsRawFd for Selector {
fn as_raw_fd(&self) -> RawFd {
self.ep
}
}

impl Drop for Selector {
fn drop(&mut self) {
if let Err(err) = syscall!(close(self.ep)) {
error!("error closing evport: {}", err);
}
}
}

pub type Event = libc::port_event;
pub type Events = Vec<Event>;

pub mod event {
use crate::sys::Event;
use crate::Token;

pub fn token(event: &Event) -> Token {
// Token(event.portev_object as usize)
Token(event.portev_events as usize)
}

pub fn is_readable(event: &Event) -> bool {
(event.portev_events as libc::c_short & libc::POLLIN) != 0
|| (event.portev_events as libc::c_short & libc::POLLPRI) != 0
}

pub fn is_writable(event: &Event) -> bool {
(event.portev_events as libc::c_short & libc::POLLOUT) != 0
}

pub fn is_error(event: &Event) -> bool {
(event.portev_events as libc::c_short & libc::POLLERR) != 0
}

pub fn is_read_closed(event: &Event) -> bool {
// Both halves of the socket have closed
event.portev_events as libc::c_short & libc::POLLHUP != 0
}

pub fn is_write_closed(event: &Event) -> bool {
// Both halves of the socket have closed
event.portev_events as libc::c_short & libc::POLLHUP != 0
// Unix pipe write end has closed
|| (event.portev_events as libc::c_short & libc::POLLOUT != 0
&& event.portev_events as libc::c_short & libc::POLLERR != 0)
}

pub fn is_priority(event: &Event) -> bool {
(event.portev_events as libc::c_short & libc::POLLPRI) != 0
}

pub fn is_aio(_: &Event) -> bool {
// Not supported in the kernel, only in libc.
false
}

pub fn is_lio(_: &Event) -> bool {
// Not supported.
false
}
}
10 changes: 8 additions & 2 deletions src/sys/unix/selector/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
#[cfg(any(target_os = "linux", target_os = "android"))]
mod epoll;

#[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::epoll::{event, Event, Events, Selector};

#[cfg(any(
Expand All @@ -23,3 +23,9 @@ mod kqueue;
target_os = "openbsd"
))]
pub use self::kqueue::{event, Event, Events, Selector};

#[cfg(any(target_os = "solaris"))]
mod evport;

#[cfg(any(target_os = "solaris"))]
pub use self::evport::{event, Event, Events, Selector};

0 comments on commit f6284af

Please sign in to comment.