aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/os-Linux/time.c
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2008-05-12 17:02:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-13 11:02:22 -0400
commitfe2cc53ee013a4d4d0317d418e7019fe6533a5a8 (patch)
tree7a173e2703c638b8eab4a2a6762c256114acec60 /arch/um/os-Linux/time.c
parent3d88958e01e71bb14a367db75f12f7a59c068f02 (diff)
uml: track and make up lost ticks
Alarm delivery could be noticably late in the !CONFIG_NOHZ case because lost ticks weren't being taken into account. This is now treated more carefully, with the time between ticks being calculated and the appropriate number of ticks delivered to the timekeeping system. Cc: Nix <nix@esperi.org.uk> Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um/os-Linux/time.c')
-rw-r--r--arch/um/os-Linux/time.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index e49280599465..bee98f466d66 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -9,7 +9,9 @@
9#include <time.h> 9#include <time.h>
10#include <sys/time.h> 10#include <sys/time.h>
11#include "kern_constants.h" 11#include "kern_constants.h"
12#include "kern_util.h"
12#include "os.h" 13#include "os.h"
14#include "process.h"
13#include "user.h" 15#include "user.h"
14 16
15int set_interval(void) 17int set_interval(void)
@@ -58,12 +60,17 @@ static inline long long timeval_to_ns(const struct timeval *tv)
58long long disable_timer(void) 60long long disable_timer(void)
59{ 61{
60 struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); 62 struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
63 int remain, max = UM_NSEC_PER_SEC / UM_HZ;
61 64
62 if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0) 65 if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
63 printk(UM_KERN_ERR "disable_timer - setitimer failed, " 66 printk(UM_KERN_ERR "disable_timer - setitimer failed, "
64 "errno = %d\n", errno); 67 "errno = %d\n", errno);
65 68
66 return timeval_to_ns(&time.it_value); 69 remain = timeval_to_ns(&time.it_value);
70 if (remain > max)
71 remain = max;
72
73 return remain;
67} 74}
68 75
69long long os_nsecs(void) 76long long os_nsecs(void)
@@ -79,7 +86,44 @@ static int after_sleep_interval(struct timespec *ts)
79{ 86{
80 return 0; 87 return 0;
81} 88}
89
90static void deliver_alarm(void)
91{
92 alarm_handler(SIGVTALRM, NULL);
93}
94
95static unsigned long long sleep_time(unsigned long long nsecs)
96{
97 return nsecs;
98}
99
82#else 100#else
101unsigned long long last_tick;
102unsigned long long skew;
103
104static void deliver_alarm(void)
105{
106 unsigned long long this_tick = os_nsecs();
107 int one_tick = UM_NSEC_PER_SEC / UM_HZ;
108
109 if (last_tick == 0)
110 last_tick = this_tick - one_tick;
111
112 skew += this_tick - last_tick;
113
114 while (skew >= one_tick) {
115 alarm_handler(SIGVTALRM, NULL);
116 skew -= one_tick;
117 }
118
119 last_tick = this_tick;
120}
121
122static unsigned long long sleep_time(unsigned long long nsecs)
123{
124 return nsecs > skew ? nsecs - skew : 0;
125}
126
83static inline long long timespec_to_us(const struct timespec *ts) 127static inline long long timespec_to_us(const struct timespec *ts)
84{ 128{
85 return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + 129 return ((long long) ts->tv_sec * UM_USEC_PER_SEC) +
@@ -102,6 +146,8 @@ static int after_sleep_interval(struct timespec *ts)
102 */ 146 */
103 if (start_usecs > usec) 147 if (start_usecs > usec)
104 start_usecs = usec; 148 start_usecs = usec;
149
150 start_usecs -= skew / UM_NSEC_PER_USEC;
105 tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, 151 tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC,
106 .tv_usec = start_usecs % UM_USEC_PER_SEC }); 152 .tv_usec = start_usecs % UM_USEC_PER_SEC });
107 interval = ((struct itimerval) { { 0, usec }, tv }); 153 interval = ((struct itimerval) { { 0, usec }, tv });
@@ -113,8 +159,6 @@ static int after_sleep_interval(struct timespec *ts)
113} 159}
114#endif 160#endif
115 161
116extern void alarm_handler(int sig, struct sigcontext *sc);
117
118void idle_sleep(unsigned long long nsecs) 162void idle_sleep(unsigned long long nsecs)
119{ 163{
120 struct timespec ts; 164 struct timespec ts;
@@ -126,10 +170,12 @@ void idle_sleep(unsigned long long nsecs)
126 */ 170 */
127 if (nsecs == 0) 171 if (nsecs == 0)
128 nsecs = UM_NSEC_PER_SEC / UM_HZ; 172 nsecs = UM_NSEC_PER_SEC / UM_HZ;
173
174 nsecs = sleep_time(nsecs);
129 ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, 175 ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC,
130 .tv_nsec = nsecs % UM_NSEC_PER_SEC }); 176 .tv_nsec = nsecs % UM_NSEC_PER_SEC });
131 177
132 if (nanosleep(&ts, &ts) == 0) 178 if (nanosleep(&ts, &ts) == 0)
133 alarm_handler(SIGVTALRM, NULL); 179 deliver_alarm();
134 after_sleep_interval(&ts); 180 after_sleep_interval(&ts);
135} 181}