time.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
  4. * Copyright (C) 2015 Thomas Meyer ([email protected])
  5. * Copyright (C) 2012-2014 Cisco Systems
  6. * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
  7. */
  8. #include <stddef.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <signal.h>
  12. #include <time.h>
  13. #include <sys/time.h>
  14. #include <kern_util.h>
  15. #include <os.h>
  16. #include <string.h>
  17. static timer_t event_high_res_timer = 0;
  18. static inline long long timespec_to_ns(const struct timespec *ts)
  19. {
  20. return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec;
  21. }
  22. long long os_persistent_clock_emulation(void)
  23. {
  24. struct timespec realtime_tp;
  25. clock_gettime(CLOCK_REALTIME, &realtime_tp);
  26. return timespec_to_ns(&realtime_tp);
  27. }
  28. /**
  29. * os_timer_create() - create an new posix (interval) timer
  30. */
  31. int os_timer_create(void)
  32. {
  33. timer_t *t = &event_high_res_timer;
  34. if (timer_create(CLOCK_MONOTONIC, NULL, t) == -1)
  35. return -1;
  36. return 0;
  37. }
  38. int os_timer_set_interval(unsigned long long nsecs)
  39. {
  40. struct itimerspec its;
  41. its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC;
  42. its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC;
  43. its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC;
  44. its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC;
  45. if (timer_settime(event_high_res_timer, 0, &its, NULL) == -1)
  46. return -errno;
  47. return 0;
  48. }
  49. int os_timer_one_shot(unsigned long long nsecs)
  50. {
  51. struct itimerspec its = {
  52. .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC,
  53. .it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC,
  54. .it_interval.tv_sec = 0,
  55. .it_interval.tv_nsec = 0, // we cheat here
  56. };
  57. timer_settime(event_high_res_timer, 0, &its, NULL);
  58. return 0;
  59. }
  60. /**
  61. * os_timer_disable() - disable the posix (interval) timer
  62. */
  63. void os_timer_disable(void)
  64. {
  65. struct itimerspec its;
  66. memset(&its, 0, sizeof(struct itimerspec));
  67. timer_settime(event_high_res_timer, 0, &its, NULL);
  68. }
  69. long long os_nsecs(void)
  70. {
  71. struct timespec ts;
  72. clock_gettime(CLOCK_MONOTONIC,&ts);
  73. return timespec_to_ns(&ts);
  74. }
  75. /**
  76. * os_idle_sleep() - sleep until interrupted
  77. */
  78. void os_idle_sleep(void)
  79. {
  80. struct itimerspec its;
  81. sigset_t set, old;
  82. /* block SIGALRM while we analyze the timer state */
  83. sigemptyset(&set);
  84. sigaddset(&set, SIGALRM);
  85. sigprocmask(SIG_BLOCK, &set, &old);
  86. /* check the timer, and if it'll fire then wait for it */
  87. timer_gettime(event_high_res_timer, &its);
  88. if (its.it_value.tv_sec || its.it_value.tv_nsec)
  89. sigsuspend(&old);
  90. /* either way, restore the signal mask */
  91. sigprocmask(SIG_UNBLOCK, &set, NULL);
  92. }