diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/Kconfig | 12 | ||||
-rw-r--r-- | arch/um/defconfig | 5 | ||||
-rw-r--r-- | arch/um/include/os.h | 1 | ||||
-rw-r--r-- | arch/um/kernel/process.c | 3 | ||||
-rw-r--r-- | arch/um/kernel/time.c | 45 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 27 | ||||
-rw-r--r-- | arch/um/os-Linux/time.c | 17 |
7 files changed, 55 insertions, 55 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 64fe8d5c067a..740d8a922e48 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -250,18 +250,6 @@ config KERNEL_STACK_ORDER | |||
250 | be 1 << order pages. The default is OK unless you're running Valgrind | 250 | be 1 << order pages. The default is OK unless you're running Valgrind |
251 | on UML, in which case, set this to 3. | 251 | on UML, in which case, set this to 3. |
252 | 252 | ||
253 | config UML_REAL_TIME_CLOCK | ||
254 | bool "Real-time Clock" | ||
255 | default y | ||
256 | help | ||
257 | This option makes UML time deltas match wall clock deltas. This | ||
258 | should normally be enabled. The exception would be if you are | ||
259 | debugging with UML and spend long times with UML stopped at a | ||
260 | breakpoint. In this case, when UML is restarted, it will call the | ||
261 | timer enough times to make up for the time spent at the breakpoint. | ||
262 | This could result in a noticeable lag. If this is a problem, then | ||
263 | disable this option. | ||
264 | |||
265 | endmenu | 253 | endmenu |
266 | 254 | ||
267 | source "init/Kconfig" | 255 | source "init/Kconfig" |
diff --git a/arch/um/defconfig b/arch/um/defconfig index 9f105c87fcc4..1cbbe980f106 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig | |||
@@ -73,8 +73,8 @@ CONFIG_FLATMEM=y | |||
73 | CONFIG_FLAT_NODE_MEM_MAP=y | 73 | CONFIG_FLAT_NODE_MEM_MAP=y |
74 | # CONFIG_SPARSEMEM_STATIC is not set | 74 | # CONFIG_SPARSEMEM_STATIC is not set |
75 | CONFIG_SPLIT_PTLOCK_CPUS=4 | 75 | CONFIG_SPLIT_PTLOCK_CPUS=4 |
76 | # CONFIG_TICK_ONESHOT is not set | 76 | CONFIG_TICK_ONESHOT=y |
77 | # CONFIG_NO_HZ is not set | 77 | CONFIG_NO_HZ=y |
78 | CONFIG_HIGH_RES_TIMERS=y | 78 | CONFIG_HIGH_RES_TIMERS=y |
79 | CONFIG_LD_SCRIPT_DYN=y | 79 | CONFIG_LD_SCRIPT_DYN=y |
80 | CONFIG_NET=y | 80 | CONFIG_NET=y |
@@ -87,7 +87,6 @@ CONFIG_MAGIC_SYSRQ=y | |||
87 | CONFIG_NEST_LEVEL=0 | 87 | CONFIG_NEST_LEVEL=0 |
88 | # CONFIG_HIGHMEM is not set | 88 | # CONFIG_HIGHMEM is not set |
89 | CONFIG_KERNEL_STACK_ORDER=0 | 89 | CONFIG_KERNEL_STACK_ORDER=0 |
90 | CONFIG_UML_REAL_TIME_CLOCK=y | ||
91 | 90 | ||
92 | # | 91 | # |
93 | # Code maturity level options | 92 | # Code maturity level options |
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index a6d80721d3c4..e4f2fe11ba50 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -254,6 +254,7 @@ extern void os_dump_core(void); | |||
254 | extern int switch_timers(int to_real); | 254 | extern int switch_timers(int to_real); |
255 | extern void idle_sleep(int secs); | 255 | extern void idle_sleep(int secs); |
256 | extern int set_interval(void); | 256 | extern int set_interval(void); |
257 | extern int timer_one_shot(int ticks); | ||
257 | extern void disable_timer(void); | 258 | extern void disable_timer(void); |
258 | extern void uml_idle_timer(void); | 259 | extern void uml_idle_timer(void); |
259 | extern unsigned long long os_nsecs(void); | 260 | extern unsigned long long os_nsecs(void); |
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 56d75afedbf7..aef494b6b81a 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include "linux/ptrace.h" | 13 | #include "linux/ptrace.h" |
14 | #include "linux/random.h" | 14 | #include "linux/random.h" |
15 | #include "linux/sched.h" | 15 | #include "linux/sched.h" |
16 | #include "linux/tick.h" | ||
16 | #include "linux/threads.h" | 17 | #include "linux/threads.h" |
17 | #include "asm/pgtable.h" | 18 | #include "asm/pgtable.h" |
18 | #include "asm/uaccess.h" | 19 | #include "asm/uaccess.h" |
@@ -244,9 +245,11 @@ void default_idle(void) | |||
244 | if (need_resched()) | 245 | if (need_resched()) |
245 | schedule(); | 246 | schedule(); |
246 | 247 | ||
248 | tick_nohz_stop_sched_tick(); | ||
247 | switch_timers(1); | 249 | switch_timers(1); |
248 | idle_sleep(10); | 250 | idle_sleep(10); |
249 | switch_timers(0); | 251 | switch_timers(0); |
252 | tick_nohz_restart_sched_tick(); | ||
250 | } | 253 | } |
251 | } | 254 | } |
252 | 255 | ||
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 3cb7135e5c47..2acdc7efb2ac 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c | |||
@@ -20,41 +20,12 @@ unsigned long long sched_clock(void) | |||
20 | return (unsigned long long)jiffies_64 * (1000000000 / HZ); | 20 | return (unsigned long long)jiffies_64 * (1000000000 / HZ); |
21 | } | 21 | } |
22 | 22 | ||
23 | #ifdef CONFIG_UML_REAL_TIME_CLOCK | ||
24 | static unsigned long long prev_nsecs[NR_CPUS]; | ||
25 | static long long delta[NR_CPUS]; /* Deviation per interval */ | ||
26 | #endif | ||
27 | |||
28 | void timer_handler(int sig, struct uml_pt_regs *regs) | 23 | void timer_handler(int sig, struct uml_pt_regs *regs) |
29 | { | 24 | { |
30 | unsigned long long ticks = 0; | ||
31 | unsigned long flags; | 25 | unsigned long flags; |
32 | #ifdef CONFIG_UML_REAL_TIME_CLOCK | ||
33 | int c = cpu(); | ||
34 | if (prev_nsecs[c]) { | ||
35 | /* We've had 1 tick */ | ||
36 | unsigned long long nsecs = os_nsecs(); | ||
37 | |||
38 | delta[c] += nsecs - prev_nsecs[c]; | ||
39 | prev_nsecs[c] = nsecs; | ||
40 | |||
41 | /* Protect against the host clock being set backwards */ | ||
42 | if (delta[c] < 0) | ||
43 | delta[c] = 0; | ||
44 | |||
45 | ticks += (delta[c] * HZ) / BILLION; | ||
46 | delta[c] -= (ticks * BILLION) / HZ; | ||
47 | } | ||
48 | else prev_nsecs[c] = os_nsecs(); | ||
49 | #else | ||
50 | ticks = 1; | ||
51 | #endif | ||
52 | 26 | ||
53 | local_irq_save(flags); | 27 | local_irq_save(flags); |
54 | while (ticks > 0) { | 28 | do_IRQ(TIMER_IRQ, regs); |
55 | do_IRQ(TIMER_IRQ, regs); | ||
56 | ticks--; | ||
57 | } | ||
58 | local_irq_restore(flags); | 29 | local_irq_restore(flags); |
59 | } | 30 | } |
60 | 31 | ||
@@ -68,10 +39,8 @@ static void itimer_set_mode(enum clock_event_mode mode, | |||
68 | 39 | ||
69 | case CLOCK_EVT_MODE_SHUTDOWN: | 40 | case CLOCK_EVT_MODE_SHUTDOWN: |
70 | case CLOCK_EVT_MODE_UNUSED: | 41 | case CLOCK_EVT_MODE_UNUSED: |
71 | disable_timer(); | ||
72 | break; | ||
73 | case CLOCK_EVT_MODE_ONESHOT: | 42 | case CLOCK_EVT_MODE_ONESHOT: |
74 | BUG(); | 43 | disable_timer(); |
75 | break; | 44 | break; |
76 | 45 | ||
77 | case CLOCK_EVT_MODE_RESUME: | 46 | case CLOCK_EVT_MODE_RESUME: |
@@ -79,13 +48,19 @@ static void itimer_set_mode(enum clock_event_mode mode, | |||
79 | } | 48 | } |
80 | } | 49 | } |
81 | 50 | ||
51 | static int itimer_next_event(unsigned long delta, | ||
52 | struct clock_event_device *evt) | ||
53 | { | ||
54 | return timer_one_shot(delta + 1); | ||
55 | } | ||
56 | |||
82 | static struct clock_event_device itimer_clockevent = { | 57 | static struct clock_event_device itimer_clockevent = { |
83 | .name = "itimer", | 58 | .name = "itimer", |
84 | .rating = 250, | 59 | .rating = 250, |
85 | .cpumask = CPU_MASK_ALL, | 60 | .cpumask = CPU_MASK_ALL, |
86 | .features = CLOCK_EVT_FEAT_PERIODIC, | 61 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
87 | .set_mode = itimer_set_mode, | 62 | .set_mode = itimer_set_mode, |
88 | .set_next_event = NULL, | 63 | .set_next_event = itimer_next_event, |
89 | .shift = 32, | 64 | .shift = 32, |
90 | .irq = 0, | 65 | .irq = 0, |
91 | }; | 66 | }; |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 0036164bb0fb..3e64814e888e 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -287,10 +287,18 @@ int start_userspace(unsigned long stub_stack) | |||
287 | 287 | ||
288 | void userspace(struct uml_pt_regs *regs) | 288 | void userspace(struct uml_pt_regs *regs) |
289 | { | 289 | { |
290 | struct itimerval timer; | ||
291 | unsigned long long nsecs, now; | ||
290 | int err, status, op, pid = userspace_pid[0]; | 292 | int err, status, op, pid = userspace_pid[0]; |
291 | /* To prevent races if using_sysemu changes under us.*/ | 293 | /* To prevent races if using_sysemu changes under us.*/ |
292 | int local_using_sysemu; | 294 | int local_using_sysemu; |
293 | 295 | ||
296 | if (getitimer(ITIMER_VIRTUAL, &timer)) | ||
297 | printk("Failed to get itimer, errno = %d\n", errno); | ||
298 | nsecs = timer.it_value.tv_sec * BILLION + | ||
299 | timer.it_value.tv_usec * 1000; | ||
300 | nsecs += os_nsecs(); | ||
301 | |||
294 | while (1) { | 302 | while (1) { |
295 | restore_registers(pid, regs); | 303 | restore_registers(pid, regs); |
296 | 304 | ||
@@ -333,8 +341,18 @@ void userspace(struct uml_pt_regs *regs) | |||
333 | case SIGTRAP: | 341 | case SIGTRAP: |
334 | relay_signal(SIGTRAP, regs); | 342 | relay_signal(SIGTRAP, regs); |
335 | break; | 343 | break; |
336 | case SIGIO: | ||
337 | case SIGVTALRM: | 344 | case SIGVTALRM: |
345 | now = os_nsecs(); | ||
346 | if(now < nsecs) | ||
347 | break; | ||
348 | block_signals(); | ||
349 | (*sig_info[sig])(sig, regs); | ||
350 | unblock_signals(); | ||
351 | nsecs = timer.it_value.tv_sec * BILLION + | ||
352 | timer.it_value.tv_usec * 1000; | ||
353 | nsecs += os_nsecs(); | ||
354 | break; | ||
355 | case SIGIO: | ||
338 | case SIGILL: | 356 | case SIGILL: |
339 | case SIGBUS: | 357 | case SIGBUS: |
340 | case SIGFPE: | 358 | case SIGFPE: |
@@ -378,6 +396,7 @@ __initcall(init_thread_regs); | |||
378 | 396 | ||
379 | int copy_context_skas0(unsigned long new_stack, int pid) | 397 | int copy_context_skas0(unsigned long new_stack, int pid) |
380 | { | 398 | { |
399 | struct timeval tv = { .tv_sec = 0, .tv_usec = 1000000 / UM_HZ }; | ||
381 | int err; | 400 | int err; |
382 | unsigned long current_stack = current_stub_stack(); | 401 | unsigned long current_stack = current_stub_stack(); |
383 | struct stub_data *data = (struct stub_data *) current_stack; | 402 | struct stub_data *data = (struct stub_data *) current_stack; |
@@ -392,9 +411,9 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
392 | *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), | 411 | *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), |
393 | .fd = new_fd, | 412 | .fd = new_fd, |
394 | .timer = ((struct itimerval) | 413 | .timer = ((struct itimerval) |
395 | { { 0, 1000000 / UM_HZ }, | 414 | { .it_value = tv, |
396 | { 0, 1000000 / UM_HZ }}) | 415 | .it_interval = tv }) }); |
397 | }); | 416 | |
398 | err = ptrace_setregs(pid, thread_regs); | 417 | err = ptrace_setregs(pid, thread_regs); |
399 | if (err < 0) | 418 | if (err < 0) |
400 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " | 419 | panic("copy_context_skas0 : PTRACE_SETREGS failed, " |
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 6ff3d98281ba..9ffc61ac8ed6 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c | |||
@@ -26,6 +26,21 @@ int set_interval(void) | |||
26 | return 0; | 26 | return 0; |
27 | } | 27 | } |
28 | 28 | ||
29 | int timer_one_shot(int ticks) | ||
30 | { | ||
31 | unsigned long usec = ticks * 1000000 / UM_HZ; | ||
32 | unsigned long sec = usec / 1000000; | ||
33 | struct itimerval interval; | ||
34 | |||
35 | usec %= 1000000; | ||
36 | interval = ((struct itimerval) { { 0, 0 }, { sec, usec } }); | ||
37 | |||
38 | if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) | ||
39 | return -errno; | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
29 | void disable_timer(void) | 44 | void disable_timer(void) |
30 | { | 45 | { |
31 | struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); | 46 | struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); |
@@ -74,7 +89,7 @@ unsigned long long os_nsecs(void) | |||
74 | struct timeval tv; | 89 | struct timeval tv; |
75 | 90 | ||
76 | gettimeofday(&tv, NULL); | 91 | gettimeofday(&tv, NULL); |
77 | return (unsigned long long) tv.tv_sec * BILLION + tv.tv_usec * 1000; | 92 | return timeval_to_ns(&tv); |
78 | } | 93 | } |
79 | 94 | ||
80 | void idle_sleep(int secs) | 95 | void idle_sleep(int secs) |