sleep.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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. * @brief nanosleep定时事件到期后,唤醒指定的进程
  11. *
  12. * @param pcb 待唤醒的进程的pcb
  13. */
  14. void nanosleep_handler(void *pcb)
  15. {
  16. process_wakeup((struct process_control_block *)pcb);
  17. }
  18. /**
  19. * @brief 休眠指定时间
  20. *
  21. * @param rqtp 指定休眠的时间
  22. * @param rmtp 返回的剩余休眠时间
  23. * @return int
  24. */
  25. int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
  26. {
  27. int64_t total_ns = rqtp->tv_nsec;
  28. if (total_ns < 0 || total_ns >= 1000000000)
  29. return -EINVAL;
  30. // 对于小于500us的时间,使用spin/rdtsc来进行定时
  31. if (total_ns < 500000)
  32. {
  33. kdebug("use rdtsc to nanosleep");
  34. uint64_t expired_tsc = rdtsc() + (total_ns * Cpu_tsc_freq) / 1000000000;
  35. while (rdtsc() < expired_tsc)
  36. pause();
  37. if (rmtp != NULL)
  38. {
  39. rmtp->tv_nsec = 0;
  40. rmtp->tv_sec = 0;
  41. }
  42. return 0;
  43. }
  44. // 增加定时任务
  45. struct timer_func_list_t *sleep_task = (struct timer_func_list_t *)kmalloc(sizeof(struct timer_func_list_t), 0);
  46. memset(sleep_task, 0, sizeof(struct timer_func_list_t));
  47. timer_func_init_us(sleep_task, &nanosleep_handler, (void *)current_pcb, total_ns / 1000);
  48. timer_func_add(sleep_task);
  49. current_pcb->state = PROC_INTERRUPTIBLE;
  50. current_pcb->flags |= PF_NEED_SCHED;
  51. sched();
  52. // todo: 增加信号唤醒的功能后,设置rmtp
  53. if (rmtp != NULL)
  54. {
  55. rmtp->tv_nsec = 0;
  56. rmtp->tv_sec = 0;
  57. }
  58. return 0;
  59. }
  60. /**
  61. * @brief 睡眠指定时间
  62. *
  63. * @param usec 微秒
  64. * @return int
  65. */
  66. int usleep(useconds_t usec)
  67. {
  68. struct timespec ts = {
  69. tv_sec : (long int)(usec / 1000000),
  70. tv_nsec : (long int)(usec % 1000000) * 1000UL
  71. };
  72. return nanosleep(&ts, NULL);
  73. }