use std::mem;
use nix::fcntl::Fd;
use nix::sys::event::*;
use error::{MioResult, MioError};
use os::IoDesc;
use poll::{IoEvent, IOREADABLE, IOWRITABLE, IOERROR, IOHINTED, IOHUPHINT};
pub struct Selector {
kq: Fd,
changes: Events
}
impl Selector {
pub fn new() -> MioResult<Selector> {
Ok(Selector {
kq: try!(kqueue().map_err(MioError::from_sys_error)),
changes: Events::new()
})
}
pub fn select(&mut self, evts: &mut Events, timeout_ms: uint) -> MioResult<()> {
let cnt = try!(kevent(self.kq, self.changes.as_slice(),
evts.as_mut_slice(), timeout_ms)
.map_err(MioError::from_sys_error));
self.changes.len = 0;
evts.len = cnt;
Ok(())
}
pub fn register(&mut self, io: &IoDesc, token: uint) -> MioResult<()> {
let flag = EV_ADD | EV_CLEAR;
try!(self.ev_push(io, EVFILT_READ, flag, FilterFlag::empty(), token));
try!(self.ev_push(io, EVFILT_WRITE, flag, FilterFlag::empty(), token));
Ok(())
}
fn ev_push(&mut self,
io: &IoDesc,
filter: EventFilter,
flags: EventFlag,
fflags: FilterFlag,
token: uint) -> MioResult<()> {
try!(self.maybe_flush_changes());
let idx = self.changes.len;
let ev = &mut self.changes.events[idx];
ev_set(ev, io.fd as uint, filter, flags, fflags, token);
self.changes.len += 1;
Ok(())
}
fn maybe_flush_changes(&mut self) -> MioResult<()> {
if self.changes.is_full() {
try!(kevent(self.kq, self.changes.as_slice(), &mut [], 0)
.map_err(MioError::from_sys_error));
self.changes.len = 0;
}
Ok(())
}
}
pub struct Events {
len: uint,
events: [KEvent, ..1024]
}
impl Events {
pub fn new() -> Events {
Events {
len: 0,
events: unsafe { mem::uninitialized() }
}
}
#[inline]
pub fn len(&self) -> uint {
self.len
}
#[inline]
pub fn get(&self, idx: uint) -> IoEvent {
if idx >= self.len {
panic!("invalid index");
}
let ev = &self.events[idx];
let token = ev.udata;
let mut kind = IOHINTED;
if ev.filter == EVFILT_READ {
kind = kind | IOREADABLE;
} else if ev.filter == EVFILT_WRITE {
kind = kind | IOWRITABLE;
} else {
unimplemented!();
}
if ev.flags.contains(EV_EOF) {
kind = kind | IOHUPHINT;
if !ev.fflags.is_empty() {
kind = kind | IOERROR;
}
}
IoEvent::new(kind, token)
}
#[inline]
fn is_full(&self) -> bool {
self.len == self.events.len()
}
fn as_slice(&self) -> &[KEvent] {
self.events.slice_to(self.len)
}
fn as_mut_slice(&mut self) -> &mut [KEvent] {
self.events.as_mut_slice()
}
}