aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/os-Linux/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/os-Linux/time.c')
-rw-r--r--arch/um/os-Linux/time.c61
1 files changed, 57 insertions, 4 deletions
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index e49280599465..dec5678fc17f 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,48 @@ 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 /* Protection against the host's time going backwards */
110 if ((last_tick != 0) && (this_tick < last_tick))
111 this_tick = last_tick;
112
113 if (last_tick == 0)
114 last_tick = this_tick - one_tick;
115
116 skew += this_tick - last_tick;
117
118 while (skew >= one_tick) {
119 alarm_handler(SIGVTALRM, NULL);
120 skew -= one_tick;
121 }
122
123 last_tick = this_tick;
124}
125
126static unsigned long long sleep_time(unsigned long long nsecs)
127{
128 return nsecs > skew ? nsecs - skew : 0;
129}
130
83static inline long long timespec_to_us(const struct timespec *ts) 131static inline long long timespec_to_us(const struct timespec *ts)
84{ 132{
85 return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + 133 return ((long long) ts->tv_sec * UM_USEC_PER_SEC) +
@@ -102,6 +150,11 @@ static int after_sleep_interval(struct timespec *ts)
102 */ 150 */
103 if (start_usecs > usec) 151 if (start_usecs > usec)
104 start_usecs = usec; 152 start_usecs = usec;
153
154 start_usecs -= skew / UM_NSEC_PER_USEC;
155 if (start_usecs < 0)
156 start_usecs = 0;
157
105 tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, 158 tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC,
106 .tv_usec = start_usecs % UM_USEC_PER_SEC }); 159 .tv_usec = start_usecs % UM_USEC_PER_SEC });
107 interval = ((struct itimerval) { { 0, usec }, tv }); 160 interval = ((struct itimerval) { { 0, usec }, tv });
@@ -113,8 +166,6 @@ static int after_sleep_interval(struct timespec *ts)
113} 166}
114#endif 167#endif
115 168
116extern void alarm_handler(int sig, struct sigcontext *sc);
117
118void idle_sleep(unsigned long long nsecs) 169void idle_sleep(unsigned long long nsecs)
119{ 170{
120 struct timespec ts; 171 struct timespec ts;
@@ -126,10 +177,12 @@ void idle_sleep(unsigned long long nsecs)
126 */ 177 */
127 if (nsecs == 0) 178 if (nsecs == 0)
128 nsecs = UM_NSEC_PER_SEC / UM_HZ; 179 nsecs = UM_NSEC_PER_SEC / UM_HZ;
180
181 nsecs = sleep_time(nsecs);
129 ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, 182 ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC,
130 .tv_nsec = nsecs % UM_NSEC_PER_SEC }); 183 .tv_nsec = nsecs % UM_NSEC_PER_SEC });
131 184
132 if (nanosleep(&ts, &ts) == 0) 185 if (nanosleep(&ts, &ts) == 0)
133 alarm_handler(SIGVTALRM, NULL); 186 deliver_alarm();
134 after_sleep_interval(&ts); 187 after_sleep_interval(&ts);
135} 188}