From 181bde801afae4304843ce95c868d4419ae87310 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Tue, 16 Oct 2007 01:27:22 -0700 Subject: 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 Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/time.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'arch/um/os-Linux/time.c') 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 @@ #include "os.h" #include "user.h" +static int is_real_timer = 0; + int set_interval(int is_virtual) { int usec = 1000000/UM_HZ; @@ -39,12 +41,14 @@ void disable_timer(void) signal(SIGVTALRM, SIG_IGN); } -void switch_timers(int to_real) +int switch_timers(int to_real) { struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - struct itimerval enable = ((struct itimerval) { { 0, 1000000/UM_HZ }, - { 0, 1000000/UM_HZ }}); - int old, new; + struct itimerval enable; + int old, new, old_type = is_real_timer; + + if(to_real == old_type) + return to_real; if (to_real) { old = ITIMER_VIRTUAL; @@ -55,10 +59,19 @@ void switch_timers(int to_real) new = ITIMER_VIRTUAL; } - if ((setitimer(old, &disable, NULL) < 0) || - (setitimer(new, &enable, NULL))) - printk(UM_KERN_ERR "switch_timers - setitimer failed, " + if (setitimer(old, &disable, &enable) < 0) + printk(UM_KERN_ERR "switch_timers - setitimer disable failed, " + "errno = %d\n", errno); + + if((enable.it_value.tv_sec == 0) && (enable.it_value.tv_usec == 0)) + enable.it_value = enable.it_interval; + + if (setitimer(new, &enable, NULL)) + printk(UM_KERN_ERR "switch_timers - setitimer enable failed, " "errno = %d\n", errno); + + is_real_timer = to_real; + return old_type; } unsigned long long os_nsecs(void) -- cgit v1.2.3-59-g8ed1b