• 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                 match self
51                     .state
52                     .compare_exchange(REGISTERING, IDLE, AcqRel, Acquire)
53                 {
54                     Ok(_) => {}
55                     // The state is REGISTERING | WAKING.
56                     Err(_) => {
57                         let waker = self.waker.borrow_mut().take().unwrap();
58                         self.state.store(IDLE, Release);
59                         waker.wake();
60                     }
61                 }
62             }
63             Err(WAKING) => {
64                 waker.wake_by_ref();
65                 hint::spin_loop();
66             }
67             // The state is REGISTERING or REGISTERING | WAKING.
68             _ => {}
69         }
70     }
71 
wake(&self)72     pub(crate) fn wake(&self) {
73         if let Some(waker) = self.take_waker() {
74             waker.wake();
75         }
76     }
77 
take_waker(&self) -> Option<Waker>78     pub(crate) fn take_waker(&self) -> Option<Waker> {
79         match self.state.fetch_or(WAKING, AcqRel) {
80             IDLE => {
81                 let waker = self.waker.borrow_mut().take();
82                 self.state.fetch_and(!WAKING, Release);
83                 waker
84             }
85             // The state is REGISTERING or REGISTERING | WAKING or WAKING.
86             _ => None,
87         }
88     }
89 }
90 
91 unsafe impl Send for AtomicWaker {}
92 unsafe impl Sync for AtomicWaker {}
93