Coverage Report

Created: 2026-11-03 08:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/parking-2.2.1/src/lib.rs
Line
Count
Source
1
//! Thread parking and unparking.
2
//!
3
//! A [`Parker`] is in either the notified or unnotified state. The [`park()`][`Parker::park()`] method blocks
4
//! the current thread until the [`Parker`] becomes notified and then puts it back into the unnotified
5
//! state. The [`unpark()`][`Unparker::unpark()`] method puts it into the notified state.
6
//!
7
//! This API is similar to [`thread::park()`] and [`Thread::unpark()`] from the standard library.
8
//! The difference is that the state "token" managed by those functions is shared across an entire
9
//! thread, and anyone can call [`thread::current()`] to access it. If you use `park` and `unpark`,
10
//! but you also call a function that uses `park` and `unpark` internally, that function could
11
//! cause a deadlock by consuming a wakeup that was intended for you. The [`Parker`] object in this
12
//! crate avoids that problem by managing its own state, which isn't shared with unrelated callers.
13
//!
14
//! [`thread::park()`]: https://doc.rust-lang.org/std/thread/fn.park.html
15
//! [`Thread::unpark()`]: https://doc.rust-lang.org/std/thread/struct.Thread.html#method.unpark
16
//! [`thread::current()`]: https://doc.rust-lang.org/std/thread/fn.current.html
17
//!
18
//! # Examples
19
//!
20
//! ```
21
//! use std::thread;
22
//! use std::time::Duration;
23
//! use parking::Parker;
24
//!
25
//! let p = Parker::new();
26
//! let u = p.unparker();
27
//!
28
//! // Notify the parker.
29
//! u.unpark();
30
//!
31
//! // Wakes up immediately because the parker is notified.
32
//! p.park();
33
//!
34
//! thread::spawn(move || {
35
//!     thread::sleep(Duration::from_millis(500));
36
//!     u.unpark();
37
//! });
38
//!
39
//! // Wakes up when `u.unpark()` notifies and then goes back into unnotified state.
40
//! p.park();
41
//! ```
42
43
#![forbid(unsafe_code)]
44
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
45
#![doc(
46
    html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
47
)]
48
#![doc(
49
    html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
50
)]
51
52
#[cfg(not(all(loom, feature = "loom")))]
53
use std::sync;
54
55
#[cfg(all(loom, feature = "loom"))]
56
use loom::sync;
57
58
use std::cell::Cell;
59
use std::fmt;
60
use std::marker::PhantomData;
61
use std::sync::Arc;
62
use std::task::{Wake, Waker};
63
use std::time::Duration;
64
65
#[cfg(not(all(loom, feature = "loom")))]
66
use std::time::Instant;
67
68
use sync::atomic::AtomicUsize;
69
use sync::atomic::Ordering::SeqCst;
70
use sync::{Condvar, Mutex};
71
72
/// Creates a parker and an associated unparker.
73
///
74
/// # Examples
75
///
76
/// ```
77
/// let (p, u) = parking::pair();
78
/// ```
79
0
pub fn pair() -> (Parker, Unparker) {
80
0
    let p = Parker::new();
81
0
    let u = p.unparker();
82
0
    (p, u)
83
0
}
84
85
/// Waits for a notification.
86
pub struct Parker {
87
    unparker: Unparker,
88
    _marker: PhantomData<Cell<()>>,
89
}
90
91
impl Parker {
92
    /// Creates a new parker.
93
    ///
94
    /// # Examples
95
    ///
96
    /// ```
97
    /// use parking::Parker;
98
    ///
99
    /// let p = Parker::new();
100
    /// ```
101
    ///
102
0
    pub fn new() -> Parker {
103
0
        Parker {
104
0
            unparker: Unparker {
105
0
                inner: Arc::new(Inner {
106
0
                    state: AtomicUsize::new(EMPTY),
107
0
                    lock: Mutex::new(()),
108
0
                    cvar: Condvar::new(),
109
0
                }),
110
0
            },
111
0
            _marker: PhantomData,
112
0
        }
113
0
    }
114
115
    /// Blocks until notified and then goes back into unnotified state.
116
    ///
117
    /// # Examples
118
    ///
119
    /// ```
120
    /// use parking::Parker;
121
    ///
122
    /// let p = Parker::new();
123
    /// let u = p.unparker();
124
    ///
125
    /// // Notify the parker.
126
    /// u.unpark();
127
    ///
128
    /// // Wakes up immediately because the parker is notified.
129
    /// p.park();
130
    /// ```
131
0
    pub fn park(&self) {
132
0
        self.unparker.inner.park(None);
133
0
    }
134
135
    /// Blocks until notified and then goes back into unnotified state, or times out after
136
    /// `duration`.
137
    ///
138
    /// Returns `true` if notified before the timeout.
139
    ///
140
    /// # Examples
141
    ///
142
    /// ```
143
    /// use std::time::Duration;
144
    /// use parking::Parker;
145
    ///
146
    /// let p = Parker::new();
147
    ///
148
    /// // Wait for a notification, or time out after 500 ms.
149
    /// p.park_timeout(Duration::from_millis(500));
150
    /// ```
151
    #[cfg(not(loom))]
152
0
    pub fn park_timeout(&self, duration: Duration) -> bool {
153
0
        self.unparker.inner.park(Some(duration))
154
0
    }
155
156
    /// Blocks until notified and then goes back into unnotified state, or times out at `instant`.
157
    ///
158
    /// Returns `true` if notified before the deadline.
159
    ///
160
    /// # Examples
161
    ///
162
    /// ```
163
    /// use std::time::{Duration, Instant};
164
    /// use parking::Parker;
165
    ///
166
    /// let p = Parker::new();
167
    ///
168
    /// // Wait for a notification, or time out after 500 ms.
169
    /// p.park_deadline(Instant::now() + Duration::from_millis(500));
170
    /// ```
171
    #[cfg(not(loom))]
172
0
    pub fn park_deadline(&self, instant: Instant) -> bool {
173
0
        self.unparker
174
0
            .inner
175
0
            .park(Some(instant.saturating_duration_since(Instant::now())))
176
0
    }
177
178
    /// Notifies the parker.
179
    ///
180
    /// Returns `true` if this call is the first to notify the parker, or `false` if the parker
181
    /// was already notified.
182
    ///
183
    /// # Examples
184
    ///
185
    /// ```
186
    /// use std::thread;
187
    /// use std::time::Duration;
188
    /// use parking::Parker;
189
    ///
190
    /// let p = Parker::new();
191
    ///
192
    /// assert_eq!(p.unpark(), true);
193
    /// assert_eq!(p.unpark(), false);
194
    ///
195
    /// // Wakes up immediately.
196
    /// p.park();
197
    /// ```
198
0
    pub fn unpark(&self) -> bool {
199
0
        self.unparker.unpark()
200
0
    }
201
202
    /// Returns a handle for unparking.
203
    ///
204
    /// The returned [`Unparker`] can be cloned and shared among threads.
205
    ///
206
    /// # Examples
207
    ///
208
    /// ```
209
    /// use parking::Parker;
210
    ///
211
    /// let p = Parker::new();
212
    /// let u = p.unparker();
213
    ///
214
    /// // Notify the parker.
215
    /// u.unpark();
216
    ///
217
    /// // Wakes up immediately because the parker is notified.
218
    /// p.park();
219
    /// ```
220
0
    pub fn unparker(&self) -> Unparker {
221
0
        self.unparker.clone()
222
0
    }
223
}
224
225
impl Default for Parker {
226
0
    fn default() -> Parker {
227
0
        Parker::new()
228
0
    }
229
}
230
231
impl fmt::Debug for Parker {
232
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233
0
        f.pad("Parker { .. }")
234
0
    }
