1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
//!Cross-platform wrapper over select.
//!
//!This library provides simple interface over POSIX's `select` enabling you to write
//!very simple async programs using `std` networking primitives.
//!
//!But if you want performance you should look for `tokio` or `mio`
mod sys;
use sys::FdSet;
pub use sys::AsRawFd;
use std::io;
use core::time;
pub use sys::FD_LIMIT;
///Represents successful select call.
///
///It contains number of fd ready.
///And also set of these ids, allowing to query which fd is ready.
pub struct SelectResult {
count: usize,
read: FdSet,
write: FdSet,
except: FdSet,
}
impl SelectResult {
#[inline]
///Returns total number of file descriptors ready.
pub const fn len(&self) -> usize {
self.count
}
#[inline]
///Returns whether specified `source` is read ready.
pub fn is_read<T: AsRawFd>(&self, source: &T) -> bool {
self.read.is_present(source)
}
#[inline]
///Returns whether specified `source` is write ready.
pub fn is_write<T: AsRawFd>(&self, source: &T) -> bool {
self.write.is_present(source)
}
#[inline]
///Returns whether specified `source` is except ready.
pub fn is_except<T: AsRawFd>(&self, source: &T) -> bool {
self.except.is_present(source)
}
}
#[derive(Clone)]
///Select abstraction allowing you to monitor specified sockets.
///
///Selector itself represents set of file descriptors to monitor, as such it is possible
///to copy it.
///Normally select modifies list of file descriptors, but `Selector` always copies existing list,
///avoiding these modifications.
///
///## Performance recommendations
///
///Generally limited to 64 file descriptors, but you should only use select when you have ~10 fds
///otherwise modern API like `kqueue` or `epoll` would yield much better performance.
///
///- Call select only when getting would block from syscall;
///- Limit number of selects, allowing it to accumulate events;
pub struct Selector {
read: FdSet,
write: FdSet,
except: FdSet,
}
impl Selector {
#[inline]
///Creates new instance with no sockets to monitor.
pub fn new() -> Self {
Self {
read: FdSet::new(),
write: FdSet::new(),
except: FdSet::new(),
}
}
#[inline]
///Adds `source` to monitor for read ops.
///
///Panics when goes over `FD_LIMIT`
pub fn add_read<T: AsRawFd>(&mut self, source: &T) {
assert!(self.read.len() < sys::FD_LIMIT);
self.read.add(source);
}
#[inline]
///Adds `source` to monitor for write ops.
///
///Panics when goes over `FD_LIMIT`
pub fn add_write<T: AsRawFd>(&mut self, source: &T) {
assert!(self.write.len() < sys::FD_LIMIT);
self.write.add(source);
}
#[inline]
///Adds `source` to monitor for exceptional ops.
///
///Panics when goes over `FD_LIMIT`
pub fn add_except<T: AsRawFd>(&mut self, source: &T) {
assert!(self.except.len() < sys::FD_LIMIT);
self.except.add(source);
}
#[inline]
///Removes all fds from read monitoring
pub fn clear_read(&mut self) {
self.read.clear();
}
#[inline]
///Removes all fds from write monitoring
pub fn clear_write(&mut self) {
self.write.clear();
}
#[inline]
///Removes all fds from except monitoring
pub fn clear_except(&mut self) {
self.except.clear();
}
#[inline]
///Performs select, awaiting indefinitely until at least one descriptor has changes.
pub fn select(&self) -> io::Result<SelectResult> {
let mut result = SelectResult {
count: 0,
read: self.read.clone(),
write: self.write.clone(),
except: self.except.clone(),
};
result.count = sys::select(&mut result.read, &mut result.write, &mut result.except)?;
Ok(result)
}
#[inline]
///Performs select, checking file descriptors for changes and returning immediately.
pub fn try_select(&self) -> io::Result<SelectResult> {
let mut result = SelectResult {
count: 0,
read: self.read.clone(),
write: self.write.clone(),
except: self.except.clone(),
};
result.count = sys::select_timeout(&mut result.read, &mut result.write, &mut result.except, time::Duration::from_secs(0))?;
Ok(result)
}
#[inline]
///Performs select, awaiting at most `time` until at least one descriptor has changes.
pub fn select_timeout(&self, time: time::Duration) -> io::Result<SelectResult> {
let mut result = SelectResult {
count: 0,
read: self.read.clone(),
write: self.write.clone(),
except: self.except.clone(),
};
result.count = sys::select_timeout(&mut result.read, &mut result.write, &mut result.except, time)?;
Ok(result)
}
}