1 use core::hint::spin_loop; 2 3 use alloc::{boxed::Box, sync::Arc}; 4 use system_error::SystemError; 5 6 use crate::{ 7 arch::{CurrentIrqArch, CurrentTimeArch}, 8 exception::InterruptArch, 9 process::ProcessManager, 10 sched::{schedule, SchedMode}, 11 time::timekeeping::getnstimeofday, 12 }; 13 14 use super::{ 15 timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper}, 16 PosixTimeSpec, TimeArch, 17 }; 18 19 /// @brief 休眠指定时间(单位:纳秒) 20 /// 21 /// @param sleep_time 指定休眠的时间 22 /// 23 /// @return Ok(TimeSpec) 剩余休眠时间 24 /// 25 /// @return Err(SystemError) 错误码 26 pub fn nanosleep(sleep_time: PosixTimeSpec) -> Result<PosixTimeSpec, SystemError> { 27 if sleep_time.tv_nsec < 0 || sleep_time.tv_nsec >= 1000000000 { 28 return Err(SystemError::EINVAL); 29 } 30 // 对于小于500us的时间,使用spin/rdtsc来进行定时 31 if sleep_time.tv_nsec < 500000 && sleep_time.tv_sec == 0 { 32 let expired_tsc: usize = CurrentTimeArch::cal_expire_cycles(sleep_time.tv_nsec as usize); 33 while CurrentTimeArch::get_cycles() < expired_tsc { 34 spin_loop() 35 } 36 return Ok(PosixTimeSpec { 37 tv_sec: 0, 38 tv_nsec: 0, 39 }); 40 } 41 42 let total_sleep_time_us: u64 = 43 sleep_time.tv_sec as u64 * 1000000 + sleep_time.tv_nsec as u64 / 1000; 44 // 创建定时器 45 let handler: Box<WakeUpHelper> = WakeUpHelper::new(ProcessManager::current_pcb()); 46 let timer: Arc<Timer> = Timer::new(handler, next_n_us_timer_jiffies(total_sleep_time_us)); 47 48 let irq_guard: crate::exception::IrqFlagsGuard = 49 unsafe { CurrentIrqArch::save_and_disable_irq() }; 50 ProcessManager::mark_sleep(true).ok(); 51 52 let start_time = getnstimeofday(); 53 timer.activate(); 54 55 drop(irq_guard); 56 schedule(SchedMode::SM_NONE); 57 58 let end_time = getnstimeofday(); 59 // 返回正确的剩余时间 60 let real_sleep_time = end_time - start_time; 61 let rm_time: PosixTimeSpec = (sleep_time - real_sleep_time.into()).into(); 62 63 return Ok(rm_time); 64 } 65