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