aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-10-16 04:27:25 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:08 -0400
commitd2753a6d199791a6abc75d9f657e3457fe61705f (patch)
treec4cda30f216d6c045ca2b83bee1fa6bc4dfc3de3
parent791a644a8d73a9b95515f074afbb3caa0a9964fa (diff)
uml: tickless support
Enable tickless support. CONFIG_TICK_ONESHOT and CONFIG_NO_HZ are enabled. itimer_clockevent gets CLOCK_EVT_FEAT_ONESHOT and an implementation of .set_next_event. CONFIG_UML_REAL_TIME_CLOCK goes away because it only makes sense when there is a clock ticking away all the time. timer_handler now just calls do_IRQ once without trying to figure out how many ticks to emulate. The idle loop now needs to turn ticking on and off. Userspace ticks keep happening as usual. However, the userspace loop keep track of when the next wakeup should happen and suppresses process ticks until that happens. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/um/Kconfig12
-rw-r--r--arch/um/defconfig5
-rw-r--r--arch/um/include/os.h1
-rw-r--r--arch/um/kernel/process.c3
-rw-r--r--arch/um/kernel/time.c45
-rw-r--r--arch/um/os-Linux/skas/process.c27
-rw-r--r--arch/um/os-Linux/time.c17
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
253config 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
265endmenu 253endmenu
266 254
267source "init/Kconfig" 255source "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
73CONFIG_FLAT_NODE_MEM_MAP=y 73CONFIG_FLAT_NODE_MEM_MAP=y
74# CONFIG_SPARSEMEM_STATIC is not set 74# CONFIG_SPARSEMEM_STATIC is not set
75CONFIG_SPLIT_PTLOCK_CPUS=4 75CONFIG_SPLIT_PTLOCK_CPUS=4
76# CONFIG_TICK_ONESHOT is not set 76CONFIG_TICK_ONESHOT=y
77# CONFIG_NO_HZ is not set 77CONFIG_NO_HZ=y
78CONFIG_HIGH_RES_TIMERS=y 78CONFIG_HIGH_RES_TIMERS=y
79CONFIG_LD_SCRIPT_DYN=y 79CONFIG_LD_SCRIPT_DYN=y
80CONFIG_NET=y 80CONFIG_NET=y
@@ -87,7 +87,6 @@ CONFIG_MAGIC_SYSRQ=y
87CONFIG_NEST_LEVEL=0 87CONFIG_NEST_LEVEL=0
88# CONFIG_HIGHMEM is not set 88# CONFIG_HIGHMEM is not set
89CONFIG_KERNEL_STACK_ORDER=0 89CONFIG_KERNEL_STACK_ORDER=0
90CONFIG_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);
254extern int switch_timers(int to_real); 254extern int switch_timers(int to_real);
255extern void idle_sleep(int secs); 255extern void idle_sleep(int secs);
256extern int set_interval(void); 256extern int set_interval(void);
257extern int timer_one_shot(int ticks);
257extern void disable_timer(void); 258extern void disable_timer(void);
258extern void uml_idle_timer(void); 259extern void uml_idle_timer(void);
259extern unsigned long long os_nsecs(void); 260extern 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
24static unsigned long long prev_nsecs[NR_CPUS];
25static long long delta[NR_CPUS]; /* Deviation per interval */
26#endif
27
28void timer_handler(int sig, struct uml_pt_regs *regs) 23void 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
51static int itimer_next_event(unsigned long delta,
52 struct clock_event_device *evt)
53{
54 return timer_one_shot(delta + 1);
55}
56
82static struct clock_event_device itimer_clockevent = { 57static 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
288void userspace(struct uml_pt_regs *regs) 288void 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
379int copy_context_skas0(unsigned long new_stack, int pid) 397int 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
29int 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
29void disable_timer(void) 44void 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
80void idle_sleep(int secs) 95void idle_sleep(int secs)