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