[PATCH 8/11] UML - Tickless support

2007-09-19 Thread Jeff Dike
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 <[EMAIL PROTECTED]>
---
 arch/um/Kconfig |   12 --
 arch/um/defconfig   |5 +---
 arch/um/include/os.h|1 
 arch/um/kernel/process.c|3 ++
 arch/um/kernel/time.c   |   45 
 arch/um/os-Linux/skas/process.c |   27 
 arch/um/os-Linux/time.c |   29 -
 7 files changed, 67 insertions(+), 55 deletions(-)

Index: linux-2.6.20/arch/um/kernel/time.c
===
--- linux-2.6.20.orig/arch/um/kernel/time.c 2007-09-19 12:25:07.0 
-0400
+++ linux-2.6.20/arch/um/kernel/time.c  2007-09-19 12:25:07.0 -0400
@@ -20,41 +20,12 @@ unsigned long long sched_clock(void)
return (unsigned long long)jiffies_64 * (10 / HZ);
 }
 
-#ifdef CONFIG_UML_REAL_TIME_CLOCK
-static unsigned long long prev_nsecs[NR_CPUS];
-static long long delta[NR_CPUS];   /* Deviation per interval */
-#endif
-
 void timer_handler(int sig, struct uml_pt_regs *regs)
 {
-   unsigned long long ticks = 0;
unsigned long flags;
-#ifdef CONFIG_UML_REAL_TIME_CLOCK
-   int c = cpu();
-   if (prev_nsecs[c]) {
-   /* We've had 1 tick */
-   unsigned long long nsecs = os_nsecs();
-
-   delta[c] += nsecs - prev_nsecs[c];
-   prev_nsecs[c] = nsecs;
-
-   /* Protect against the host clock being set backwards */
-   if (delta[c] < 0)
-   delta[c] = 0;
-
-   ticks += (delta[c] * HZ) / BILLION;
-   delta[c] -= (ticks * BILLION) / HZ;
-   }
-   else prev_nsecs[c] = os_nsecs();
-#else
-   ticks = 1;
-#endif
 
local_irq_save(flags);
-   while (ticks > 0) {
-   do_IRQ(TIMER_IRQ, regs);
-   ticks--;
-   }
+   do_IRQ(TIMER_IRQ, regs);
local_irq_restore(flags);
 }
 
@@ -68,10 +39,8 @@ static void itimer_set_mode(enum clock_e
 
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
-   disable_timer();
-   break;
case CLOCK_EVT_MODE_ONESHOT:
-   BUG();
+   disable_timer();
break;
 
case CLOCK_EVT_MODE_RESUME:
@@ -79,13 +48,19 @@ static void itimer_set_mode(enum clock_e
}
 }
 
+static int itimer_next_event(unsigned long delta,
+struct clock_event_device *evt)
+{
+   return timer_one_shot(delta + 1);
+}
+
 static struct clock_event_device itimer_clockevent = {
.name   = "itimer",
.rating = 250,
.cpumask= CPU_MASK_ALL,
-   .features   = CLOCK_EVT_FEAT_PERIODIC,
+   .features   = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode   = itimer_set_mode,
-   .set_next_event = NULL,
+   .set_next_event = itimer_next_event,
.shift  = 32,
.irq= 0,
 };
Index: linux-2.6.20/arch/um/os-Linux/time.c
===
--- linux-2.6.20.orig/arch/um/os-Linux/time.c   2007-09-19 12:25:07.0 
-0400
+++ linux-2.6.20/arch/um/os-Linux/time.c2007-09-19 12:25:07.0 
-0400
@@ -26,6 +26,33 @@ int set_interval(void)
return 0;
 }
 
+int timer_one_shot(int ticks)
+{
+   unsigned long usec = ticks * 100 / UM_HZ;
+   unsigned long sec = usec / 100;
+   struct itimerval interval;
+
+   usec %= 100;
+   interval = ((struct itimerval) { { 0, 0 }, { sec, usec } });
+
+   if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
+   return -errno;
+
+   return 0;
+}
+
+static inline unsigned long long tv_to_nsec(struct timeval *tv)
+{
+   /* Cast tv->tv_sec to a long long in order to force this whole
+* calculation to 64 bits.  Otherwise, we'll get a negative
+* 32-bit number getting cast to a very large 64-bit number on
+* return.
+*/
+
+   return ((unsigned long long) tv->tv_sec) * BILLION +
+   tv->tv_usec * 1000;
+}
+
 void disable_timer(void)
 {
struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
@@ -74,7 +101,7 @@ unsigned long long os_nsecs(void)
struct timeval tv;
 

[PATCH 8/11] UML - Tickless support

2007-09-12 Thread Jeff Dike
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.

For now, process ticks are ignored.  This breaks userspace time
accounting and this will be fixed later.

Signed-off-by: Jeff Dike <[EMAIL PROTECTED]>
--
 arch/um/Kconfig |   12 --
 arch/um/defconfig   |5 +---
 arch/um/include/os.h|1 
 arch/um/kernel/process.c|3 ++
 arch/um/kernel/time.c   |   45 
 arch/um/os-Linux/skas/process.c |   11 ++---
 arch/um/os-Linux/time.c |   29 -
 7 files changed, 51 insertions(+), 55 deletions(-)

Index: linux-2.6.22/arch/um/kernel/time.c
===
--- linux-2.6.22.orig/arch/um/kernel/time.c 2007-09-12 15:12:35.0 
-0400
+++ linux-2.6.22/arch/um/kernel/time.c  2007-09-12 15:15:48.0 -0400
@@ -20,41 +20,12 @@ unsigned long long sched_clock(void)
return (unsigned long long)jiffies_64 * (10 / HZ);
 }
 
