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) 错误码
nanosleep(sleep_time: PosixTimeSpec) -> Result<PosixTimeSpec, 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