time.c 4.1 KB

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