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 sem: SemaphoreInner::new(0).unwrap(), 60 } 61 } 62 63 /// Asynchronously waits for this Waiter to get signaled. 64 /// 65 /// # Examples 66 /// 67 /// ``` 68 /// use std::sync::Arc; 69 /// 70 /// use ylong_runtime::sync::waiter::Waiter; 71 /// 72 /// let waiter = Arc::new(Waiter::new()); 73 /// let waiter2 = waiter.clone(); 74 /// let _ = ylong_runtime::block_on(async { 75 /// let handle = ylong_runtime::spawn(async move { 76 /// waiter2.wait().await; 77 /// }); 78 /// waiter.wake_one(); 79 /// let _ = handle.await; 80 /// }); 81 /// ``` wait(&self)82 pub async fn wait(&self) { 83 // The result of `acquire()` will be `Err()` only when the semaphore is closed. 84 // `Waiter` will not close, so the result of `acquire()` must be `Ok(())`. 85 self.sem.acquire().await.unwrap(); 86 } 87 88 /// Notifies one task waiting on it. 89 /// 90 /// If this method gets called when there is no task waiting on this Waiter, 91 /// then the next task called `wait` on it will not get blocked. 92 /// 93 /// If this method gets called multiple times, only one task will get passed 94 /// straightly when calling `wait`. Any other task still has to 95 /// asynchronously wait for it to be released. 96 /// 97 /// 98 /// # Examples 99 /// 100 /// ``` 101 /// use std::sync::Arc; 102 /// 103 /// use ylong_runtime::sync::waiter::Waiter; 104 /// 105 /// let waiter = Arc::new(Waiter::new()); 106 /// let waiter2 = waiter.clone(); 107 /// let _ = ylong_runtime::block_on(async { 108 /// let handle = ylong_runtime::spawn(async move { 109 /// waiter2.wait().await; 110 /// }); 111 /// waiter.wake_one(); 112 /// let _ = handle.await; 113 /// }); 114 /// ``` wake_one(&self)115 pub fn wake_one(&self) { 116 self.sem.release_notify(); 117 } 118 119 /// Notifies all tasks waiting on it. 120 /// 121 /// Unlike `wake_one`, if this method gets called when there is no task 122 /// waiting on this wake, then the next task called `wait` on it will 123 /// `still` get blocked. 124 /// 125 /// # Examples 126 /// 127 /// ```no run 128 /// use std::sync::Arc; 129 /// use ylong_runtime::sync::waiter::Waiter; 130 /// 131 /// let waiter = Arc::new(Waiter::new()); 132 /// let waiter2 = waiter.clone(); 133 /// let waiter3 = waiter.clone(); 134 /// let _ = ylong_runtime::block_on(async { 135 /// let handle = ylong_runtime::spawn(async move { 136 /// waiter2.wait().await; 137 /// }); 138 /// let handle2 = ylong_runtime::spawn(async move { 139 /// waiter3.wait().await; 140 /// }); 141 /// waiter.wake_all(); 142 /// }); 143 /// ``` wake_all(&self)144 pub fn wake_all(&self) { 145 self.sem.release_all(); 146 } 147 } 148