xref: /DragonOS/kernel/src/time/sleep.rs (revision 91e9d4ab55ef960f57a1b6287bc523ca4341f67a)
14fda81ceSLoGin use core::hint::spin_loop;
2bacd691cSlogin 
3bacd691cSlogin use alloc::{boxed::Box, sync::Arc};
4*91e9d4abSLoGin use system_error::SystemError;
5bacd691cSlogin 
6bacd691cSlogin use crate::{
74fda81ceSLoGin     arch::{sched::sched, CurrentIrqArch, CurrentTimeArch},
8ab5c8ca4Slogin     exception::InterruptArch,
9ab5c8ca4Slogin     include::bindings::bindings::{useconds_t, Cpu_tsc_freq},
101496ba7bSLoGin     process::ProcessManager,
118612b6ceSLoGin     time::timekeeping::getnstimeofday,
12bacd691cSlogin };
13bacd691cSlogin 
14bacd691cSlogin use super::{
15bacd691cSlogin     timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper},
164fda81ceSLoGin     TimeArch, TimeSpec,
17bacd691cSlogin };
18bacd691cSlogin 
19bacd691cSlogin /// @brief 休眠指定时间(单位:纳秒)
20bacd691cSlogin ///
21bacd691cSlogin /// @param sleep_time 指定休眠的时间
22bacd691cSlogin ///
23bacd691cSlogin /// @return Ok(TimeSpec) 剩余休眠时间
24bacd691cSlogin ///
25bacd691cSlogin /// @return Err(SystemError) 错误码
26ab5c8ca4Slogin pub fn nanosleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
27bacd691cSlogin     if sleep_time.tv_nsec < 0 || sleep_time.tv_nsec >= 1000000000 {
28bacd691cSlogin         return Err(SystemError::EINVAL);
29bacd691cSlogin     }
30bacd691cSlogin     // 对于小于500us的时间,使用spin/rdtsc来进行定时
318612b6ceSLoGin     if sleep_time.tv_nsec < 500000 && sleep_time.tv_sec == 0 {
324fda81ceSLoGin         let expired_tsc: u64 = unsafe {
334fda81ceSLoGin             CurrentTimeArch::get_cycles() as u64
344fda81ceSLoGin                 + (sleep_time.tv_nsec as u64 * Cpu_tsc_freq) / 1000000000
354fda81ceSLoGin         };
364fda81ceSLoGin         while (CurrentTimeArch::get_cycles() as u64) < expired_tsc {
37bacd691cSlogin             spin_loop()
38bacd691cSlogin         }
39bacd691cSlogin         return Ok(TimeSpec {
40bacd691cSlogin             tv_sec: 0,
41bacd691cSlogin             tv_nsec: 0,
42bacd691cSlogin         });
43bacd691cSlogin     }
448612b6ceSLoGin 
458612b6ceSLoGin     let total_sleep_time_us: u64 =
468612b6ceSLoGin         sleep_time.tv_sec as u64 * 1000000 + sleep_time.tv_nsec as u64 / 1000;
47bacd691cSlogin     // 创建定时器
481496ba7bSLoGin     let handler: Box<WakeUpHelper> = WakeUpHelper::new(ProcessManager::current_pcb());
498612b6ceSLoGin     let timer: Arc<Timer> = Timer::new(handler, next_n_us_timer_jiffies(total_sleep_time_us));
50bacd691cSlogin 
51ab5c8ca4Slogin     let irq_guard: crate::exception::IrqFlagsGuard =
52ab5c8ca4Slogin         unsafe { CurrentIrqArch::save_and_disable_irq() };
531496ba7bSLoGin     ProcessManager::mark_sleep(true).ok();
548612b6ceSLoGin 
558612b6ceSLoGin     let start_time = getnstimeofday();
56bacd691cSlogin     timer.activate();
571496ba7bSLoGin 
58ab5c8ca4Slogin     drop(irq_guard);
59bacd691cSlogin     sched();
60bacd691cSlogin 
618612b6ceSLoGin     let end_time = getnstimeofday();
628612b6ceSLoGin     // 返回正确的剩余时间
638612b6ceSLoGin     let real_sleep_time = end_time - start_time;
648612b6ceSLoGin     let rm_time: TimeSpec = (sleep_time - real_sleep_time.into()).into();
65bacd691cSlogin 
668612b6ceSLoGin     return Ok(rm_time);
67bacd691cSlogin }
68bacd691cSlogin 
69bacd691cSlogin /// @brief 休眠指定时间(单位:微秒)
70bacd691cSlogin ///
71bacd691cSlogin ///  @param usec 微秒
72bacd691cSlogin ///
73bacd691cSlogin /// @return Ok(TimeSpec) 剩余休眠时间
74bacd691cSlogin ///
75bacd691cSlogin /// @return Err(SystemError) 错误码
76ab5c8ca4Slogin pub fn usleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
77ab5c8ca4Slogin     match nanosleep(sleep_time) {
78bacd691cSlogin         Ok(value) => return Ok(value),
79bacd691cSlogin         Err(err) => return Err(err),
80bacd691cSlogin     };
81bacd691cSlogin }
82bacd691cSlogin 
83bacd691cSlogin //===== 以下为提供给C的接口 =====
84bacd691cSlogin 
85bacd691cSlogin /// @brief 休眠指定时间(单位:微秒)(提供给C的接口)
86bacd691cSlogin ///
87bacd691cSlogin ///  @param usec 微秒
88bacd691cSlogin ///
89bacd691cSlogin /// @return Ok(i32) 0
90bacd691cSlogin ///
91bacd691cSlogin /// @return Err(SystemError) 错误码
92bacd691cSlogin #[no_mangle]
93bacd691cSlogin pub extern "C" fn rs_usleep(usec: useconds_t) -> i32 {
94bacd691cSlogin     let sleep_time = TimeSpec {
95bacd691cSlogin         tv_sec: (usec / 1000000) as i64,
96bacd691cSlogin         tv_nsec: ((usec % 1000000) * 1000) as i64,
97bacd691cSlogin     };
98ab5c8ca4Slogin     match usleep(sleep_time) {
99bacd691cSlogin         Ok(_) => {
100bacd691cSlogin             return 0;
101bacd691cSlogin         }
102bacd691cSlogin         Err(err) => {
103bacd691cSlogin             return err.to_posix_errno();
104bacd691cSlogin         }
105bacd691cSlogin     };
106bacd691cSlogin }
107