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); /* time.c */ #define BILLION (1000 * 1000 * 1000) -extern void switch_timers(int to_real); +extern int switch_timers(int to_real); extern void idle_sleep(int secs); extern int set_interval(int is_virtual); 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) do { current->thread.saved_task = NULL; - /* XXX need to check runqueues[cpu].idle */ - if (current->pid == 0) - switch_timers(0); - switch_threads(&from->thread.switch_buf, &to->thread.switch_buf); arch_switch_to(current->thread.prev_sched, current); - if (current->pid == 0) - switch_timers(1); - if (current->thread.saved_task) show_regs(&(current->thread.regs)); next= current->thread.saved_task; @@ -251,7 +244,9 @@ void default_idle(void) if (need_resched()) schedule(); + switch_timers(1); idle_sleep(10); + switch_timers(0); } } 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) { struct uml_pt_regs regs; - if (sig == SIGALRM) - switch_timers(0); - if (sc != NULL) copy_sc(®s, sc); regs.is_user = 0; unblock_signals(); timer_handler(sig, ®s); - - if (sig == SIGALRM) - switch_timers(1); } void alarm_handler(int sig, struct sigcontext *sc) @@ -116,6 +110,7 @@ void (*handlers[_NSIG])(int sig, struct sigcontext *sc); void handle_signal(int sig, struct sigcontext *sc) { unsigned long pending = 1UL << sig; + int timer = switch_timers(0); do { int nested, bail; @@ -152,6 +147,8 @@ void handle_signal(int sig, struct sigcontext *sc) if (!nested) pending = from_irq_stack(nested); } while (pending); + + switch_timers(timer); } 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 @@ #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)