time.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
  3. * Licensed under the GPL
  4. */
  5. #include <stddef.h>
  6. #include <errno.h>
  7. #include <signal.h>
  8. #include <time.h>
  9. #include <sys/time.h>
  10. #include "kern_util.h"
  11. #include "os.h"
  12. #include "internal.h"
  13. int set_interval(void)
  14. {
  15. int usec = UM_USEC_PER_SEC / UM_HZ;
  16. struct itimerval interval = ((struct itimerval) { { 0, usec },
  17. { 0, usec } });
  18. if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
  19. return -errno;
  20. return 0;
  21. }
  22. int timer_one_shot(int ticks)
  23. {
  24. unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ;
  25. unsigned long sec = usec / UM_USEC_PER_SEC;
  26. struct itimerval interval;
  27. usec %= UM_USEC_PER_SEC;
  28. interval = ((struct itimerval) { { 0, 0 }, { sec, usec } });
  29. if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
  30. return -errno;
  31. return 0;
  32. }
  33. /**
  34. * timeval_to_ns - Convert timeval to nanoseconds
  35. * @ts: pointer to the timeval variable to be converted
  36. *
  37. * Returns the scalar nanosecond representation of the timeval
  38. * parameter.
  39. *
  40. * Ripped from linux/time.h because it's a kernel header, and thus
  41. * unusable from here.
  42. */
  43. static inline long long timeval_to_ns(const struct timeval *tv)
  44. {
  45. return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) +
  46. tv->tv_usec * UM_NSEC_PER_USEC;
  47. }
  48. long long disable_timer(void)
  49. {
  50. struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
  51. long long remain, max = UM_NSEC_PER_SEC / UM_HZ;
  52. if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
  53. printk(UM_KERN_ERR "disable_timer - setitimer failed, "
  54. "errno = %d\n", errno);
  55. remain = timeval_to_ns(&time.it_value);
  56. if (remain > max)
  57. remain = max;
  58. return remain;
  59. }
  60. long long os_nsecs(void)
  61. {
  62. struct timeval tv;
  63. gettimeofday(&tv, NULL);
  64. return timeval_to_ns(&tv);
  65. }
  66. #ifdef UML_CONFIG_NO_HZ
  67. static int after_sleep_interval(struct timespec *ts)
  68. {
  69. return 0;
  70. }
  71. static void deliver_alarm(void)
  72. {
  73. alarm_handler(SIGVTALRM, NULL);
  74. }
  75. static unsigned long long sleep_time(unsigned long long nsecs)
  76. {
  77. return nsecs;
  78. }
  79. #else
  80. unsigned long long last_tick;
  81. unsigned long long skew;
  82. static void deliver_alarm(void)
  83. {
  84. unsigned long long this_tick = os_nsecs();
  85. int one_tick = UM_NSEC_PER_SEC / UM_HZ;
  86. /* Protection against the host's time going backwards */
  87. if ((last_tick != 0) && (this_tick < last_tick))
  88. this_tick = last_tick;
  89. if (last_tick == 0)
  90. last_tick = this_tick - one_tick;
  91. skew += this_tick - last_tick;
  92. while (skew >= one_tick) {
  93. alarm_handler(SIGVTALRM, NULL);
  94. skew -= one_tick;
  95. }
  96. last_tick = this_tick;
  97. }
  98. static unsigned long long sleep_time(unsigned long long nsecs)
  99. {
  100. return nsecs > skew ? nsecs - skew : 0;
  101. }
  102. static inline long long timespec_to_us(const struct timespec *ts)
  103. {
  104. return ((long long) ts->tv_sec * UM_USEC_PER_SEC) +
  105. ts->tv_nsec / UM_NSEC_PER_USEC;
  106. }
  107. static int after_sleep_interval(struct timespec *ts)
  108. {
  109. int usec = UM_USEC_PER_SEC / UM_HZ;
  110. long long start_usecs = timespec_to_us(ts);
  111. struct timeval tv;
  112. struct itimerval interval;
  113. /*
  114. * It seems that rounding can increase the value returned from
  115. * setitimer to larger than the one passed in. Over time,
  116. * this will cause the remaining time to be greater than the
  117. * tick interval. If this happens, then just reduce the first
  118. * tick to the interval value.
  119. */
  120. if (start_usecs > usec)
  121. start_usecs = usec;
  122. start_usecs -= skew / UM_NSEC_PER_USEC;
  123. if (start_usecs < 0)
  124. start_usecs = 0;
  125. tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC,
  126. .tv_usec = start_usecs % UM_USEC_PER_SEC });
  127. interval = ((struct itimerval) { { 0, usec }, tv });
  128. if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
  129. return -errno;
  130. return 0;
  131. }
  132. #endif
  133. void idle_sleep(unsigned long long nsecs)
  134. {
  135. struct timespec ts;
  136. /*
  137. * nsecs can come in as zero, in which case, this starts a
  138. * busy loop. To prevent this, reset nsecs to the tick
  139. * interval if it is zero.
  140. */
  141. if (nsecs == 0)
  142. nsecs = UM_NSEC_PER_SEC / UM_HZ;
  143. nsecs = sleep_time(nsecs);
  144. ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC,
  145. .tv_nsec = nsecs % UM_NSEC_PER_SEC });
  146. if (nanosleep(&ts, &ts) == 0)
  147. deliver_alarm();
  148. after_sleep_interval(&ts);
  149. }