• 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::convert::TryInto;
15 use std::future::Future;
16 use std::pin::Pin;
17 use std::task::{Context, Poll};
18 use std::time::{Duration, Instant};
19 
20 const TEN_YEARS: Duration = Duration::from_secs(86400 * 365 * 10);
21 
22 /// Waits until 'instant' has reached.
23 ///
24 /// # Panic
25 /// Calling this method outside of a Ylong Runtime could cause panic, for
26 /// example, outside of an async closure that is passed to ylong_runtime::spawn
27 /// or ylong_runtime::block_on. The async wrapping is necessary since it makes
28 /// the function become lazy in order to get successfully executed on the
29 /// runtime.
sleep_until(instant: Instant) -> Sleep30 pub fn sleep_until(instant: Instant) -> Sleep {
31     Sleep::new_timeout(instant)
32 }
33 
34 /// Waits until 'duration' has elapsed.
35 ///
36 /// # Panic
37 /// Calling this method outside of a Ylong Runtime could cause panic, for
38 /// example, outside of an async closure that is passed to ylong_runtime::spawn
39 /// or ylong_runtime::block_on. The async wrapping is necessary since it makes
40 /// the function become lazy in order to get successfully executed on the
41 /// runtime.
sleep(duration: Duration) -> Sleep42 pub fn sleep(duration: Duration) -> Sleep {
43     // If the time reaches the maximum value,
44     // then set the default timing time to 10 years.
45     match Instant::now().checked_add(duration) {
46         Some(deadline) => Sleep::new_timeout(deadline),
47         None => Sleep::new_timeout(Instant::now() + TEN_YEARS),
48     }
49 }
50 
51 /// A structure that implements Future. returned by func [`sleep`].
52 ///
53 /// [`sleep`]: sleep
54 /// # Examples
55 ///
56 /// ```
57 /// use std::time::Duration;
58 ///
59 /// use ylong_runtime::time::sleep;
60 ///
61 /// async fn sleep_test() {
62 ///     let sleep = sleep(Duration::from_secs(2)).await;
63 ///     println!("2 secs have elapsed");
64 /// }
65 /// ```
66 pub struct Sleep {
67     // During the polling of this structure, no repeated insertion.
68     need_insert: bool,
69 
70     // The time at which the structure should end.
71     deadline: Instant,
72 
73     inner: SleepInner,
74 }
75 
76 cfg_ffrt!(
77     use crate::ffrt::ffrt_timer::FfrtTimerEntry;
78     use std::task::Waker;
79 
80     struct SleepInner {
81         // ffrt timer handle
82         timer: Option<FfrtTimerEntry>,
83         // the waker to wakeup the timer task
84         waker: Option<*mut Waker>,
85     }
86 
87     // FFRT needs this unsafe impl since `Sleep` has a mut pointer in it.
88     // In non-ffrt environment, `Sleep` auto-derives Sync & Send.
89     unsafe impl Send for Sleep {}
90     unsafe impl Sync for Sleep {}
91 
92     impl Sleep {
93         // Creates a Sleep structure based on the given deadline.
94         fn new_timeout(deadline: Instant) -> Self {
95             Self {
96                 need_insert: true,
97                 deadline,
98                 inner: SleepInner {
99                     timer: None,
100                     waker: None,
101                 }
102             }
103         }
104 
105         // Resets the deadline of the Sleep
106         pub(crate) fn reset(&mut self, new_deadline: Instant) {
107             self.need_insert = true;
108             self.deadline = new_deadline;
109 
110             if let Some(waker) = self.inner.waker.take() {
111                 unsafe {
112                     drop(Box::from_raw(waker as *mut Waker));
113                 }
114             }
115         }
116 
117         // Cancels the Sleep
118         fn cancel(&mut self) {
119             if let Some(timer) = self.inner.timer.take() {
120                 timer.timer_deregister();
121             }
122             if let Some(waker) = self.inner.waker.take() {
123                 unsafe {
124                     drop(Box::from_raw(waker as *mut Waker));
125                 }
126             }
127         }
128     }
129 
130     impl Future for Sleep {
131         type Output = ();
132 
133         fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
134             let this = self.get_mut();
135 
136             if this.need_insert {
137                 if let Some(duration) = this.deadline.checked_duration_since(Instant::now()) {
138                     let ms = duration.as_millis()
139                     .try_into()
140                     .unwrap_or(u64::MAX);
141 
142                     let waker = Box::new(cx.waker().clone());
143                     let waker_ptr = Box::into_raw(waker);
144 
145                     if let Some(waker) = this.inner.waker.take() {
146                         unsafe { drop(Box::from_raw(waker as *mut Waker)); }
147                     }
148 
149                     this.inner.waker = Some(waker_ptr);
150                     this.inner.timer = Some(FfrtTimerEntry::timer_register(waker_ptr, ms));
151                     this.need_insert = false;
152                 } else {
153                     return Poll::Ready(());
154                 }
155             }
156 
157             // this unwrap is safe since we have already insert the timer into the entry
158             let timer = this.inner.timer.as_ref().unwrap();
159             if timer.result() {
160                 Poll::Ready(())
161             } else {
162                 Poll::Pending
163             }
164         }
165     }
166 );
167 
168 impl Sleep {
169     // Returns the deadline of the Sleep
deadline(&self) -> Instant170     pub(crate) fn deadline(&self) -> Instant {
171         self.deadline
172     }
173 }
174 
175 cfg_not_ffrt!(
176     use crate::executor::driver::Handle;
177     use crate::time::Clock;
178     use std::sync::Arc;
179     use std::cmp;
180     use std::ptr::NonNull;
181 
182     struct SleepInner {
183         // Corresponding Timer structure.
184         timer: Clock,
185         // Timer driver handle
186         handle: Arc<Handle>,
187     }
188 
189     impl Sleep {
190         // Creates a Sleep structure based on the given deadline.
191         fn new_timeout(deadline: Instant) -> Self {
192             let handle = Handle::get_handle().expect("sleep new out of worker ctx");
193 
194             let start_time = handle.start_time();
195             let deadline = cmp::max(deadline, start_time);
196 
197             let timer = Clock::new();
198             Self {
199                 need_insert: true,
200                 deadline,
201                 inner: SleepInner {
202                     timer,
203                     handle,
204                 }
205             }
206         }
207 
208         // Resets the deadline of the Sleep
209         pub(crate) fn reset(&mut self, new_deadline: Instant) {
210             self.need_insert = true;
211             self.deadline = new_deadline;
212             self.inner.timer.set_result(false);
213         }
214 
215         // Cancels the Sleep
216         fn cancel(&mut self) {
217             let driver = &self.inner.handle;
218             driver.timer_cancel(NonNull::from(&self.inner.timer));
219         }
220     }
221 
222     impl Future for Sleep {
223         type Output = ();
224 
225         fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
226             let this = self.get_mut();
227             let driver = &this.inner.handle;
228 
229             if this.need_insert {
230                 let ms = this
231                     .deadline
232                     .checked_duration_since(driver.start_time())
233                     .unwrap()
234                     .as_millis()
235                     .try_into()
236                     .unwrap_or(u64::MAX);
237                 this.inner.timer.set_expiration(ms);
238                 this.inner.timer.set_waker(cx.waker().clone());
239 
240                 match driver.timer_register(NonNull::from(&this.inner.timer)) {
241                     Ok(_) => this.need_insert = false,
242                     Err(_) => {
243                         // Even if the insertion fails, there is no need to insert again here,
244                         // it is a timeout clock and needs to be triggered immediately at the next poll.
245                         this.need_insert = false;
246                         this.inner.timer.set_result(true);
247                     }
248                 }
249             }
250 
251             if this.inner.timer.result() {
252                 Poll::Ready(())
253             } else {
254                 Poll::Pending
255             }
256         }
257     }
258 );
259 
260 impl Drop for Sleep {
drop(&mut self)261     fn drop(&mut self) {
262         // For some uses, for example, Timeout,
263         // `Sleep` enters the `Pending` state first and inserts the `TimerHandle` into
264         // the `DRIVER`, the future of timeout returns `Ready` in advance of the
265         // next polling, as a result, the `TimerHandle` pointer in the `DRIVER`
266         // is invalid. need to cancel the `TimerHandle` operation during `Sleep`
267         // drop.
268         self.cancel()
269     }
270 }
271 
272 #[cfg(test)]
273 mod test {
274     use std::time::Duration;
275 
276     use crate::time::sleep;
277     use crate::{block_on, spawn};
278 
279     /// UT test cases for new_sleep
280     ///
281     /// # Brief
282     /// 1. Uses sleep to create a Sleep Struct.
283     /// 2. Uses block_on to test different sleep duration.
284     #[test]
new_timer_sleep()285     fn new_timer_sleep() {
286         block_on(async move {
287             sleep(Duration::new(0, 20_000_000)).await;
288             sleep(Duration::new(0, 20_000_000)).await;
289             sleep(Duration::new(0, 20_000_000)).await;
290         });
291 
292         let handle_one = spawn(async {
293             sleep(Duration::new(0, 20_000_000)).await;
294         });
295         let handle_two = spawn(async {
296             sleep(Duration::new(0, 20_000_000)).await;
297         });
298         let handle_three = spawn(async {
299             sleep(Duration::new(0, 20_000_000)).await;
300         });
301         block_on(handle_one).unwrap();
302         block_on(handle_two).unwrap();
303         block_on(handle_three).unwrap();
304     }
305 }
306