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 //! Wakes tasks to wake up 15 16 use crate::sync::semaphore_inner::SemaphoreInner; 17 18 /// Wakes one or multiple tasks to wake up. 19 /// 20 /// `Waiter` itself does not protect any data. Its only purpose is to signal 21 /// other tasks to perform an operation. 22 /// 23 /// # Examples 24 /// 25 /// ``` 26 /// use std::sync::Arc; 27 /// 28 /// use ylong_runtime::sync::waiter::Waiter; 29 /// 30 /// let waiter = Arc::new(Waiter::new()); 31 /// let waiter2 = waiter.clone(); 32 /// 33 /// let _ = ylong_runtime::block_on(async { 34 /// let handle = ylong_runtime::spawn(async move { 35 /// waiter2.wait().await; 36 /// }); 37 /// waiter.wake_one(); 38 /// let _ = handle.await; 39 /// }); 40 /// ``` 41 pub struct Waiter { 42 sem: SemaphoreInner, 43 } 44 45 impl Waiter { 46 /// Creates a new Waiter. 47 /// 48 /// # Examples 49 /// 50 /// ``` 51 /// use ylong_runtime::sync::waiter::Waiter; 52 /// 53 /// let waiter = Waiter::new(); 54 /// ``` 55 // Prevent to increase binary size and thus mask this warning. 56 #[allow(clippy::new_without_default)] new() -> Waiter57 pub fn new() -> Waiter { 58 Waiter { 59 // bounded by permit::max 60 sem: SemaphoreInner::new(0).unwrap(), 61 } 62 } 63 64 /// Asynchronously waits for this Waiter to get signaled. 65 /// 66 /// # Examples 67 /// 68 /// ``` 69 /// use std::sync::Arc; 70 /// 71 /// use ylong_runtime::sync::waiter::Waiter; 72 /// 73 /// let waiter = Arc::new(Waiter::new()); 74 /// let waiter2 = waiter.clone(); 75 /// let _ = ylong_runtime::block_on(async { 76 /// let handle = ylong_runtime::spawn(async move { 77 /// waiter2.wait().await; 78 /// }); 79 /// waiter.wake_one(); 80 /// let _ = handle.await; 81 /// }); 82 /// ``` wait(&self)83 pub async fn wait(&self) { 84 // The result of `acquire()` will be `Err()` only when the semaphore is closed. 85 // `Waiter` will not close, so the result of `acquire()` must be `Ok(())`. 86 self.sem.acquire().await.unwrap(); 87 } 88 89 /// Notifies one task waiting on it. 90 /// 91 /// If this method gets called when there is no task waiting on this Waiter, 92 /// then the next task called `wait` on it will not get blocked. 93 /// 94 /// If this method gets called multiple times, only one task will get passed 95 /// straightly when calling `wait`. Any other task still has to 96 /// asynchronously wait for it to be released. 97 /// 98 /// 99 /// # Examples 100 /// 101 /// ``` 102 /// use std::sync::Arc; 103 /// 104 /// use ylong_runtime::sync::waiter::Waiter; 105 /// 106 /// let waiter = Arc::new(Waiter::new()); 107 /// let waiter2 = waiter.clone(); 108 /// let _ = ylong_runtime::block_on(async { 109 /// let handle = ylong_runtime::spawn(async move { 110 /// waiter2.wait().await; 111 /// }); 112 /// waiter.wake_one(); 113 /// let _ = handle.await; 114 /// }); 115 /// ``` wake_one(&self)116 pub fn wake_one(&self) { 117 self.sem.release_notify(); 118 } 119 120 /// Notifies all tasks waiting on it. 121 /// 122 /// Unlike `wake_one`, if this method gets called when there is no task 123 /// waiting on this wake, then the next task called `wait` on it will 124 /// `still` get blocked. 125 /// 126 /// # Examples 127 /// 128 /// ```no run 129 /// use std::sync::Arc; 130 /// use ylong_runtime::sync::waiter::Waiter; 131 /// 132 /// let waiter = Arc::new(Waiter::new()); 133 /// let waiter2 = waiter.clone(); 134 /// let waiter3 = waiter.clone(); 135 /// let _ = ylong_runtime::block_on(async { 136 /// let handle = ylong_runtime::spawn(async move { 137 /// waiter2.wait().await; 138 /// }); 139 /// let handle2 = ylong_runtime::spawn(async move { 140 /// waiter3.wait().await; 141 /// }); 142 /// waiter.wake_all(); 143 /// }); 144 /// ``` wake_all(&self)145 pub fn wake_all(&self) { 146 self.sem.release_all(); 147 } 148 } 149