235
}
236
237
/// Notifies a parker.
238
pub struct Unparker {
239
    inner: Arc<Inner>,
240
}
241
242
impl Unparker {
243
    /// Notifies the associated parker.
244
    ///
245
    /// Returns `true` if this call is the first to notify the parker, or `false` if the parker
246
    /// was already notified.
247
    ///
248
    /// # Examples
249
    ///
250
    /// ```
251
    /// use std::thread;
252
    /// use std::time::Duration;
253
    /// use parking::Parker;
254
    ///
255
    /// let p = Parker::new();
256
    /// let u = p.unparker();
257
    ///
258
    /// thread::spawn(move || {
259
    ///     thread::sleep(Duration::from_millis(500));
260
    ///     u.unpark();
261
    /// });
262
    ///
263
    /// // Wakes up when `u.unpark()` notifies and then goes back into unnotified state.
264
    /// p.park();
265
    /// ```
266
0
    pub fn unpark(&self) -> bool {
267
0
        self.inner.unpark()
268
0
    }
269
270
    /// Indicates whether this unparker will unpark the associated parker.
271
    ///
272
    /// This can be used to avoid unnecessary work before calling `unpark()`.
273
    ///
274
    /// # Examples
275
    ///
276
    /// ```
277
    /// use parking::Parker;
278
    ///
279
    /// let p = Parker::new();
280
    /// let u = p.unparker();
281
    ///
282
    /// assert!(u.will_unpark(&p));
283
    /// ```
284
0
    pub fn will_unpark(&self, parker: &Parker) -> bool {
285
0
        Arc::ptr_eq(&self.inner, &parker.unparker.inner)
286
0
    }
287
288
    /// Indicates whether two unparkers will unpark the same parker.
289
    ///
290
    /// # Examples
291
    ///
292
    /// ```
293
    /// use parking::Parker;
294
    ///
295
    /// let p = Parker::new();
296
    /// let u1 = p.unparker();
297
    /// let u2 = p.unparker();
298
    ///
299
    /// assert!(u1.same_parker(&u2));
300
    /// ```
301
0
    pub fn same_parker(&self, other: &Unparker) -> bool {
302
0
        Arc::ptr_eq(&self.inner, &other.inner)
303
0
    }
304
}
305
306
impl fmt::Debug for Unparker {
307
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308
0
        f.pad("Unparker { .. }")
309
0
    }
