Coverage Report

Created: 2025-03-07 06:49

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