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
use {Error, Result, from_ffi};
use errno::Errno;
use libc::c_int;
use std::fmt;
use std::os::unix::io::RawFd;

mod ffi {
    use libc::{c_int};
    use super::EpollEvent;

    extern {
        pub fn epoll_create(size: c_int) -> c_int;
        pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *const EpollEvent) -> c_int;
        pub fn epoll_wait(epfd: c_int, events: *mut EpollEvent, max_events: c_int, timeout: c_int) -> c_int;
    }
}

bitflags!(
    #[repr(C)]
    flags EpollEventKind: u32 {
        const EPOLLIN = 0x001,
        const EPOLLPRI = 0x002,
        const EPOLLOUT = 0x004,
        const EPOLLRDNORM = 0x040,
        const EPOLLRDBAND = 0x080,
        const EPOLLWRNORM = 0x100,
        const EPOLLWRBAND = 0x200,
        const EPOLLMSG = 0x400,
        const EPOLLERR = 0x008,
        const EPOLLHUP = 0x010,
        const EPOLLRDHUP = 0x2000,
        const EPOLLWAKEUP = 1 << 29,
        const EPOLLONESHOT = 1 << 30,
        const EPOLLET = 1 << 31
    }
);

impl fmt::Debug for EpollEventKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let variants = [
            (EPOLLIN,       "EPOLLIN"),
            (EPOLLPRI,      "EPOLLPRI"),
            (EPOLLOUT,      "EPOLLOUT"),
            (EPOLLRDNORM,   "EPOLLRDNORM"),
            (EPOLLRDBAND,   "EPOLLRDBAND"),
            (EPOLLWRNORM,   "EPOLLWRNORM"),
            (EPOLLWRBAND,   "EPOLLWRBAND"),
            (EPOLLMSG,      "EPOLLMSG"),
            (EPOLLERR,      "EPOLLERR"),
            (EPOLLHUP,      "EPOLLHUP"),
            (EPOLLRDHUP,    "EPOLLRDHUP"),
            (EPOLLWAKEUP,   "EPOLLWAKEUP"),
            (EPOLLONESHOT,  "EPOLLONESHOT"),
            (EPOLLET,       "EPOLLET")];

        let mut first = true;

        for &(val, name) in variants.iter() {
            if self.contains(val) {
                if first {
                    first = false;
                    try!(write!(fmt, "{}", name));
                } else {
                    try!(write!(fmt, "|{}", name));
                }
            }
        }

        Ok(())
    }
}

#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
    EpollCtlAdd = 1,
    EpollCtlDel = 2,
    EpollCtlMod = 3
}

#[cfg(all(target_os = "android", not(target_arch = "x86_64")))]
#[derive(Copy)]
#[repr(C)]
pub struct EpollEvent {
    pub events: EpollEventKind,
    pub data: u64
}

#[cfg(all(target_os = "android", not(target_arch = "x86_64")))]
#[test]
fn test_epoll_event_size() {
    use std::mem::size_of;
    assert_eq!(size_of::<EpollEvent>(), 16);
}

#[cfg(any(not(target_os = "android"), target_arch = "x86_64"))]
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct EpollEvent {
    pub events: EpollEventKind,
    pub data: u64
}

#[inline]
pub fn epoll_create() -> Result<RawFd> {
    let res = unsafe { ffi::epoll_create(1024) };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(res)
}

#[inline]
pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &EpollEvent) -> Result<()> {
    let res = unsafe { ffi::epoll_ctl(epfd, op as c_int, fd, event as *const EpollEvent) };
    from_ffi(res)
}

#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
    let res = unsafe {
        ffi::epoll_wait(epfd, events.as_mut_ptr(), events.len() as c_int, timeout_ms as c_int)
    };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(res as usize)
}