]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/cloudabi/condvar.rs
Rollup merge of #77334 - pickfire:patch-4, r=jyn514
[rust.git] / library / std / src / sys / cloudabi / condvar.rs
1 use crate::mem;
2 use crate::sync::atomic::{AtomicU32, Ordering};
3 use crate::sys::cloudabi::abi;
4 use crate::sys::mutex::{self, Mutex};
5 use crate::sys::time::checked_dur2intervals;
6 use crate::time::Duration;
7
8 extern "C" {
9     #[thread_local]
10     static __pthread_thread_id: abi::tid;
11 }
12
13 pub struct Condvar {
14     condvar: AtomicU32,
15 }
16
17 pub type MovableCondvar = Condvar;
18
19 unsafe impl Send for Condvar {}
20 unsafe impl Sync for Condvar {}
21
22 impl Condvar {
23     pub const fn new() -> Condvar {
24         Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) }
25     }
26
27     pub unsafe fn init(&mut self) {}
28
29     pub unsafe fn notify_one(&self) {
30         if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
31             let ret = abi::condvar_signal(
32                 &self.condvar as *const AtomicU32 as *mut abi::condvar,
33                 abi::scope::PRIVATE,
34                 1,
35             );
36             assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable");
37         }
38     }
39
40     pub unsafe fn notify_all(&self) {
41         if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
42             let ret = abi::condvar_signal(
43                 &self.condvar as *const AtomicU32 as *mut abi::condvar,
44                 abi::scope::PRIVATE,
45                 abi::nthreads::MAX,
46             );
47             assert_eq!(ret, abi::errno::SUCCESS, "Failed to broadcast on condition variable");
48         }
49     }
50
51     pub unsafe fn wait(&self, mutex: &Mutex) {
52         let mutex = mutex::raw(mutex);
53         assert_eq!(
54             mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
55             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
56             "This lock is not write-locked by this thread"
57         );
58
59         // Call into the kernel to wait on the condition variable.
60         let subscription = abi::subscription {
61             type_: abi::eventtype::CONDVAR,
62             union: abi::subscription_union {
63                 condvar: abi::subscription_condvar {
64                     condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
65                     condvar_scope: abi::scope::PRIVATE,
66                     lock: mutex as *const AtomicU32 as *mut abi::lock,
67                     lock_scope: abi::scope::PRIVATE,
68                 },
69             },
70             ..mem::zeroed()
71         };
72         let mut event: mem::MaybeUninit<abi::event> = mem::MaybeUninit::uninit();
73         let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit();
74         let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, nevents.as_mut_ptr());
75         assert_eq!(ret, abi::errno::SUCCESS, "Failed to wait on condition variable");
76         assert_eq!(
77             event.assume_init().error,
78             abi::errno::SUCCESS,
79             "Failed to wait on condition variable"
80         );
81     }
82
83     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
84         let mutex = mutex::raw(mutex);
85         assert_eq!(
86             mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
87             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
88             "This lock is not write-locked by this thread"
89         );
90
91         // Call into the kernel to wait on the condition variable.
92         let timeout =
93             checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds");
94         let subscriptions = [
95             abi::subscription {
96                 type_: abi::eventtype::CONDVAR,
97                 union: abi::subscription_union {
98                     condvar: abi::subscription_condvar {
99                         condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
100                         condvar_scope: abi::scope::PRIVATE,
101                         lock: mutex as *const AtomicU32 as *mut abi::lock,
102                         lock_scope: abi::scope::PRIVATE,
103                     },
104                 },
105                 ..mem::zeroed()
106             },
107             abi::subscription {
108                 type_: abi::eventtype::CLOCK,
109                 union: abi::subscription_union {
110                     clock: abi::subscription_clock {
111                         clock_id: abi::clockid::MONOTONIC,
112                         timeout,
113                         ..mem::zeroed()
114                     },
115                 },
116                 ..mem::zeroed()
117             },
118         ];
119         let mut events: [mem::MaybeUninit<abi::event>; 2] = [mem::MaybeUninit::uninit(); 2];
120         let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit();
121         let ret = abi::poll(
122             subscriptions.as_ptr(),
123             mem::MaybeUninit::slice_as_mut_ptr(&mut events),
124             2,
125             nevents.as_mut_ptr(),
126         );
127         assert_eq!(ret, abi::errno::SUCCESS, "Failed to wait on condition variable");
128         let nevents = nevents.assume_init();
129         for i in 0..nevents {
130             assert_eq!(
131                 events[i].assume_init().error,
132                 abi::errno::SUCCESS,
133                 "Failed to wait on condition variable"
134             );
135             if events[i].assume_init().type_ == abi::eventtype::CONDVAR {
136                 return true;
137             }
138         }
139         false
140     }
141
142     pub unsafe fn destroy(&self) {
143         assert_eq!(
144             self.condvar.load(Ordering::Relaxed),
145             abi::CONDVAR_HAS_NO_WAITERS.0,
146             "Attempted to destroy a condition variable with blocked threads"
147         );
148     }
149 }