1 // Copyright 2016 Amanieu d'Antras
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7
8 //! A simple spin lock based thread parker. Used on platforms without better
9 //! parking facilities available.
10
11 use core::hint::spin_loop;
12 use core::sync::atomic::{AtomicBool, Ordering};
13 use std::thread;
14 use std::time::Instant;
15
16 // Helper type for putting a thread to sleep until some other thread wakes it up
17 pub struct ThreadParker {
18 parked: AtomicBool,
19 }
20
21 impl super::ThreadParkerT for ThreadParker {
22 type UnparkHandle = UnparkHandle;
23
24 const IS_CHEAP_TO_CONSTRUCT: bool = true;
25
26 #[inline]
new() -> ThreadParker27 fn new() -> ThreadParker {
28 ThreadParker {
29 parked: AtomicBool::new(false),
30 }
31 }
32
33 #[inline]
prepare_park(&self)34 unsafe fn prepare_park(&self) {
35 self.parked.store(true, Ordering::Relaxed);
36 }
37
38 #[inline]
timed_out(&self) -> bool39 unsafe fn timed_out(&self) -> bool {
40 self.parked.load(Ordering::Relaxed) != false
41 }
42
43 #[inline]
park(&self)44 unsafe fn park(&self) {
45 while self.parked.load(Ordering::Acquire) != false {
46 spin_loop();
47 }
48 }
49
50 #[inline]
park_until(&self, timeout: Instant) -> bool51 unsafe fn park_until(&self, timeout: Instant) -> bool {
52 while self.parked.load(Ordering::Acquire) != false {
53 if Instant::now() >= timeout {
54 return false;
55 }
56 spin_loop();
57 }
58 true
59 }
60
61 #[inline]
unpark_lock(&self) -> UnparkHandle62 unsafe fn unpark_lock(&self) -> UnparkHandle {
63 // We don't need to lock anything, just clear the state
64 self.parked.store(false, Ordering::Release);
65 UnparkHandle(())
66 }
67 }
68
69 pub struct UnparkHandle(());
70
71 impl super::UnparkHandleT for UnparkHandle {
72 #[inline]
unpark(self)73 unsafe fn unpark(self) {}
74 }
75
76 #[inline]
thread_yield()77 pub fn thread_yield() {
78 thread::yield_now();
79 }
80