• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::cell::RefCell;
15 use std::hint;
16 use std::sync::atomic::AtomicU8;
17 use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
18 use std::task::Waker;
19 
20 pub(crate) struct AtomicWaker {
21     state: AtomicU8,
22     waker: RefCell<Option<Waker>>,
23 }
24 
25 /// Idle state
26 const IDLE: u8 = 0;
27 
28 /// A new waker is registering.
29 const REGISTERING: u8 = 0b01;
30 
31 /// The waker is being woken.
32 const WAKING: u8 = 0b10;
33 
34 impl AtomicWaker {
new() -> Self35     pub(crate) fn new() -> Self {
36         Self {
37             state: AtomicU8::new(IDLE),
38             waker: RefCell::new(None),
39         }
40     }
41 
register_by_ref(&self, waker: &Waker)42     pub(crate) fn register_by_ref(&self, waker: &Waker) {
43         match self
44             .state
45             .compare_exchange(IDLE, REGISTERING, Acquire, Acquire)
46         {
47             Ok(IDLE) => {
48                 self.waker.borrow_mut().replace(waker.clone());
49 
50                 if self
51                     .state
52                     .compare_exchange(REGISTERING, IDLE, AcqRel, Acquire)
53                     .is_err()
54                 {
55                     // atomic waker has been waked or registered, therefore waker must exist
56                     let waker = self.waker.borrow_mut().take().unwrap();
57                     self.state.store(IDLE, Release);
58                     waker.wake();
59                 }
60             }
61             Err(WAKING) => {
62                 waker.wake_by_ref();
63                 hint::spin_loop();
64             }
65             // The state is REGISTERING or REGISTERING | WAKING.
66             _ => {}
67         }
68     }
69 
wake(&self)70     pub(crate) fn wake(&self) {
71         if let Some(waker) = self.take_waker() {
72             waker.wake();
73         }
74     }
75 
take_waker(&self) -> Option<Waker>76     pub(crate) fn take_waker(&self) -> Option<Waker> {
77         match self.state.fetch_or(WAKING, AcqRel) {
78             IDLE => {
79                 let waker = self.waker.borrow_mut().take();
80                 self.state.fetch_and(!WAKING, Release);
81                 waker
82             }
83             // The state is REGISTERING or REGISTERING | WAKING or WAKING.
84             _ => None,
85         }
86     }
87 }
88 
89 unsafe impl Send for AtomicWaker {}
90 unsafe impl Sync for AtomicWaker {}
91