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