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 use core::{
9 arch::wasm32,
10 sync::atomic::{AtomicI32, Ordering},
11 };
12 use std::time::{Duration, Instant};
13 use std::{convert::TryFrom, thread};
14
15 // Helper type for putting a thread to sleep until some other thread wakes it up
16 pub struct ThreadParker {
17 parked: AtomicI32,
18 }
19
20 const UNPARKED: i32 = 0;
21 const PARKED: i32 = 1;
22
23 impl super::ThreadParkerT for ThreadParker {
24 type UnparkHandle = UnparkHandle;
25
26 const IS_CHEAP_TO_CONSTRUCT: bool = true;
27
28 #[inline]
new() -> ThreadParker29 fn new() -> ThreadParker {
30 ThreadParker {
31 parked: AtomicI32::new(UNPARKED),
32 }
33 }
34
35 #[inline]
prepare_park(&self)36 unsafe fn prepare_park(&self) {
37 self.parked.store(PARKED, Ordering::Relaxed);
38 }
39
40 #[inline]
timed_out(&self) -> bool41 unsafe fn timed_out(&self) -> bool {
42 self.parked.load(Ordering::Relaxed) == PARKED
43 }
44
45 #[inline]
park(&self)46 unsafe fn park(&self) {
47 while self.parked.load(Ordering::Acquire) == PARKED {
48 let r = wasm32::memory_atomic_wait32(self.ptr(), PARKED, -1);
49 // we should have either woken up (0) or got a not-equal due to a
50 // race (1). We should never time out (2)
51 debug_assert!(r == 0 || r == 1);
52 }
53 }
54
55 #[inline]
park_until(&self, timeout: Instant) -> bool56 unsafe fn park_until(&self, timeout: Instant) -> bool {
57 while self.parked.load(Ordering::Acquire) == PARKED {
58 if let Some(left) = timeout.checked_duration_since(Instant::now()) {
59 let nanos_left = i64::try_from(left.as_nanos()).unwrap_or(i64::max_value());
60 let r = wasm32::memory_atomic_wait32(self.ptr(), PARKED, nanos_left);
61 debug_assert!(r == 0 || r == 1 || r == 2);
62 } else {
63 return false;
64 }
65 }
66 true
67 }
68
69 #[inline]
unpark_lock(&self) -> UnparkHandle70 unsafe fn unpark_lock(&self) -> UnparkHandle {
71 // We don't need to lock anything, just clear the state
72 self.parked.store(UNPARKED, Ordering::Release);
73 UnparkHandle(self.ptr())
74 }
75 }
76
77 impl ThreadParker {
78 #[inline]
ptr(&self) -> *mut i3279 fn ptr(&self) -> *mut i32 {
80 &self.parked as *const AtomicI32 as *mut i32
81 }
82 }
83
84 pub struct UnparkHandle(*mut i32);
85
86 impl super::UnparkHandleT for UnparkHandle {
87 #[inline]
unpark(self)88 unsafe fn unpark(self) {
89 let num_notified = wasm32::memory_atomic_notify(self.0 as *mut i32, 1);
90 debug_assert!(num_notified == 0 || num_notified == 1);
91 }
92 }
93
94 #[inline]
thread_yield()95 pub fn thread_yield() {
96 thread::yield_now();
97 }
98