1 #include "sleep.h"
2 #include <common/errno.h>
3 #include <time/timer.h>
4 #include <process/process.h>
5 #include <sched/sched.h>
6 #include <mm/slab.h>
7 #include <common/cpu.h>
8 #include <common/glib.h>
9 
10 /**
11  * @brief nanosleep定时事件到期后,唤醒指定的进程
12  *
13  * @param pcb 待唤醒的进程的pcb
14  */
nanosleep_handler(void * pcb)15 void nanosleep_handler(void *pcb)
16 {
17     process_wakeup((struct process_control_block *)pcb);
18 }
19 
20 /**
21  * @brief 休眠指定时间
22  *
23  * @param rqtp 指定休眠的时间
24  * @param rmtp 返回的剩余休眠时间
25  * @return int
26  */
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)27 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
28 {
29 
30     if (rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000)
31         return -EINVAL;
32 
33 
34     // 对于小于500us的时间,使用spin/rdtsc来进行定时
35     if (rqtp->tv_nsec < 500000)
36     {
37         uint64_t expired_tsc = rdtsc() + (((uint64_t)rqtp->tv_nsec) * Cpu_tsc_freq) / 1000000000;
38         while (rdtsc() < expired_tsc)
39             ;
40 
41         if (rmtp != NULL)
42         {
43             rmtp->tv_nsec = 0;
44             rmtp->tv_sec = 0;
45         }
46         return 0;
47     }
48 
49     // 增加定时任务
50     struct timer_func_list_t *sleep_task = (struct timer_func_list_t *)kmalloc(sizeof(struct timer_func_list_t), 0);
51     memset(sleep_task, 0, sizeof(struct timer_func_list_t));
52 
53     timer_func_init_us(sleep_task, &nanosleep_handler, (void *)current_pcb, rqtp->tv_nsec / 1000);
54 
55     timer_func_add(sleep_task);
56 
57     current_pcb->state = PROC_INTERRUPTIBLE;
58     current_pcb->flags |= PF_NEED_SCHED;
59     sched();
60 
61     // todo: 增加信号唤醒的功能后,设置rmtp
62 
63     if (rmtp != NULL)
64     {
65         rmtp->tv_nsec = 0;
66         rmtp->tv_sec = 0;
67     }
68 
69     return 0;
70 }
71 
72 /**
73  * @brief 睡眠指定时间
74  *
75  * @param usec 微秒
76  * @return int
77  */
usleep(useconds_t usec)78 int usleep(useconds_t usec)
79 {
80     struct timespec ts = {
81         tv_sec : (long int)(usec / 1000000),
82         tv_nsec : (long int)(usec % 1000000) * 1000UL
83     };
84 
85     return nanosleep(&ts, NULL);
86 }
87