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::future::Future;
15 use std::pin::Pin;
16 use std::task::{Context, Poll};
17 use std::time::{Duration, Instant};
18 
19 use crate::futures::poll_fn;
20 use crate::time::sleep::{sleep_until, Sleep};
21 
22 const TEN_YEARS: Duration = Duration::from_secs(86400 * 365 * 10);
23 
24 /// Creates new [`Timer`] that yields with interval of `period`. The first task
25 /// starts immediately.
26 ///
27 /// # Examples
28 ///
29 /// ```
30 /// use std::time::Duration;
31 ///
32 /// use ylong_runtime::time;
33 ///
34 /// async fn timer_test() {
35 ///     let mut timer = time::timer(Duration::from_millis(10));
36 ///     // ticks immediately
37 ///     timer.next_period().await;
38 ///     // ticks after 10 ms
39 ///     timer.next_period().await;
40 ///     // ticks after 10 ms
41 ///     timer.next_period().await;
42 /// }
43 ///
44 /// let handle = ylong_runtime::spawn(timer_test());
45 /// ylong_runtime::block_on(handle).unwrap();
46 /// ```
timer(period: Duration) -> Timer47 pub fn timer(period: Duration) -> Timer {
48     timer_at(Instant::now(), period)
49 }
50 
51 /// Creates new [`Timer`] that yields with interval of `period`.
52 /// The first task starts at the `start` Instant.
53 ///
54 /// # Examples
55 ///
56 /// ```
57 /// use std::time::{Duration, Instant};
58 ///
59 /// use ylong_runtime::time;
60 ///
61 /// async fn timer_at_test() {
62 ///     let mut timer = time::timer_at(
63 ///         Instant::now() + Duration::from_millis(10),
64 ///         Duration::from_millis(30),
65 ///     );
66 ///     // ticks after 10 ms
67 ///     timer.next_period().await;
68 ///     // ticks after 30 ms
69 ///     timer.next_period().await;
70 ///     // ticks after 30 ms
71 ///     timer.next_period().await;
72 /// }
73 ///
74 /// let handle = ylong_runtime::spawn(timer_at_test());
75 /// ylong_runtime::block_on(handle).unwrap();
76 /// ```
timer_at(start: Instant, period: Duration) -> Timer77 pub fn timer_at(start: Instant, period: Duration) -> Timer {
78     let start = Box::pin(sleep_until(start));
79     Timer { start, period }
80 }
81 
82 /// Automatically executes closure every 'period' for 'repeat_time' times.
83 /// When 'repeat_time' is `None()`, the closure will executes until drop.
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// use std::sync::{Arc, Mutex};
89 /// use std::time::{Duration, Instant};
90 ///
91 /// use ylong_runtime::{block_on, spawn, time};
92 ///
93 /// let x = Arc::new(Mutex::new(0));
94 /// let xc = x.clone();
95 ///
96 /// let closure = move || {
97 ///     let mut a = xc.lock().unwrap();
98 ///     *a = *a + 1;
99 /// };
100 ///
101 /// let handle = spawn(time::periodic_schedule(
102 ///     closure,
103 ///     Some(3),
104 ///     Duration::from_millis(100),
105 /// ));
106 /// let _ = block_on(handle);
107 ///
108 /// let x = x.lock().unwrap();
109 /// assert_eq!(*x, 3);
110 /// ```
periodic_schedule<T>(mut closure: T, repeat_time: Option<usize>, period: Duration) where T: FnMut() + Send + 'static,111 pub async fn periodic_schedule<T>(mut closure: T, repeat_time: Option<usize>, period: Duration)
112 where
113     T: FnMut() + Send + 'static,
114 {
115     let mut timer = timer(period);
116     match repeat_time {
117         Some(times) => {
118             for _ in 0..times {
119                 closure();
120                 timer.next_period().await;
121             }
122         }
123         None => loop {
124             closure();
125             timer.next_period().await;
126         },
127     }
128 }
129 
130 /// Struct of Timer
131 pub struct Timer {
132     start: Pin<Box<Sleep>>,
133     period: Duration,
134 }
135 
136 impl Timer {
137     /// Waits until the next Instant reached.
next_period(&mut self) -> Instant138     pub async fn next_period(&mut self) -> Instant {
139         poll_fn(|cx| self.poll_next_period(cx)).await
140     }
141 
poll_next_period(&mut self, cx: &mut Context<'_>) -> Poll<Instant>142     fn poll_next_period(&mut self, cx: &mut Context<'_>) -> Poll<Instant> {
143         if Pin::new(&mut self.start).poll(cx).is_pending() {
144             return Poll::Pending;
145         }
146 
147         let deadline = self.start.deadline();
148         let next = match deadline.checked_add(self.period) {
149             Some(next_out) => next_out,
150             None => deadline + TEN_YEARS,
151         };
152 
153         self.start.as_mut().reset(next);
154 
155         Poll::Ready(next)
156     }
157 
158     /// Resets Timer from now on.
reset(&mut self)159     pub fn reset(&mut self) {
160         self.start.as_mut().reset(Instant::now() + self.period);
161     }
162 
163     /// Gets period
period(&self) -> Duration164     pub fn period(&self) -> Duration {
165         self.period
166     }
167 }
168 
169 #[cfg(test)]
170 mod test {
171     use std::sync::{Arc, Mutex};
172     use std::time::{Duration, Instant};
173 
174     use crate::time::sleep;
175     use crate::{block_on, spawn, time};
176 
177     /// UT test cases for new_timer
178     ///
179     /// # Brief
180     /// 1. Uses time to create a Timer Struct.
181     /// 2. Checks whether the period, reset, and timeout policy are correct.
182     #[test]
ut_new_timer()183     fn ut_new_timer() {
184         block_on(async move {
185             let mut timer = time::timer::timer(Duration::new(1, 0));
186 
187             assert_eq!(Duration::new(1, 0), timer.period());
188             timer.reset();
189             assert_eq!(Duration::new(1, 0), timer.period());
190         });
191     }
192 
193     /// UT test cases for new_timer_base
194     ///
195     /// # Brief
196     /// 1. Uses timer_at to create a Timer Struct.
197     /// 2. Uses tick() to wait until next Instant.
198     #[test]
ut_new_timer_base()199     fn ut_new_timer_base() {
200         let handle = spawn(async move {
201             let mut a = 0;
202             let mut timer = time::timer::timer_at(
203                 Instant::now() + Duration::new(0, 20_000_000),
204                 Duration::new(0, 20_000_000),
205             );
206             a += 1;
207             timer.next_period().await;
208             a += 1;
209             timer.next_period().await;
210             a += 1;
211             timer.next_period().await;
212             assert_eq!(a, 3);
213         });
214         block_on(handle).unwrap();
215     }
216 
217     /// UT test cases for new_timer_timeout
218     ///
219     /// # Brief
220     /// 1. Uses time to create a Timer Struct.
221     /// 2. Sets TimeoutPolicy as Delay.
222     /// 2. Uses tick() to wait until next Instant.
223     #[test]
ut_new_timer_timeout()224     fn ut_new_timer_timeout() {
225         let handle = spawn(async move {
226             let mut a = 0;
227             let mut timer = time::timer::timer_at(
228                 Instant::now() + Duration::from_millis(100),
229                 Duration::from_millis(100),
230             );
231             a += 1;
232             timer.next_period().await;
233             sleep(Duration::new(0, 300_000_000)).await;
234             a += 1;
235             timer.next_period().await;
236             a += 1;
237             timer.next_period().await;
238             assert_eq!(a, 3);
239         });
240         block_on(handle).unwrap();
241     }
242 
243     /// UT test cases for new_timer_schedule
244     ///
245     /// # Brief
246     /// 1. Creates a closure.
247     /// 2. Use period_schedule() to execute this closure for 10 times.
248     /// 3. Checks if result is correct.
249     #[test]
ut_new_timer_schedule()250     fn ut_new_timer_schedule() {
251         let x = Arc::new(Mutex::new(0));
252         let xc = x.clone();
253 
254         let closure = move || {
255             let mut a = xc.lock().unwrap();
256             *a += 1;
257         };
258 
259         let task = time::periodic_schedule(closure, Some(10), Duration::from_nanos(20_000_000));
260 
261         let handle = spawn(task);
262         let _ = block_on(handle);
263 
264         let x = x.lock().unwrap();
265         assert_eq!(*x, 10);
266     }
267 }
268