|
9 | 9 |
|
10 | 10 | use std::cell::RefCell;
|
11 | 11 | use std::collections::BinaryHeap;
|
12 |
| -use std::sync::{ |
13 |
| - atomic::{AtomicBool, Ordering}, |
14 |
| - Arc, Mutex, |
15 |
| -}; |
| 12 | +use std::sync::{Arc, Mutex}; |
16 | 13 | use std::time::{Duration, Instant};
|
17 | 14 |
|
18 |
| -use super::ping::{make_ping, PingError, PingSource}; |
19 | 15 | use crate::{EventSource, Poll, PostAction, Readiness, Token, TokenFactory};
|
20 | 16 |
|
| 17 | +#[cfg(target_os = "linux")] |
| 18 | +mod timerfd; |
| 19 | +#[cfg(target_os = "linux")] |
| 20 | +use timerfd::{TimerScheduler, TimerSource}; |
| 21 | + |
| 22 | +#[cfg(any( |
| 23 | + target_os = "dragonfly", |
| 24 | + target_os = "freebsd", |
| 25 | + target_os = "netbsd", |
| 26 | + target_os = "openbsd", |
| 27 | + target_os = "macos" |
| 28 | +))] |
| 29 | +mod threaded; |
| 30 | + |
| 31 | +#[cfg(any( |
| 32 | + target_os = "dragonfly", |
| 33 | + target_os = "freebsd", |
| 34 | + target_os = "netbsd", |
| 35 | + target_os = "openbsd", |
| 36 | + target_os = "macos" |
| 37 | +))] |
| 38 | +use threaded::{TimerScheduler, TimerSource}; |
| 39 | + |
| 40 | +/// An error arising from processing events for a timer. |
| 41 | +#[derive(thiserror::Error, Debug)] |
| 42 | +#[error(transparent)] |
| 43 | +pub struct TimerError(Box<dyn std::error::Error + Sync + Send>); |
| 44 | + |
21 | 45 | /// A Timer event source
|
22 | 46 | ///
|
23 | 47 | /// It generates events of type `(T, TimerHandle<T>)`, providing you
|
@@ -122,23 +146,21 @@ impl<T> EventSource for Timer<T> {
|
122 | 146 | inner: self.inner.clone(),
|
123 | 147 | };
|
124 | 148 | let inner = &self.inner;
|
125 |
| - self.source |
126 |
| - .process_events(readiness, token, |(), &mut ()| { |
127 |
| - loop { |
128 |
| - let next_expired: Option<T> = { |
129 |
| - let mut guard = inner.lock().unwrap(); |
130 |
| - guard.next_expired() |
131 |
| - }; |
132 |
| - if let Some(val) = next_expired { |
133 |
| - callback(val, &mut handle); |
134 |
| - } else { |
135 |
| - break; |
136 |
| - } |
| 149 | + self.source.process_events(readiness, token, |(), &mut ()| { |
| 150 | + loop { |
| 151 | + let next_expired: Option<T> = { |
| 152 | + let mut guard = inner.lock().unwrap(); |
| 153 | + guard.next_expired() |
| 154 | + }; |
| 155 | + if let Some(val) = next_expired { |
| 156 | + callback(val, &mut handle); |
| 157 | + } else { |
| 158 | + break; |
137 | 159 | }
|
138 |
| - // now compute the next timeout and signal if necessary |
139 |
| - inner.lock().unwrap().reschedule(); |
140 |
| - }) |
141 |
| - .map_err(TimerError) |
| 160 | + } |
| 161 | + // now compute the next timeout and signal if necessary |
| 162 | + inner.lock().unwrap().reschedule(); |
| 163 | + }) |
142 | 164 | }
|
143 | 165 |
|
144 | 166 | fn register(&mut self, poll: &mut Poll, token_factory: &mut TokenFactory) -> crate::Result<()> {
|
@@ -272,97 +294,6 @@ impl<T> std::cmp::PartialEq for TimeoutData<T> {
|
272 | 294 |
|
273 | 295 | impl<T> std::cmp::Eq for TimeoutData<T> {}
|
274 | 296 |
|
275 |
| -/* |
276 |
| - * Scheduling |
277 |
| - */ |
278 |
| - |
279 |
| -#[derive(Debug)] |
280 |
| -struct TimerScheduler { |
281 |
| - current_deadline: Arc<Mutex<Option<Instant>>>, |
282 |
| - kill_switch: Arc<AtomicBool>, |
283 |
| - thread: Option<std::thread::JoinHandle<()>>, |
284 |
| -} |
285 |
| - |
286 |
| -type TimerSource = PingSource; |
287 |
| - |
288 |
| -impl TimerScheduler { |
289 |
| - fn new() -> crate::Result<(TimerScheduler, TimerSource)> { |
290 |
| - let current_deadline = Arc::new(Mutex::new(None::<Instant>)); |
291 |
| - let thread_deadline = current_deadline.clone(); |
292 |
| - |
293 |
| - let kill_switch = Arc::new(AtomicBool::new(false)); |
294 |
| - let thread_kill = kill_switch.clone(); |
295 |
| - |
296 |
| - let (ping, ping_source) = make_ping()?; |
297 |
| - |
298 |
| - let thread = std::thread::Builder::new() |
299 |
| - .name("calloop timer".into()) |
300 |
| - .spawn(move || loop { |
301 |
| - // stop if requested |
302 |
| - if thread_kill.load(Ordering::Acquire) { |
303 |
| - return; |
304 |
| - } |
305 |
| - // otherwise check the timeout |
306 |
| - let opt_deadline: Option<Instant> = { |
307 |
| - // subscope to ensure the mutex does not remain locked while the thread is parked |
308 |
| - let guard = thread_deadline.lock().unwrap(); |
309 |
| - *guard |
310 |
| - }; |
311 |
| - if let Some(deadline) = opt_deadline { |
312 |
| - if let Some(remaining) = deadline.checked_duration_since(Instant::now()) { |
313 |
| - // it is not yet expired, go to sleep until it |
314 |
| - std::thread::park_timeout(remaining); |
315 |
| - } else { |
316 |
| - // it is expired, wake the event loop and go to sleep |
317 |
| - ping.ping(); |
318 |
| - std::thread::park(); |
319 |
| - } |
320 |
| - } else { |
321 |
| - // there is none, got to sleep |
322 |
| - std::thread::park(); |
323 |
| - } |
324 |
| - })?; |
325 |
| - |
326 |
| - let scheduler = TimerScheduler { |
327 |
| - current_deadline, |
328 |
| - kill_switch, |
329 |
| - thread: Some(thread), |
330 |
| - }; |
331 |
| - Ok((scheduler, ping_source)) |
332 |
| - } |
333 |
| - |
334 |
| - fn reschedule(&mut self, new_deadline: Instant) { |
335 |
| - let mut deadline_guard = self.current_deadline.lock().unwrap(); |
336 |
| - if let Some(current_deadline) = *deadline_guard { |
337 |
| - if new_deadline < current_deadline || current_deadline <= Instant::now() { |
338 |
| - *deadline_guard = Some(new_deadline); |
339 |
| - self.thread.as_ref().unwrap().thread().unpark(); |
340 |
| - } |
341 |
| - } else { |
342 |
| - *deadline_guard = Some(new_deadline); |
343 |
| - self.thread.as_ref().unwrap().thread().unpark(); |
344 |
| - } |
345 |
| - } |
346 |
| - |
347 |
| - fn deschedule(&mut self) { |
348 |
| - *(self.current_deadline.lock().unwrap()) = None; |
349 |
| - } |
350 |
| -} |
351 |
| - |
352 |
| -impl Drop for TimerScheduler { |
353 |
| - fn drop(&mut self) { |
354 |
| - self.kill_switch.store(true, Ordering::Release); |
355 |
| - let thread = self.thread.take().unwrap(); |
356 |
| - thread.thread().unpark(); |
357 |
| - let _ = thread.join(); |
358 |
| - } |
359 |
| -} |
360 |
| - |
361 |
| -/// An error arising from processing events for a timer. |
362 |
| -#[derive(thiserror::Error, Debug)] |
363 |
| -#[error(transparent)] |
364 |
| -pub struct TimerError(PingError); |
365 |
| - |
366 | 297 | /*
|
367 | 298 | * Tests
|
368 | 299 | */
|
|
0 commit comments