Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move SigSet, TimeVal to libc, add TimeSpec and pselect syscall. #276

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 58 additions & 49 deletions src/sys/select.rs
Original file line number Diff line number Diff line change
@@ -1,85 +1,94 @@
use std::ptr::null_mut;
use std::ptr::{null, null_mut};
use std::os::unix::io::RawFd;
use libc::c_int;
use std::mem;
use libc;
use libc::{fd_set, c_int, timespec, timeval, sigset_t};
use {Errno, Result};
use sys::time::TimeVal;
use sys::time::{TimeVal, TimeSpec};
use sys::signal::SigSet;

pub const FD_SETSIZE: RawFd = 1024;

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[repr(C)]
pub struct FdSet {
bits: [i32; FD_SETSIZE as usize / 32]
set: fd_set
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
const BITS: usize = 32;

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
#[repr(C)]
#[derive(Clone)]
pub struct FdSet {
bits: [u64; FD_SETSIZE as usize / 64]
impl AsRef<fd_set> for FdSet {
fn as_ref(&self) -> &fd_set {
&self.set
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AsMut?

}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
const BITS: usize = 64;
pub const FD_SETSIZE: RawFd = libc::FD_SETSIZE as RawFd;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be a usize as in libc.


impl FdSet {
pub fn new() -> FdSet {
FdSet {
bits: [0; FD_SETSIZE as usize / BITS]
}
let mut set = FdSet {
set: unsafe { mem::uninitialized() }
};
set.clear();
set
}

pub fn insert(&mut self, fd: RawFd) {
let fd = fd as usize;
self.bits[fd / BITS] |= 1 << (fd % BITS);
assert!(fd >= 0 && fd < FD_SETSIZE, "RawFd out of bounds");
unsafe {
libc::FD_SET(fd, &mut self.set as *mut _);
}
}

pub fn remove(&mut self, fd: RawFd) {
let fd = fd as usize;
self.bits[fd / BITS] &= !(1 << (fd % BITS));
assert!(fd >= 0 && fd < FD_SETSIZE, "RawFd out of bounds");
unsafe {
libc::FD_CLR(fd, &mut self.set as *mut _);
}
}

pub fn contains(&mut self, fd: RawFd) -> bool {
let fd = fd as usize;
self.bits[fd / BITS] & (1 << (fd % BITS)) > 0
pub fn contains(&self, fd: RawFd) -> bool {
assert!(fd >= 0 && fd < FD_SETSIZE, "RawFd out of bounds");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can probably just return false in this case, while preserving expected meaning?

unsafe {
// We require `transmute` here because FD_ISSET wants a mutable pointer,
// when in fact it doesn't mutate.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for the comment, thanks :-)

libc::FD_ISSET(fd, mem::transmute(&self.set as *const fd_set))
}
}

pub fn clear(&mut self) {
for bits in &mut self.bits {
*bits = 0
unsafe {
libc::FD_ZERO(&mut self.set as *mut _);
}
}
}

mod ffi {
use libc::c_int;
use sys::time::TimeVal;
use super::FdSet;

extern {
pub fn select(nfds: c_int,
readfds: *mut FdSet,
writefds: *mut FdSet,
errorfds: *mut FdSet,
timeout: *mut TimeVal) -> c_int;
}
}

pub fn select(nfds: c_int,
readfds: Option<&mut FdSet>,
writefds: Option<&mut FdSet>,
errorfds: Option<&mut FdSet>,
timeout: Option<&mut TimeVal>) -> Result<c_int> {
let readfds = readfds.map(|set| set as *mut FdSet).unwrap_or(null_mut());
let writefds = writefds.map(|set| set as *mut FdSet).unwrap_or(null_mut());
let errorfds = errorfds.map(|set| set as *mut FdSet).unwrap_or(null_mut());
let timeout = timeout.map(|tv| tv as *mut TimeVal).unwrap_or(null_mut());
let readfds = readfds.map(|set| &mut set.set as *mut fd_set).unwrap_or(null_mut());
let writefds = writefds.map(|set| &mut set.set as *mut fd_set).unwrap_or(null_mut());
let errorfds = errorfds.map(|set| &mut set.set as *mut fd_set).unwrap_or(null_mut());
let timeout = timeout.map(|tv| tv.as_mut() as *mut timeval).unwrap_or(null_mut());

let res = unsafe {
libc::select(nfds, readfds, writefds, errorfds, timeout)
};

Errno::result(res)
}

pub fn pselect(nfds: c_int,
readfds: Option<&mut FdSet>,
writefds: Option<&mut FdSet>,
errorfds: Option<&mut FdSet>,
timeout: Option<&TimeSpec>,
sigmask: Option<&SigSet>) -> Result<c_int> {
let readfds = readfds.map(|set| &mut set.set as *mut fd_set).unwrap_or(null_mut());
let writefds = writefds.map(|set| &mut set.set as *mut fd_set).unwrap_or(null_mut());
let errorfds = errorfds.map(|set| &mut set.set as *mut fd_set).unwrap_or(null_mut());
let timeout = timeout.map(|ts| ts.as_ref() as *const timespec).unwrap_or(null());
let sigmask = sigmask.map(|sm| sm.as_ref() as *const sigset_t).unwrap_or(null());

let res = unsafe {
ffi::select(nfds, readfds, writefds, errorfds, timeout)
libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
};

Errno::result(res)
Expand Down
Loading