time.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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 (thomas@m3y3r.de)
  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/signalfd.h>
  14. #include <sys/time.h>
  15. #include <kern_util.h>
  16. #include <os.h>
  17. #include <smp.h>
  18. #include <string.h>
  19. #include "internal.h"
  20. static timer_t event_high_res_timer[CONFIG_NR_CPUS] = { 0 };
  21. static inline long long timespec_to_ns(const struct timespec *ts)
  22. {
  23. return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + ts->tv_nsec;
  24. }
  25. long long os_persistent_clock_emulation(void)
  26. {
  27. struct timespec realtime_tp;
  28. clock_gettime(CLOCK_REALTIME, &realtime_tp);
  29. return timespec_to_ns(&realtime_tp);
  30. }
  31. #ifndef sigev_notify_thread_id
  32. #define sigev_notify_thread_id _sigev_un._tid
  33. #endif
  34. /**
  35. * os_timer_create() - create an new posix (interval) timer
  36. */
  37. int os_timer_create(void)
  38. {
  39. int cpu = uml_curr_cpu();
  40. timer_t *t = &event_high_res_timer[cpu];
  41. struct sigevent sev = {
  42. .sigev_notify = SIGEV_THREAD_ID,
  43. .sigev_signo = SIGALRM,
  44. .sigev_value.sival_ptr = t,
  45. .sigev_notify_thread_id = gettid(),
  46. };
  47. if (timer_create(CLOCK_MONOTONIC, &sev, t) == -1)
  48. return -1;
  49. return 0;
  50. }
  51. int os_timer_set_interval(int cpu, unsigned long long nsecs)
  52. {
  53. struct itimerspec its;
  54. its.it_value.tv_sec = nsecs / UM_NSEC_PER_SEC;
  55. its.it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC;
  56. its.it_interval.tv_sec = nsecs / UM_NSEC_PER_SEC;
  57. its.it_interval.tv_nsec = nsecs % UM_NSEC_PER_SEC;
  58. if (timer_settime(event_high_res_timer[cpu], 0, &its, NULL) == -1)
  59. return -errno;
  60. return 0;
  61. }
  62. int os_timer_one_shot(int cpu, unsigned long long nsecs)
  63. {
  64. struct itimerspec its = {
  65. .it_value.tv_sec = nsecs / UM_NSEC_PER_SEC,
  66. .it_value.tv_nsec = nsecs % UM_NSEC_PER_SEC,
  67. .it_interval.tv_sec = 0,
  68. .it_interval.tv_nsec = 0, // we cheat here
  69. };
  70. timer_settime(event_high_res_timer[cpu], 0, &its, NULL);
  71. return 0;
  72. }
  73. /**
  74. * os_timer_disable() - disable the posix (interval) timer
  75. * @cpu: the CPU for which the timer is to be disabled
  76. */
  77. void os_timer_disable(int cpu)
  78. {
  79. struct itimerspec its;
  80. memset(&its, 0, sizeof(struct itimerspec));
  81. timer_settime(event_high_res_timer[cpu], 0, &its, NULL);
  82. }
  83. long long os_nsecs(void)
  84. {
  85. struct timespec ts;
  86. clock_gettime(CLOCK_MONOTONIC,&ts);
  87. return timespec_to_ns(&ts);
  88. }
  89. static __thread int wake_signals;
  90. void os_idle_prepare(void)
  91. {
  92. sigset_t set;
  93. sigemptyset(&set);
  94. sigaddset(&set, SIGALRM);
  95. sigaddset(&set, IPI_SIGNAL);
  96. /*
  97. * We need to use signalfd rather than sigsuspend in idle sleep
  98. * because the IPI signal is a real-time signal that carries data,
  99. * and unlike handling SIGALRM, we cannot simply flag it in
  100. * signals_pending.
  101. */
  102. wake_signals = signalfd(-1, &set, SFD_CLOEXEC);
  103. if (wake_signals < 0)
  104. panic("Failed to create signal FD, errno = %d", errno);
  105. }
  106. /**
  107. * os_idle_sleep() - sleep until interrupted
  108. */
  109. void os_idle_sleep(void)
  110. {
  111. sigset_t set;
  112. /*
  113. * Block SIGALRM while performing the need_resched check.
  114. * Note that, because IRQs are disabled, the IPI signal is
  115. * already blocked.
  116. */
  117. sigemptyset(&set);
  118. sigaddset(&set, SIGALRM);
  119. sigprocmask(SIG_BLOCK, &set, NULL);
  120. /*
  121. * Because disabling IRQs does not block SIGALRM, it is also
  122. * necessary to check for any pending timer alarms.
  123. */
  124. if (!uml_need_resched() && !timer_alarm_pending())
  125. os_poll(1, &wake_signals);
  126. /* Restore the signal mask. */
  127. sigprocmask(SIG_UNBLOCK, &set, NULL);
  128. }