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
// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com> // // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. #[macro_use] extern crate bitflags; extern crate libc; use std::io::{self, Error}; use std::os::unix::io::RawFd; bitflags! { pub struct ControlOptions: i32 { /// Indicates an addition to the interest list. const EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD; /// Indicates a modification of flags for an interest already in list. const EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD; /// Indicates a removal of an interest from the list. const EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL; } } bitflags! { pub struct Events: u32 { /// Sets the Edge Triggered behavior for the associated file descriptor. /// /// The default behavior for epoll is Level Triggered. const EPOLLET = libc::EPOLLET as u32; /// The associated file is available for read operations. const EPOLLIN = libc::EPOLLIN as u32; /// Error condition happened on the associated file descriptor. /// /// `wait` will always wait for this event; is not necessary to set it in events. const EPOLLERR = libc::EPOLLERR as u32; /// Hang up happened on the associated file descriptor. /// /// `wait` will always wait for this event; it is not necessary to set it in events. /// Note that when reading from a channel such as a pipe or a stream socket, this event /// merely indicates that the peer closed its end of the channel. Subsequent reads from /// the channel will return 0 (end of file) only after all outstanding data in the /// channel has been consumed. const EPOLLHUP = libc::EPOLLHUP as u32; /// The associated file is available for write operations. const EPOLLOUT = libc::EPOLLOUT as u32; /// There is urgent data available for read operations. const EPOLLPRI = libc::EPOLLPRI as u32; /// Stream socket peer closed connection, or shut down writing half of connection. /// /// This flag is especially useful for writing simple code to detect peer shutdown when /// using Edge Triggered monitoring. const EPOLLRDHUP = libc::EPOLLRDHUP as u32; /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND` /// capability, ensure that the system does not enter "suspend" or "hibernate" while this /// event is pending or being processed. /// /// The event is considered as being "processed" from the time when it is returned by /// a call to `wait` until the next call to `wait` on the same `EpollInstance` /// descriptor, the closure of that file descriptor, the removal of the event file /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file /// descriptor with `EPOLL_CTL_MOD`. const EPOLLWAKEUP = libc::EPOLLWAKEUP as u32; /// Sets the one-shot behavior for the associated file descriptor. /// /// This means that after an event is pulled out with `wait` the associated file /// descriptor is internally disabled and no other events will be reported by the epoll /// interface. The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file /// descriptor with a new event mask. const EPOLLONESHOT = libc::EPOLLONESHOT as u32; } } /// 'libc::epoll_event' equivalent. #[repr(C)] #[repr(packed)] #[derive(Clone, Copy)] pub struct Event { pub events: u32, pub data: u64 } impl Event { pub fn new(events: Events, data: u64) -> Event { Event { events: events.bits(), data: data } } } /// Creates a new epoll file descriptor. /// /// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor. /// /// ## Notes /// /// * `epoll_create1()` is the underlying syscall. pub fn create(cloexec: bool) -> io::Result<RawFd> { let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 }; unsafe { cvt(libc::epoll_create1(flags)) } } /// Safe wrapper for `libc::epoll_ctl` pub fn ctl(epfd: RawFd, op: ControlOptions, fd: RawFd, mut event: Event) -> io::Result<()> { let e = &mut event as *mut _ as *mut libc::epoll_event; unsafe { try!(cvt(libc::epoll_ctl(epfd, op.bits, fd, e))) }; Ok(()) } /// Safe wrapper for `libc::epoll_wait` /// /// ## Notes /// /// * If `timeout` is negative, it will block until an event is received. pub fn wait(epfd: RawFd, timeout: i32, buf: &mut [Event]) -> io::Result<usize> { let timeout = if timeout < -1 { -1 } else { timeout }; let num_events = unsafe { try!(cvt(libc::epoll_wait(epfd, buf.as_mut_ptr() as *mut libc::epoll_event, buf.len() as i32, timeout))) as usize }; Ok(num_events) } fn cvt(result: libc::c_int) -> io::Result<libc::c_int> { if result < 0 { Err(Error::last_os_error()) } else { Ok(result) } }