310
}
311
312
impl Clone for Unparker {
313
0
    fn clone(&self) -> Unparker {
314
0
        Unparker {
315
0
            inner: self.inner.clone(),
316
0
        }
317
0
    }
318
}
319
320
impl From<Unparker> for Waker {
321
0
    fn from(up: Unparker) -> Self {
322
0
        Waker::from(up.inner)
323
0
    }
324
}
325
326
const EMPTY: usize = 0;
327
const PARKED: usize = 1;
328
const NOTIFIED: usize = 2;
329
330
struct Inner {
331
    state: AtomicUsize,
332
    lock: Mutex<()>,
333
    cvar: Condvar,
334
}
335
336
impl Inner {
337
0
    fn park(&self, timeout: Option<Duration>) -> bool {
338
        // If we were previously notified then we consume this notification and return quickly.
339
0
        if self
340
0
            .state
341
0
            .compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst)
342
0
            .is_ok()
343
        {
344
0
            return true;
345
0
        }
346
347
        // If the timeout is zero, then there is no need to actually block.
348
0
        if let Some(dur) = timeout {
349
0
            if dur == Duration::from_millis(0) {
350
0
                return false;
351
0
            }
352
0
        }
353
354
        // Otherwise we need to coordinate going to sleep.
355
0
        let mut m = self.lock.lock().unwrap();
356
357
0
        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
358
0
            Ok(_) => {}
359
            // Consume this notification to avoid spurious wakeups in the next park.
360
            Err(NOTIFIED) => {
361
                // We must read `state` here, even though we know it will be `NOTIFIED`. This is
362
                // because `unpark` may have been called again since we read `NOTIFIED` in the
363
                // `compare_exchange` above. We must perform an acquire operation that synchronizes
364
                // with that `unpark` to observe any writes it made before the call to `unpark`. To
365
                // do that we must read from the write it made to `state`.
366
0
                let old = self.state.swap(EMPTY, SeqCst);
367
0
                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
368
0
                return true;
369
            }
370
0
            Err(n) => panic!("inconsistent park_timeout state: {}", n),
371
        }
372
373
0
        match timeout {
374
            None => {
375
                loop {
376
                    // Block the current thread on the conditional variable.
377
0
                    m = self.cvar.wait(m).unwrap();
378
379
0
                    if self
380
0
                        .state
381
0
                        .compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst)
382
0
                        .is_ok()
383
                    {
384
                        // got a notification
385
0
                        return true;
386
0
                    }
387
                }
388
            }
389
0
            Some(timeout) => {
390
                #[cfg(not(loom))]
391
                {
392
                    // Wait with a timeout, and if we spuriously wake up or otherwise wake up from a
393
                    // notification we just want to unconditionally set `state` back to `EMPTY`, either
394
                    // consuming a notification or un-flagging ourselves as parked.
395
0
                    let (_m, _result) = self.cvar.wait_timeout(m, timeout).unwrap();
396
397
0
                    match self.state.swap(EMPTY, SeqCst) {
398
0
                        NOTIFIED => true, // got a notification
399
0
                        PARKED => false,  // no notification
400
0
                        n => panic!("inconsistent park_timeout state: {}", n),
401
                    }
402
                }
403
404
                #[cfg(loom)]
405
                {
406
                    let _ = timeout;
407
                    panic!("park_timeout is not supported under loom");
408
                }
409
            }
410
        }
411
0
    }
412
413
0
    pub fn unpark(&self) -> bool {
414
        // To ensure the unparked thread will observe any writes we made before this call, we must
415
        // perform a release operation that `park` can synchronize with. To do that we must write
416
        // `NOTIFIED` even if `state` is already `NOTIFIED`. That is why this must be a swap rather
417
        // than a compare-and-swap that returns if it reads `NOTIFIED` on failure.
418
0
        match self.state.swap(NOTIFIED, SeqCst) {
419
0
            EMPTY => return true,     // no one was waiting
420
0
            NOTIFIED => return false, // already unparked
421
0
            PARKED => {}              // gotta go wake someone up
422
0
            _ => panic!("inconsistent state in unpark"),
423
        }
424
425
        // There is a period between when the parked thread sets `state` to `PARKED` (or last
426
        // checked `state` in the case of a spurious wakeup) and when it actually waits on `cvar`.
427
        // If we were to notify during this period it would be ignored and then when the parked
428
        // thread went to sleep it would never wake up. Fortunately, it has `lock` locked at this
429
        // stage so we can acquire `lock` to wait until it is ready to receive the notification.
430
        //
431
        // Releasing `lock` before the call to `notify_one` means that when the parked thread wakes
432
        // it doesn't get woken only to have to wait for us to release `lock`.
433
0
        drop(self.lock.lock().unwrap());
434
0
        self.cvar.notify_one();
435
0
        true
436
0
    }
437
}
438
439
impl Wake for Inner {
440
    #[inline]
441
0
    fn wake(self: Arc<Self>) {
442
0
        self.unpark();
443
0
    }
444
445
    #[inline]
446
0
    fn wake_by_ref(self: &Arc<Self>) {
447
0
        self.unpark();
448
0
    }
449
}