diff options
author | Jeff Dike <jdike@addtoit.com> | 2007-10-16 04:27:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:08 -0400 |
commit | 181bde801afae4304843ce95c868d4419ae87310 (patch) | |
tree | f33e6c88e36cda7699fc2dfe2b6ac9ccb3c6963f /arch/um | |
parent | 532d0fa4d104ca3e37dd38bc5073376fcc3c2712 (diff) |
uml: fix timer switching
Fix up the switching between virtual and real timers. The idle loop sleeps,
so the timer at that point must be real time. At all other times, the timer
must be virtual. Even when userspace is running, and the kernel is asleep,
the virtual timer is correct because the process timer will be running and the
process timer will be firing.
The timer switch used to be in the context switch and timer handler code.
This is moved to the idle loop and the signal handler, making it much more
clear why it is happening.
switch_timers now returns the old timer type so that it may be restored. The
signal handler uses this in order to restore the previous timer type when it
returns.
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>
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/include/os.h | 2 | ||||
-rw-r--r-- | arch/um/kernel/process.c | 9 | ||||
-rw-r--r-- | arch/um/os-Linux/signal.c | 9 | ||||
-rw-r--r-- | arch/um/os-Linux/time.c | 27 |
4 files changed, 26 insertions, 21 deletions
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index e861c8adb44f..12de1ea68370 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -250,7 +250,7 @@ extern void os_dump_core(void); | |||
250 | /* time.c */ | 250 | /* time.c */ |
251 | #define BILLION (1000 * 1000 * 1000) | 251 | #define BILLION (1000 * 1000 * 1000) |
252 | 252 | ||
253 | extern void switch_timers(int to_real); | 253 | extern int switch_timers(int to_real); |
254 | extern void idle_sleep(int secs); | 254 | extern void idle_sleep(int secs); |
255 | extern int set_interval(int is_virtual); | 255 | extern int set_interval(int is_virtual); |
256 | extern void disable_timer(void); | 256 | extern void disable_timer(void); |
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 8a6882dfba01..56d75afedbf7 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c | |||
@@ -95,18 +95,11 @@ void *_switch_to(void *prev, void *next, void *last) | |||
95 | do { | 95 | do { |
96 | current->thread.saved_task = NULL; | 96 | current->thread.saved_task = NULL; |
97 | 97 | ||
98 | /* XXX need to check runqueues[cpu].idle */ | ||
99 | if (current->pid == 0) | ||
100 | switch_timers(0); | ||
101 | |||
102 | switch_threads(&from->thread.switch_buf, | 98 | switch_threads(&from->thread.switch_buf, |
103 | &to->thread.switch_buf); | 99 | &to->thread.switch_buf); |
104 | 100 | ||
105 | arch_switch_to(current->thread.prev_sched, current); | 101 | arch_switch_to(current->thread.prev_sched, current); |
106 | 102 | ||
107 | if (current->pid == 0) | ||
108 | switch_timers(1); | ||
109 | |||
110 | if (current->thread.saved_task) | 103 | if (current->thread.saved_task) |
111 | show_regs(&(current->thread.regs)); | 104 | show_regs(&(current->thread.regs)); |
112 | next= current->thread.saved_task; | 105 | next= current->thread.saved_task; |
@@ -251,7 +244,9 @@ void default_idle(void) | |||
251 | if (need_resched()) | 244 | if (need_resched()) |
252 | schedule(); | 245 | schedule(); |
253 | 246 | ||
247 | switch_timers(1); | ||
254 | idle_sleep(10); | 248 | idle_sleep(10); |
249 | switch_timers(0); | ||
255 | } | 250 | } |
256 | } | 251 | } |
257 | 252 | ||
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 49c113b576b7..1c5267ec13b0 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
@@ -59,17 +59,11 @@ static void real_alarm_handler(int sig, struct sigcontext *sc) | |||
59 | { | 59 | { |
60 | struct uml_pt_regs regs; | 60 | struct uml_pt_regs regs; |
61 | 61 | ||
62 | if (sig == SIGALRM) | ||
63 | switch_timers(0); | ||
64 | |||
65 | if (sc != NULL) | 62 | if (sc != NULL) |
66 | copy_sc(®s, sc); | 63 | copy_sc(®s, sc); |
67 | regs.is_user = 0; | 64 | regs.is_user = 0; |
68 | unblock_signals(); | 65 | unblock_signals(); |
69 | timer_handler(sig, ®s); | 66 | timer_handler(sig, ®s); |
70 | |||
71 | if (sig == SIGALRM) | ||
72 | switch_timers(1); | ||
73 | } | 67 | } |
74 | 68 | ||
75 | void alarm_handler(int sig, struct sigcontext *sc) | 69 | void alarm_handler(int sig, struct sigcontext *sc) |
@@ -116,6 +110,7 @@ void (*handlers[_NSIG])(int sig, struct sigcontext *sc); | |||
116 | void handle_signal(int sig, struct sigcontext *sc) | 110 | void handle_signal(int sig, struct sigcontext *sc) |
117 | { | 111 | { |
118 | unsigned long pending = 1UL << sig; | 112 | unsigned long pending = 1UL << sig; |
113 | int timer = switch_timers(0); | ||
119 | 114 | ||
120 | do { | 115 | do { |
121 | int nested, bail; | 116 | int nested, bail; |
@@ -152,6 +147,8 @@ void handle_signal(int sig, struct sigcontext *sc) | |||
152 | if (!nested) | 147 | if (!nested) |
153 | pending = from_irq_stack(nested); | 148 | pending = from_irq_stack(nested); |
154 | } while (pending); | 149 | } while (pending); |
150 | |||
151 | switch_timers(timer); | ||
155 | } | 152 | } |
156 | 153 | ||
157 | extern void hard_handler(int sig); | 154 | extern void hard_handler(int sig); |
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 5939653f99ea..a16a0f484edc 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include "os.h" | 12 | #include "os.h" |
13 | #include "user.h" | 13 | #include "user.h" |
14 | 14 | ||
15 | static int is_real_timer = 0; | ||
16 | |||
15 | int set_interval(int is_virtual) | 17 | int set_interval(int is_virtual) |
16 | { | 18 | { |
17 | int usec = 1000000/UM_HZ; | 19 | int usec = 1000000/UM_HZ; |
@@ -39,12 +41,14 @@ void disable_timer(void) | |||
39 | signal(SIGVTALRM, SIG_IGN); | 41 | signal(SIGVTALRM, SIG_IGN); |
40 | } | 42 | } |
41 | 43 | ||
42 | void switch_timers(int to_real) | 44 | int switch_timers(int to_real) |
43 | { | 45 | { |
44 | struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); | 46 | struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); |
45 | struct itimerval enable = ((struct itimerval) { { 0, 1000000/UM_HZ }, | 47 | struct itimerval enable; |
46 | { 0, 1000000/UM_HZ }}); | 48 | int old, new, old_type = is_real_timer; |
47 | int old, new; | 49 | |
50 | if(to_real == old_type) | ||
51 | return to_real; | ||
48 | 52 | ||
49 | if (to_real) { | 53 | if (to_real) { |
50 | old = ITIMER_VIRTUAL; | 54 | old = ITIMER_VIRTUAL; |
@@ -55,10 +59,19 @@ void switch_timers(int to_real) | |||
55 | new = ITIMER_VIRTUAL; | 59 | new = ITIMER_VIRTUAL; |
56 | } | 60 | } |
57 | 61 | ||
58 | if ((setitimer(old, &disable, NULL) < 0) || | 62 | if (setitimer(old, &disable, &enable) < 0) |
59 | (setitimer(new, &enable, NULL))) | 63 | printk(UM_KERN_ERR "switch_timers - setitimer disable failed, " |
60 | printk(UM_KERN_ERR "switch_timers - setitimer failed, " | 64 | "errno = %d\n", errno); |
65 | |||
66 | if((enable.it_value.tv_sec == 0) && (enable.it_value.tv_usec == 0)) | ||
67 | enable.it_value = enable.it_interval; | ||
68 | |||
69 | if (setitimer(new, &enable, NULL)) | ||
70 | printk(UM_KERN_ERR "switch_timers - setitimer enable failed, " | ||
61 | "errno = %d\n", errno); | 71 | "errno = %d\n", errno); |
72 | |||
73 | is_real_timer = to_real; | ||
74 | return old_type; | ||
62 | } | 75 | } |
63 | 76 | ||
64 | unsigned long long os_nsecs(void) | 77 | unsigned long long os_nsecs(void) |