| 1 | use std::{ |
| 2 | cell::RefCell, |
| 3 | collections::HashMap, |
| 4 | rc::Rc, |
| 5 | sync::Arc, |
| 6 | time::{Duration, Instant}, |
| 7 | }; |
| 8 | |
| 9 | #[cfg (unix)] |
| 10 | use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd as Borrowed, RawFd as Raw}; |
| 11 | |
| 12 | #[cfg (windows)] |
| 13 | use std::os::windows::io::{AsRawSocket, AsSocket, BorrowedSocket as Borrowed, RawSocket as Raw}; |
| 14 | |
| 15 | use polling::{Event, Events, PollMode, Poller}; |
| 16 | |
| 17 | use crate::sources::timer::TimerWheel; |
| 18 | use crate::token::TokenInner; |
| 19 | use crate::RegistrationToken; |
| 20 | |
| 21 | /// Possible modes for registering a file descriptor |
| 22 | #[derive (Copy, Clone, Debug)] |
| 23 | pub enum Mode { |
| 24 | /// Single event generation |
| 25 | /// |
| 26 | /// This FD will be disabled as soon as it has generated one event. |
| 27 | /// |
| 28 | /// The user will need to use `LoopHandle::update()` to re-enable it if |
| 29 | /// desired. |
| 30 | OneShot, |
| 31 | |
| 32 | /// Level-triggering |
| 33 | /// |
| 34 | /// This FD will report events on every poll as long as the requested interests |
| 35 | /// are available. |
| 36 | Level, |
| 37 | |
| 38 | /// Edge-triggering |
| 39 | /// |
| 40 | /// This FD will report events only when it *gains* one of the requested interests. |
| 41 | /// it must thus be fully processed before it'll generate events again. |
| 42 | /// |
| 43 | /// This mode is not supported on certain platforms, and an error will be returned |
| 44 | /// if it is used. |
| 45 | /// |
| 46 | /// ## Supported Platforms |
| 47 | /// |
| 48 | /// As of the time of writing, the platforms that support edge triggered polling are |
| 49 | /// as follows: |
| 50 | /// |
| 51 | /// - Linux/Android |
| 52 | /// - macOS/iOS/tvOS/watchOS |
| 53 | /// - FreeBSD/OpenBSD/NetBSD/DragonflyBSD |
| 54 | Edge, |
| 55 | } |
| 56 | |
| 57 | /// Interest to register regarding the file descriptor |
| 58 | #[derive (Copy, Clone, Debug)] |
| 59 | pub struct Interest { |
| 60 | /// Wait for the FD to be readable |
| 61 | pub readable: bool, |
| 62 | |
| 63 | /// Wait for the FD to be writable |
| 64 | pub writable: bool, |
| 65 | } |
| 66 | |
| 67 | impl Interest { |
| 68 | /// Shorthand for empty interest |
| 69 | pub const EMPTY: Interest = Interest { |
| 70 | readable: false, |
| 71 | writable: false, |
| 72 | }; |
| 73 | |
| 74 | /// Shorthand for read interest |
| 75 | pub const READ: Interest = Interest { |
| 76 | readable: true, |
| 77 | writable: false, |
| 78 | }; |
| 79 | |
| 80 | /// Shorthand for write interest |
| 81 | pub const WRITE: Interest = Interest { |
| 82 | readable: false, |
| 83 | writable: true, |
| 84 | }; |
| 85 | |
| 86 | /// Shorthand for read and write interest |
| 87 | pub const BOTH: Interest = Interest { |
| 88 | readable: true, |
| 89 | writable: true, |
| 90 | }; |
| 91 | } |
| 92 | |
| 93 | /// Readiness for a file descriptor notification |
| 94 | #[derive (Copy, Clone, Debug)] |
| 95 | pub struct Readiness { |
| 96 | /// Is the FD readable |
| 97 | pub readable: bool, |
| 98 | |
| 99 | /// Is the FD writable |
| 100 | pub writable: bool, |
| 101 | |
| 102 | /// Is the FD in an error state |
| 103 | pub error: bool, |
| 104 | } |
| 105 | |
| 106 | impl Readiness { |
| 107 | /// Shorthand for empty readiness |
| 108 | pub const EMPTY: Readiness = Readiness { |
| 109 | readable: false, |
| 110 | writable: false, |
| 111 | error: false, |
| 112 | }; |
| 113 | } |
| 114 | |
| 115 | #[derive (Debug)] |
| 116 | pub(crate) struct PollEvent { |
| 117 | pub(crate) readiness: Readiness, |
| 118 | pub(crate) token: Token, |
| 119 | } |
| 120 | |
| 121 | /// Factory for creating tokens in your registrations |
| 122 | /// |
| 123 | /// When composing event sources, each sub-source needs to |
| 124 | /// have its own token to identify itself. This factory is |
| 125 | /// provided to produce such unique tokens. |
| 126 | |
| 127 | #[derive (Debug)] |
| 128 | pub struct TokenFactory { |
| 129 | next_token: TokenInner, |
| 130 | } |
| 131 | |
| 132 | impl TokenFactory { |
| 133 | pub(crate) fn new(token: TokenInner) -> TokenFactory { |
| 134 | TokenFactory { |
| 135 | next_token: token.forget_sub_id(), |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | /// Get the "raw" registration token of this TokenFactory |
| 140 | pub(crate) fn registration_token(&self) -> RegistrationToken { |
| 141 | RegistrationToken::new(self.next_token.forget_sub_id()) |
| 142 | } |
| 143 | |
| 144 | /// Produce a new unique token |
| 145 | pub fn token(&mut self) -> Token { |
| 146 | let token: TokenInner = self.next_token; |
| 147 | self.next_token = token.increment_sub_id(); |
| 148 | Token { inner: token } |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | /// A token (for implementation of the [`EventSource`](crate::EventSource) trait) |
| 153 | /// |
| 154 | /// This token is produced by the [`TokenFactory`] and is used when calling the |
| 155 | /// [`EventSource`](crate::EventSource) implementations to process event, in order |
| 156 | /// to identify which sub-source produced them. |
| 157 | /// |
| 158 | /// You should forward it to the [`Poll`] when registering your file descriptors. |
| 159 | #[derive (Clone, Copy, Debug, PartialEq, Eq)] |
| 160 | pub struct Token { |
| 161 | pub(crate) inner: TokenInner, |
| 162 | } |
| 163 | |
| 164 | /// The polling system |
| 165 | /// |
| 166 | /// This type represents the polling system of calloop, on which you |
| 167 | /// can register your file descriptors. This interface is only accessible in |
| 168 | /// implementations of the [`EventSource`](crate::EventSource) trait. |
| 169 | /// |
| 170 | /// You only need to interact with this type if you are implementing your |
| 171 | /// own event sources, while implementing the [`EventSource`](crate::EventSource) trait. |
| 172 | /// And even in this case, you can often just use the [`Generic`](crate::generic::Generic) event |
| 173 | /// source and delegate the implementations to it. |
| 174 | pub struct Poll { |
| 175 | /// The handle to wepoll/epoll/kqueue/... used to poll for events. |
| 176 | pub(crate) poller: Arc<Poller>, |
| 177 | |
| 178 | /// The buffer of events returned by the poller. |
| 179 | events: RefCell<Events>, |
| 180 | |
| 181 | /// The sources registered as level triggered. |
| 182 | /// |
| 183 | /// Some platforms that `polling` supports do not support level-triggered events. As of the time |
| 184 | /// of writing, this only includes Solaris and illumos. To work around this, we emulate level |
| 185 | /// triggered events by keeping this map of file descriptors. |
| 186 | /// |
| 187 | /// One can emulate level triggered events on top of oneshot events by just re-registering the |
| 188 | /// file descriptor every time it is polled. However, this is not ideal, as it requires a |
| 189 | /// system call every time. It's better to use the intergrated system, if available. |
| 190 | level_triggered: Option<RefCell<HashMap<usize, (Raw, polling::Event)>>>, |
| 191 | |
| 192 | pub(crate) timers: Rc<RefCell<TimerWheel>>, |
| 193 | } |
| 194 | |
| 195 | impl std::fmt::Debug for Poll { |
| 196 | #[cfg_attr (feature = "nightly_coverage" , coverage(off))] |
| 197 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 198 | f.write_str(data:"Poll { ... }" ) |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | impl Poll { |
| 203 | pub(crate) fn new() -> crate::Result<Poll> { |
| 204 | Self::new_inner(false) |
| 205 | } |
| 206 | |
| 207 | fn new_inner(force_fallback_lt: bool) -> crate::Result<Poll> { |
| 208 | let poller = Poller::new()?; |
| 209 | let level_triggered = if poller.supports_level() && !force_fallback_lt { |
| 210 | None |
| 211 | } else { |
| 212 | Some(RefCell::new(HashMap::new())) |
| 213 | }; |
| 214 | |
| 215 | Ok(Poll { |
| 216 | poller: Arc::new(poller), |
| 217 | events: RefCell::new(Events::new()), |
| 218 | timers: Rc::new(RefCell::new(TimerWheel::new())), |
| 219 | level_triggered, |
| 220 | }) |
| 221 | } |
| 222 | |
| 223 | pub(crate) fn poll(&self, mut timeout: Option<Duration>) -> crate::Result<Vec<PollEvent>> { |
| 224 | // Adjust the timeout for the timers. |
| 225 | let next_timeout = self |
| 226 | .timers |
| 227 | .borrow() |
| 228 | .next_deadline() |
| 229 | .map(|deadline| deadline.saturating_duration_since(Instant::now())); |
| 230 | timeout = match (timeout, next_timeout) { |
| 231 | (Some(timeout), Some(next_timeout)) => Some(timeout.min(next_timeout)), |
| 232 | _ => timeout.or(next_timeout), |
| 233 | }; |
| 234 | |
| 235 | let mut events = self.events.borrow_mut(); |
| 236 | events.clear(); |
| 237 | self.poller.wait(&mut events, timeout)?; |
| 238 | |
| 239 | // Convert `polling` events to `calloop` events. |
| 240 | let level_triggered = self.level_triggered.as_ref().map(RefCell::borrow); |
| 241 | let mut poll_events = events |
| 242 | .iter() |
| 243 | .map(|ev| { |
| 244 | // If we need to emulate level-triggered events... |
| 245 | if let Some(level_triggered) = level_triggered.as_ref() { |
| 246 | // ...and this event is from a level-triggered source... |
| 247 | if let Some((source, interest)) = level_triggered.get(&ev.key) { |
| 248 | // ...then we need to re-register the source. |
| 249 | // SAFETY: The source is valid. |
| 250 | self.poller |
| 251 | .modify(unsafe { Borrowed::borrow_raw(*source) }, *interest)?; |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | Ok(PollEvent { |
| 256 | readiness: Readiness { |
| 257 | readable: ev.readable, |
| 258 | writable: ev.writable, |
| 259 | error: false, |
| 260 | }, |
| 261 | token: Token { |
| 262 | inner: TokenInner::from(ev.key), |
| 263 | }, |
| 264 | }) |
| 265 | }) |
| 266 | .collect::<std::io::Result<Vec<_>>>()?; |
| 267 | |
| 268 | drop(events); |
| 269 | |
| 270 | let now = Instant::now(); |
| 271 | let mut timers = self.timers.borrow_mut(); |
| 272 | while let Some((_, token)) = timers.next_expired(now) { |
| 273 | poll_events.push(PollEvent { |
| 274 | readiness: Readiness { |
| 275 | readable: true, |
| 276 | writable: false, |
| 277 | error: false, |
| 278 | }, |
| 279 | token, |
| 280 | }); |
| 281 | } |
| 282 | |
| 283 | Ok(poll_events) |
| 284 | } |
| 285 | |
| 286 | /// Register a new file descriptor for polling |
| 287 | /// |
| 288 | /// The file descriptor will be registered with given interest, |
| 289 | /// mode and token. This function will fail if given a |
| 290 | /// bad file descriptor or if the provided file descriptor is already |
| 291 | /// registered. |
| 292 | /// |
| 293 | /// # Safety |
| 294 | /// |
| 295 | /// The registered source must not be dropped before it is unregistered. |
| 296 | /// |
| 297 | /// # Leaking tokens |
| 298 | /// |
| 299 | /// If your event source is dropped without being unregistered, the token |
| 300 | /// passed in here will remain on the heap and continue to be used by the |
| 301 | /// polling system even though no event source will match it. |
| 302 | pub unsafe fn register( |
| 303 | &self, |
| 304 | #[cfg (unix)] fd: impl AsFd, |
| 305 | #[cfg (windows)] fd: impl AsSocket, |
| 306 | interest: Interest, |
| 307 | mode: Mode, |
| 308 | token: Token, |
| 309 | ) -> crate::Result<()> { |
| 310 | let raw = { |
| 311 | #[cfg (unix)] |
| 312 | { |
| 313 | fd.as_fd().as_raw_fd() |
| 314 | } |
| 315 | |
| 316 | #[cfg (windows)] |
| 317 | { |
| 318 | fd.as_socket().as_raw_socket() |
| 319 | } |
| 320 | }; |
| 321 | |
| 322 | let ev = cvt_interest(interest, token); |
| 323 | |
| 324 | // SAFETY: See invariant on function. |
| 325 | unsafe { |
| 326 | self.poller |
| 327 | .add_with_mode(raw, ev, cvt_mode(mode, self.poller.supports_level()))?; |
| 328 | } |
| 329 | |
| 330 | // If this is level triggered and we're emulating level triggered mode... |
| 331 | if let (Mode::Level, Some(level_triggered)) = (mode, self.level_triggered.as_ref()) { |
| 332 | // ...then we need to keep track of the source. |
| 333 | let mut level_triggered = level_triggered.borrow_mut(); |
| 334 | level_triggered.insert(ev.key, (raw, ev)); |
| 335 | } |
| 336 | |
| 337 | Ok(()) |
| 338 | } |
| 339 | |
| 340 | /// Update the registration for a file descriptor |
| 341 | /// |
| 342 | /// This allows you to change the interest, mode or token of a file |
| 343 | /// descriptor. Fails if the provided fd is not currently registered. |
| 344 | /// |
| 345 | /// See note on [`register()`](Self::register()) regarding leaking. |
| 346 | pub fn reregister( |
| 347 | &self, |
| 348 | #[cfg (unix)] fd: impl AsFd, |
| 349 | #[cfg (windows)] fd: impl AsSocket, |
| 350 | interest: Interest, |
| 351 | mode: Mode, |
| 352 | token: Token, |
| 353 | ) -> crate::Result<()> { |
| 354 | let (borrowed, raw) = { |
| 355 | #[cfg (unix)] |
| 356 | { |
| 357 | (fd.as_fd(), fd.as_fd().as_raw_fd()) |
| 358 | } |
| 359 | |
| 360 | #[cfg (windows)] |
| 361 | { |
| 362 | (fd.as_socket(), fd.as_socket().as_raw_socket()) |
| 363 | } |
| 364 | }; |
| 365 | |
| 366 | let ev = cvt_interest(interest, token); |
| 367 | self.poller |
| 368 | .modify_with_mode(borrowed, ev, cvt_mode(mode, self.poller.supports_level()))?; |
| 369 | |
| 370 | // If this is level triggered and we're emulating level triggered mode... |
| 371 | if let (Mode::Level, Some(level_triggered)) = (mode, self.level_triggered.as_ref()) { |
| 372 | // ...then we need to keep track of the source. |
| 373 | let mut level_triggered = level_triggered.borrow_mut(); |
| 374 | level_triggered.insert(ev.key, (raw, ev)); |
| 375 | } |
| 376 | |
| 377 | Ok(()) |
| 378 | } |
| 379 | |
| 380 | /// Unregister a file descriptor |
| 381 | /// |
| 382 | /// This file descriptor will no longer generate events. Fails if the |
| 383 | /// provided file descriptor is not currently registered. |
| 384 | pub fn unregister( |
| 385 | &self, |
| 386 | #[cfg (unix)] fd: impl AsFd, |
| 387 | #[cfg (windows)] fd: impl AsSocket, |
| 388 | ) -> crate::Result<()> { |
| 389 | let (borrowed, raw) = { |
| 390 | #[cfg (unix)] |
| 391 | { |
| 392 | (fd.as_fd(), fd.as_fd().as_raw_fd()) |
| 393 | } |
| 394 | |
| 395 | #[cfg (windows)] |
| 396 | { |
| 397 | (fd.as_socket(), fd.as_socket().as_raw_socket()) |
| 398 | } |
| 399 | }; |
| 400 | self.poller.delete(borrowed)?; |
| 401 | |
| 402 | if let Some(level_triggered) = self.level_triggered.as_ref() { |
| 403 | let mut level_triggered = level_triggered.borrow_mut(); |
| 404 | level_triggered.retain(|_, (source, _)| *source != raw); |
| 405 | } |
| 406 | |
| 407 | Ok(()) |
| 408 | } |
| 409 | |
| 410 | /// Get a thread-safe handle which can be used to wake up the `Poll`. |
| 411 | pub(crate) fn notifier(&self) -> Notifier { |
| 412 | Notifier(self.poller.clone()) |
| 413 | } |
| 414 | |
| 415 | /// Get a reference to the poller. |
| 416 | pub(crate) fn poller(&self) -> &Arc<Poller> { |
| 417 | &self.poller |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | /// Thread-safe handle which can be used to wake up the `Poll`. |
| 422 | #[derive (Clone)] |
| 423 | pub(crate) struct Notifier(Arc<Poller>); |
| 424 | |
| 425 | impl Notifier { |
| 426 | pub(crate) fn notify(&self) -> crate::Result<()> { |
| 427 | self.0.notify()?; |
| 428 | |
| 429 | Ok(()) |
| 430 | } |
| 431 | } |
| 432 | |
| 433 | fn cvt_interest(interest: Interest, tok: Token) -> Event { |
| 434 | let mut event: Event = Event::none(key:tok.inner.into()); |
| 435 | event.readable = interest.readable; |
| 436 | event.writable = interest.writable; |
| 437 | event |
| 438 | } |
| 439 | |
| 440 | fn cvt_mode(mode: Mode, supports_other_modes: bool) -> PollMode { |
| 441 | if !supports_other_modes { |
| 442 | return PollMode::Oneshot; |
| 443 | } |
| 444 | |
| 445 | match mode { |
| 446 | Mode::Edge => PollMode::Edge, |
| 447 | Mode::Level => PollMode::Level, |
| 448 | Mode::OneShot => PollMode::Oneshot, |
| 449 | } |
| 450 | } |
| 451 | |