xref: /DragonOS/kernel/src/time/sleep.rs (revision ab5c8ca46db8e7d4793a9791292122b0b9684274)
1*ab5c8ca4Slogin use core::{arch::x86_64::_rdtsc, hint::spin_loop};
2bacd691cSlogin 
3bacd691cSlogin use alloc::{boxed::Box, sync::Arc};
4bacd691cSlogin 
5bacd691cSlogin use crate::{
6bacd691cSlogin     arch::{
7bacd691cSlogin         asm::current::current_pcb,
8bacd691cSlogin         sched::sched,
9*ab5c8ca4Slogin         CurrentIrqArch,
10bacd691cSlogin     },
11*ab5c8ca4Slogin     exception::InterruptArch,
12*ab5c8ca4Slogin     include::bindings::bindings::{useconds_t, Cpu_tsc_freq},
13bacd691cSlogin     syscall::SystemError,
14bacd691cSlogin };
15bacd691cSlogin 
16bacd691cSlogin use super::{
17bacd691cSlogin     timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper},
18bacd691cSlogin     TimeSpec,
19bacd691cSlogin };
20bacd691cSlogin 
21bacd691cSlogin /// @brief 休眠指定时间(单位:纳秒)
22bacd691cSlogin ///
23bacd691cSlogin /// @param sleep_time 指定休眠的时间
24bacd691cSlogin ///
25bacd691cSlogin /// @return Ok(TimeSpec) 剩余休眠时间
26bacd691cSlogin ///
27bacd691cSlogin /// @return Err(SystemError) 错误码
28*ab5c8ca4Slogin pub fn nanosleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
29bacd691cSlogin     if sleep_time.tv_nsec < 0 || sleep_time.tv_nsec >= 1000000000 {
30bacd691cSlogin         return Err(SystemError::EINVAL);
31bacd691cSlogin     }
32bacd691cSlogin     // 对于小于500us的时间,使用spin/rdtsc来进行定时
33bacd691cSlogin 
34bacd691cSlogin     if sleep_time.tv_nsec < 500000 {
35bacd691cSlogin         let expired_tsc: u64 =
36bacd691cSlogin             unsafe { _rdtsc() + (sleep_time.tv_nsec as u64 * Cpu_tsc_freq) / 1000000000 };
37bacd691cSlogin         while unsafe { _rdtsc() } < expired_tsc {
38bacd691cSlogin             spin_loop()
39bacd691cSlogin         }
40bacd691cSlogin         return Ok(TimeSpec {
41bacd691cSlogin             tv_sec: 0,
42bacd691cSlogin             tv_nsec: 0,
43bacd691cSlogin         });
44bacd691cSlogin     }
45bacd691cSlogin     // 创建定时器
46bacd691cSlogin     let handler: Box<WakeUpHelper> = WakeUpHelper::new(current_pcb());
47bacd691cSlogin     let timer: Arc<Timer> = Timer::new(
48bacd691cSlogin         handler,
49bacd691cSlogin         next_n_us_timer_jiffies((sleep_time.tv_nsec / 1000) as u64),
50bacd691cSlogin     );
51bacd691cSlogin 
52*ab5c8ca4Slogin     let irq_guard: crate::exception::IrqFlagsGuard =
53*ab5c8ca4Slogin         unsafe { CurrentIrqArch::save_and_disable_irq() };
54bacd691cSlogin     timer.activate();
55bacd691cSlogin     unsafe {
56bacd691cSlogin         current_pcb().mark_sleep_interruptible();
57bacd691cSlogin     }
58*ab5c8ca4Slogin     drop(irq_guard);
59bacd691cSlogin 
60bacd691cSlogin     sched();
61bacd691cSlogin 
62bacd691cSlogin     // TODO: 增加信号唤醒的功能后,返回正确的剩余时间
63bacd691cSlogin 
64bacd691cSlogin     return Ok(TimeSpec {
65bacd691cSlogin         tv_sec: 0,
66bacd691cSlogin         tv_nsec: 0,
67bacd691cSlogin     });
68bacd691cSlogin }
69bacd691cSlogin 
70bacd691cSlogin /// @brief 休眠指定时间(单位:微秒)
71bacd691cSlogin ///
72bacd691cSlogin ///  @param usec 微秒
73bacd691cSlogin ///
74bacd691cSlogin /// @return Ok(TimeSpec) 剩余休眠时间
75bacd691cSlogin ///
76bacd691cSlogin /// @return Err(SystemError) 错误码
77*ab5c8ca4Slogin pub fn usleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
78*ab5c8ca4Slogin     match nanosleep(sleep_time) {
79bacd691cSlogin         Ok(value) => return Ok(value),
80bacd691cSlogin         Err(err) => return Err(err),
81bacd691cSlogin     };
82bacd691cSlogin }
83bacd691cSlogin 
84bacd691cSlogin //===== 以下为提供给C的接口 =====
85bacd691cSlogin 
86bacd691cSlogin /// @brief 休眠指定时间(单位:微秒)(提供给C的接口)
87bacd691cSlogin ///
88bacd691cSlogin ///  @param usec 微秒
89bacd691cSlogin ///
90bacd691cSlogin /// @return Ok(i32) 0
91bacd691cSlogin ///
92bacd691cSlogin /// @return Err(SystemError) 错误码
93bacd691cSlogin #[no_mangle]
94bacd691cSlogin pub extern "C" fn rs_usleep(usec: useconds_t) -> i32 {
95bacd691cSlogin     let sleep_time = TimeSpec {
96bacd691cSlogin         tv_sec: (usec / 1000000) as i64,
97bacd691cSlogin         tv_nsec: ((usec % 1000000) * 1000) as i64,
98bacd691cSlogin     };
99*ab5c8ca4Slogin     match usleep(sleep_time) {
100bacd691cSlogin         Ok(_) => {
101bacd691cSlogin             return 0;
102bacd691cSlogin         }
103bacd691cSlogin         Err(err) => {
104bacd691cSlogin             return err.to_posix_errno();
105bacd691cSlogin         }
106bacd691cSlogin     };
107bacd691cSlogin }
108