aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-10-16 04:27:22 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:08 -0400
commit181bde801afae4304843ce95c868d4419ae87310 (patch)
treef33e6c88e36cda7699fc2dfe2b6ac9ccb3c6963f /arch/um
parent532d0fa4d104ca3e37dd38bc5073376fcc3c2712 (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.h2
-rw-r--r--arch/um/kernel/process.c9
-rw-r--r--arch/um/os-Linux/signal.c9
-rw-r--r--arch/um/os-Linux/time.c27
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
253extern void switch_timers(int to_real); 253extern int switch_timers(int to_real);
254extern void idle_sleep(int secs); 254extern void idle_sleep(int secs);
255extern int set_interval(int is_virtual); 255extern int set_interval(int is_virtual);
256extern void disable_timer(void); 256extern 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(&regs, sc); 63 copy_sc(&regs, sc);
67 regs.is_user = 0; 64 regs.is_user = 0;
68 unblock_signals(); 65 unblock_signals();
69 timer_handler(sig, &regs); 66 timer_handler(sig, &regs);
70
71 if (sig == SIGALRM)
72 switch_timers(1);
73} 67}
74 68
75void alarm_handler(int sig, struct sigcontext *sc) 69void alarm_handler(int sig, struct sigcontext *sc)
@@ -116,6 +110,7 @@ void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
116void handle_signal(int sig, struct sigcontext *sc) 110void 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
157extern void hard_handler(int sig); 154extern 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
15static int is_real_timer = 0;
16
15int set_interval(int is_virtual) 17int 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
42void switch_timers(int to_real) 44int 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
64unsigned long long os_nsecs(void) 77unsigned long long os_nsecs(void)