-#ifdef CONFIG_UML_REAL_TIME_CLOCK
-static unsigned long long prev_nsecs[NR_CPUS];
-static long long delta[NR_CPUS];   /* Deviation per interval */
-#endif
-
 void timer_handler(int sig, struct uml_pt_regs *regs)
 {
-   unsigned long long ticks = 0;
unsigned long flags;
-#ifdef CONFIG_UML_REAL_TIME_CLOCK
-   int c = cpu();
-   if (prev_nsecs[c]) {
-   /* We've had 1 tick */
-   unsigned long long nsecs = os_nsecs();
-
-   delta[c] += nsecs - prev_nsecs[c];
-   prev_nsecs[c] = nsecs;
-
-   /* Protect against the host clock being set backwards */
-   if (delta[c] < 0)
-   delta[c] = 0;
-
-   ticks += (delta[c] * HZ) / BILLION;
-   delta[c] -= (ticks * BILLION) / HZ;
-   }
-   else prev_nsecs[c] = os_nsecs();
-#else
-   ticks = 1;
-#endif
 
local_irq_save(flags);
-   while (ticks > 0) {
-   do_IRQ(TIMER_IRQ, regs);
-   ticks--;
-   }
+   do_IRQ(TIMER_IRQ, regs);
local_irq_restore(flags);
 }
 
@@ -68,10 +39,8 @@ static void itimer_set_mode(enum clock_e
 
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
-   disable_timer();
-   break;
case CLOCK_EVT_MODE_ONESHOT:
-   BUG();
+   disable_timer();
break;
 
case CLOCK_EVT_MODE_RESUME:
@@ -79,13 +48,19 @@ static void itimer_set_mode(enum clock_e
}
 }
 
+static int itimer_next_event(unsigned long delta,
+struct clock_event_device *evt)
+{
+   return timer_one_shot(delta + 1);
+}
+
 static struct clock_event_device itimer_clockevent = {
.name   = "itimer",
.rating = 250,
.cpumask= CPU_MASK_ALL,
-   .features   = CLOCK_EVT_FEAT_PERIODIC,
+   .features   = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode   = itimer_set_mode,
-   .set_next_event = NULL,
+   .set_next_event = itimer_next_event,
.shift  = 32,
.irq= 0,
 };
Index: linux-2.6.22/arch/um/os-Linux/time.c
===
--- linux-2.6.22.orig/arch/um/os-Linux/time.c   2007-09-12 14:56:38.0 
-0400
+++ linux-2.6.22/arch/um/os-Linux/time.c2007-09-12 15:15:48.0 
-0400
@@ -26,6 +26,33 @@ int set_interval(void)
return 0;
 }
 
+int timer_one_shot(int ticks)
+{
+   unsigned long usec = ticks * 100 / UM_HZ;
+   unsigned long sec = usec / 100;
+   struct itimerval interval;
+
+   usec %= 100;
+   interval = ((struct itimerval) { { 0, 0 }, { sec, usec } });
+
+   if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
+   return -errno;
+
+   return 0;
+}
+
+static inline unsigned long long tv_to_nsec(struct timeval *tv)
+{
+   /* Cast tv->tv_sec to a long long in order to force this whole
+* calculation to 64 bits.  Otherwise, we'll get a negative
+* 32-bit number getting cast to a very large 64-bit number on
+* return.
+*/
+
+   return ((unsigned long long) tv->tv_sec) * BILLION +
+   tv->tv_usec * 1000;
+}
+
 void disable_timer(void)
 {
struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
@@ -78,7 +105,7 @@ unsigned long long os_nsecs(void)
struct timeval tv;
 
gettimeofday(&tv, NULL);
-   return (unsigned long long) tv.tv_sec