linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] timer.c negative shift, kernel 2.5.39
@ 2002-09-29 19:12 Rolf Fokkens
  0 siblings, 0 replies; only message in thread
From: Rolf Fokkens @ 2002-09-29 19:12 UTC (permalink / raw)
  To: linux-kernel, torvalds

Hi!

It appears that kernel time keeping may become unpredictable when HZ is
raised to large values due to negative shift operations in timer.c:

  time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);

Suppose on x86:
        HZ = 2048
and     SHIFT_SCALE = 22
and     SHIFT_UPDATE = (SHIFT_KG + MAXTC) = 12
then
        SHIFT_HZ = 11
and     (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE) = -1

This negative number is a problem for shift operations. The
following patch takes care of it (I hope).

Currently include/linux/timex.h prohibits HZ values greater than 1536,
which in turn prevents the case described above... though this is only
because of the values of SHIFT_SCALE, SHIFT_KG and MAXTC. This patch
allows values of HZ up to 3072.


Rolf Fokkens
fokkensr@fokkensr.vertis.nl

(3d post of this patch)


diff -ruN linux-2.5.39.orig/kernel/timer.c linux-2.5.39.signedshift/kernel/timer.c
--- linux-2.5.39.orig/kernel/timer.c	Sat Sep 28 14:42:56 2002
+++ linux-2.5.39.signedshift/kernel/timer.c	Sun Sep 29 18:33:33 2002
@@ -339,6 +339,11 @@
 	run_task_queue(&tq_immediate);
 }
 
+static inline long signedshift (long val, int nshift)
+{
+    return (nshift > 0 ? val << nshift : val >> -nshift);
+}
+
 /*
  * this routine handles the overflow of the microsecond field
  *
@@ -418,7 +423,7 @@
 	if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
 	    ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
 	time_offset += ltemp;
-	time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+        time_adj = signedshift (-ltemp, SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
     } else {
 	ltemp = time_offset;
 	if (!(time_status & STA_FLL))
@@ -426,7 +431,7 @@
 	if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE)
 	    ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE;
 	time_offset -= ltemp;
-	time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+        time_adj = signedshift (ltemp, SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
     }
 
     /*
diff -ruN linux-2.5.39.orig/include/linux/timex.h linux-2.5.39.signedshift/include/linux/timex.h
--- linux-2.5.39.orig/include/linux/timex.h	Mon Sep 16 20:43:47 2002
+++ linux-2.5.39.signedshift/include/linux/timex.h	Sun Sep 29 18:39:23 2002
@@ -75,6 +75,8 @@
 # define SHIFT_HZ	9
 #elif HZ >= 768 && HZ < 1536
 # define SHIFT_HZ	10
+#elif HZ >= 1536 && HZ < 3072
+# define SHIFT_HZ	11
 #else
 # error You lose.
 #endif

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-09-29 19:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-29 19:12 [PATCH] timer.c negative shift, kernel 2.5.39 Rolf Fokkens

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).