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.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}