/rust/registry/src/index.crates.io-6f17d22bba15001f/epoll-4.3.3/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com> |
2 | | // |
3 | | // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. |
4 | | // If a copy of the MPL was not distributed with this file, |
5 | | // You can obtain one at http://mozilla.org/MPL/2.0/. |
6 | | |
7 | | #[macro_use] |
8 | | extern crate bitflags; |
9 | | extern crate libc; |
10 | | |
11 | | use std::fmt::{Debug, Formatter, Result}; |
12 | | use std::io::{self, Error}; |
13 | | use std::os::unix::io::RawFd; |
14 | | |
15 | | #[repr(i32)] |
16 | | #[allow(non_camel_case_types)] |
17 | | pub enum ControlOptions { |
18 | | /// Indicates an addition to the interest list. |
19 | | EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD, |
20 | | /// Indicates a modification of flags for an interest already in list. |
21 | | EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD, |
22 | | /// Indicates a removal of an interest from the list. |
23 | | EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL, |
24 | | } |
25 | | |
26 | | bitflags! { |
27 | | |
28 | | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
29 | | pub struct Events: u32 { |
30 | | /// Sets the Edge Triggered behavior for the associated file descriptor. |
31 | | /// |
32 | | /// The default behavior for epoll is Level Triggered. |
33 | | const EPOLLET = libc::EPOLLET as u32; |
34 | | /// The associated file is available for read operations. |
35 | | const EPOLLIN = libc::EPOLLIN as u32; |
36 | | /// Error condition happened on the associated file descriptor. |
37 | | /// |
38 | | /// `wait` will always wait for this event; is not necessary to set it in events. |
39 | | const EPOLLERR = libc::EPOLLERR as u32; |
40 | | /// Hang up happened on the associated file descriptor. |
41 | | /// |
42 | | /// `wait` will always wait for this event; it is not necessary to set it in events. |
43 | | /// Note that when reading from a channel such as a pipe or a stream socket, this event |
44 | | /// merely indicates that the peer closed its end of the channel. Subsequent reads from |
45 | | /// the channel will return 0 (end of file) only after all outstanding data in the |
46 | | /// channel has been consumed. |
47 | | const EPOLLHUP = libc::EPOLLHUP as u32; |
48 | | /// The associated file is available for write operations. |
49 | | const EPOLLOUT = libc::EPOLLOUT as u32; |
50 | | /// There is urgent data available for read operations. |
51 | | const EPOLLPRI = libc::EPOLLPRI as u32; |
52 | | /// Stream socket peer closed connection, or shut down writing half of connection. |
53 | | /// |
54 | | /// This flag is especially useful for writing simple code to detect peer shutdown when |
55 | | /// using Edge Triggered monitoring. |
56 | | const EPOLLRDHUP = libc::EPOLLRDHUP as u32; |
57 | | /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND` |
58 | | /// capability, ensure that the system does not enter "suspend" or "hibernate" while this |
59 | | /// event is pending or being processed. |
60 | | /// |
61 | | /// The event is considered as being "processed" from the time when it is returned by |
62 | | /// a call to `wait` until the next call to `wait` on the same `EpollInstance` |
63 | | /// descriptor, the closure of that file descriptor, the removal of the event file |
64 | | /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file |
65 | | /// descriptor with `EPOLL_CTL_MOD`. |
66 | | const EPOLLWAKEUP = libc::EPOLLWAKEUP as u32; |
67 | | /// Sets the one-shot behavior for the associated file descriptor. |
68 | | /// |
69 | | /// This means that after an event is pulled out with `wait` the associated file |
70 | | /// descriptor is internally disabled and no other events will be reported by the epoll |
71 | | /// interface. The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file |
72 | | /// descriptor with a new event mask. |
73 | | const EPOLLONESHOT = libc::EPOLLONESHOT as u32; |
74 | | /// Sets an exclusive wakeup mode for the epoll file descriptor that is being attached to |
75 | | /// the target file descriptor, `fd`. When a wakeup event occurs and multiple epoll file |
76 | | /// descriptors are attached to the same target file using `EPOLLEXCLUSIVE`, one or more of |
77 | | /// the epoll file descriptors will receive an event with `wait`. The default in this |
78 | | /// scenario (when `EPOLLEXCLUSIVE` is not set) is for all epoll file descriptors to |
79 | | /// receive an event. `EPOLLEXCLUSIVE` is thus useful for avoiding thundering herd problems |
80 | | /// in certain scenarios. |
81 | | /// |
82 | | /// If the same file descriptor is in multiple epoll instances, some with the |
83 | | /// `EPOLLEXCLUSIVE` flag, and others without, then events will be provided to all epoll |
84 | | /// instances that did not specify `EPOLLEXCLUSIVE`, and at least one of the epoll |
85 | | /// instances that did specify `EPOLLEXCLUSIVE`. |
86 | | /// |
87 | | /// The following values may be specified in conjunction with `EPOLLEXCLUSIVE`: `EPOLLIN`, |
88 | | /// `EPOLLOUT`, `EPOLLWAKEUP`, and `EPOLLET`. `EPOLLHUP` and `EPOLLERR` can also be |
89 | | /// specified, but this is not required: as usual, these events are always reported if they |
90 | | /// occur, regardless of whether they are specified in `Events`. Attempts to specify other |
91 | | /// values in `Events` yield the error `EINVAL`. |
92 | | /// |
93 | | /// `EPOLLEXCLUSIVE` may be used only in an `EPOLL_CTL_ADD` operation; attempts to employ |
94 | | /// it with `EPOLL_CTL_MOD` yield an error. If `EPOLLEXCLUSIVE` has been set using `ctl`, |
95 | | /// then a subsequent `EPOLL_CTL_MOD` on the same `epfd`, `fd` pair yields an error. A call |
96 | | /// to `ctl` that specifies `EPOLLEXCLUSIVE` in `Events` and specifies the target file |
97 | | /// descriptor `fd` as an epoll instance will likewise fail. The error in all of these |
98 | | /// cases is `EINVAL`. |
99 | | /// |
100 | | /// The `EPOLLEXCLUSIVE` flag is an input flag for the `Event.events` field when calling |
101 | | /// `ctl`; it is never returned by `wait`. |
102 | | const EPOLLEXCLUSIVE = libc::EPOLLEXCLUSIVE as u32; |
103 | | } |
104 | | } |
105 | | |
106 | | /// 'libc::epoll_event' equivalent. |
107 | | #[repr(C)] |
108 | | #[cfg_attr(target_arch = "x86_64", repr(packed))] |
109 | | #[derive(Clone, Copy)] |
110 | | pub struct Event { |
111 | | pub events: u32, |
112 | | pub data: u64, |
113 | | } |
114 | | |
115 | | impl Event { |
116 | 109k | pub fn new(events: Events, data: u64) -> Event { |
117 | 109k | Event { |
118 | 109k | events: events.bits(), |
119 | 109k | data: data, |
120 | 109k | } |
121 | 109k | } |
122 | | } |
123 | | |
124 | | impl Debug for Event { |
125 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> Result { |
126 | 0 | let data = self.data; |
127 | 0 | f.debug_struct("Event") |
128 | 0 | .field("events", &Events::from_bits_retain(self.events)) // Retain so we can see erroneously set bits too |
129 | 0 | .field("data", &data) |
130 | 0 | .finish() |
131 | 0 | } |
132 | | } |
133 | | |
134 | | /// Creates a new epoll file descriptor. |
135 | | /// |
136 | | /// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor. |
137 | | /// |
138 | | /// ## Notes |
139 | | /// |
140 | | /// * `epoll_create1()` is the underlying syscall. |
141 | 32.6k | pub fn create(cloexec: bool) -> io::Result<RawFd> { |
142 | 32.6k | let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 }; |
143 | 32.6k | unsafe { cvt(libc::epoll_create1(flags)) } |
144 | 32.6k | } |
145 | | |
146 | | /// Safe wrapper for `libc::epoll_ctl` |
147 | 77.2k | pub fn ctl( |
148 | 77.2k | epfd: RawFd, |
149 | 77.2k | op: ControlOptions, |
150 | 77.2k | fd: RawFd, |
151 | 77.2k | mut event: Event, |
152 | 77.2k | ) -> io::Result<()> { |
153 | 77.2k | let e = &mut event as *mut _ as *mut libc::epoll_event; |
154 | 77.2k | unsafe { cvt(libc::epoll_ctl(epfd, op as i32, fd, e))? }; |
155 | 77.2k | Ok(()) |
156 | 77.2k | } |
157 | | |
158 | | /// Safe wrapper for `libc::epoll_wait` |
159 | | /// |
160 | | /// ## Notes |
161 | | /// |
162 | | /// * If `timeout` is negative, it will block until an event is received. |
163 | 745k | pub fn wait(epfd: RawFd, timeout: i32, buf: &mut [Event]) -> io::Result<usize> { |
164 | 745k | let timeout = if timeout < -1 { -1 } else { timeout }; |
165 | 745k | let num_events = unsafe { |
166 | 745k | cvt(libc::epoll_wait( |
167 | 745k | epfd, |
168 | 745k | buf.as_mut_ptr() as *mut libc::epoll_event, |
169 | 745k | buf.len() as i32, |
170 | 745k | timeout, |
171 | 745k | ))? as usize |
172 | | }; |
173 | 745k | Ok(num_events) |
174 | 745k | } |
175 | | |
176 | | /// Safe wrapper for `libc::close` |
177 | 0 | pub fn close(epfd: RawFd) -> io::Result<()> { |
178 | 0 | cvt(unsafe { libc::close(epfd) })?; |
179 | 0 | Ok(()) |
180 | 0 | } |
181 | | |
182 | 855k | fn cvt(result: libc::c_int) -> io::Result<libc::c_int> { |
183 | 855k | if result < 0 { |
184 | 0 | Err(Error::last_os_error()) |
185 | | } else { |
186 | 855k | Ok(result) |
187 | | } |
188 | 855k | } |