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
use std::ptr::null_mut;
use std::os::unix::io::RawFd;
use libc::c_int;
use {Result, Error};
use errno::Errno;
use sys::time::TimeVal;

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]
}

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

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
#[repr(C)]
pub struct FdSet {
    bits: [u64; FD_SETSIZE as usize / 64]
}

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

impl FdSet {
    pub fn new() -> FdSet {
        FdSet {
            bits: [0; FD_SETSIZE as usize / BITS]
        }
    }

    pub fn insert(&mut self, fd: RawFd) {
        let fd = fd as usize;
        self.bits[fd / BITS] |= 1 << (fd % BITS);
    }

    pub fn remove(&mut self, fd: RawFd) {
        let fd = fd as usize;
        self.bits[fd / BITS] &= !(1 << (fd % BITS));
    }

    pub fn contains(&mut self, fd: RawFd) -> bool {
        let fd = fd as usize;
        self.bits[fd / BITS] & (1 << (fd % BITS)) > 0
    }
}

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: &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 as *mut TimeVal;

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

    if res == -1 {
        Err(Error::Sys(Errno::last()))
    } else {   
        Ok(res)
    } 
}