Skip to contentSkip to conversation

High-res-timers part 2 (x86 platform code) take 7

PATCH In review george anzinger 5 participants 36 messages Oct 25, 2002 – Jan 9, 2003

Subsystems (7)
VFS Library code MM core Scheduler +3 more subsystems
lore
Share & tools
lore
#0 lore raw

PATCH 2/3 High-res-timers part 2 (x86 platform code) take 7

This patch, in conjunction with the "core" high-res-timers patch implements high resolution timers on the i386 platforms. The high-res-timers use the periodic interrupt to "remind" the system to look at the clock. The clock should be relatively high resolution (1 micro second or better). This patch allows configuring of three possible clocks, the TSC, the ACPI pm timer, or the Programmable interrupt timer (PIT). Most of the changes in this patch are in the arch/i386/kernel/timer/* code.

This patch uses (if available) the APIC timer(s) to generate 1/HZ ticks and sub 1/HZ ticks as needed. The PIT still interrupts, but if the APIC timer is available, just causes the wall clock update. No attempt is made to make this interrupt happen on jiffie boundaries, however, the APIC timers are disciplined to expire on 1/HZ boundaries to give consistent timer latencies WRT to the system time.

With this patch applied and enabled (at config time in the processor feature section), the system clock will be the specified clock. The PIT is not used to keep track of time, but only to remind the system to look at the clock. Sub jiffies are kept and available for code that knows how to use them.

Depends on the core high res timers patch.

Patch is against 2.5.44

This patch as well as the POSIX clocks & timers patch is available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent) changes
*i386 The high-res changes for the i386 (x86) platform
posixhr The changes to the POSIX clocks & timers patch to
use high-res timers

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/Config.help +69 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/Config.help linux/arch/i386/Config.help
@@ -52,6 +52,75 @@
   Say Y here if you are building a kernel for a desktop, embedded
   or real-time system.  Say N if you are unsure.
 
+High-res-timers
+CONFIG_HIGH_RES_TIMERS
+  POSIX timers are available by default.  This option enables high
+  resolution POSIX timers.  With this option the resolution is at
+  least 1 micro second.  High resolution is not free.  If enabled this
+  option will add a small overhead each time a timer expires that is
+  not on a 1/HZ tick boundry.  If no such timers are used the overhead
+  is nil.
+
+  This option enables two additional POSIX CLOCKS, CLOCK_REALTIME_HR
+  and CLOCK_MONOTONIC_HR.  Note that this option does not change the
+  resolution of CLOCK_REALTIME or CLOCK_MONOTONIC which remain at 1/HZ
+  resolution.
+
+High-res-timers clock
+CONFIG_HIGH_RES_TIMER_ACPI_PM 
+  This option allows you to choose the wall clock timer for your system.
+  With high resolution timers on the x86 platforms it is best to keep
+  the interrupt generating timer separate from the time keeping timer.
+  On x86 platforms there are three possible sources implemented for the
+  wall clock.  These are:
+ 
+  <timer>				<resolution>
+  ACPI power management (pm) timer	~280 nano seconds
+  TSC (Time Stamp Counter)		1/CPU clock
+  PIT (Programmable Interrupt Timer)	~838 nano seconds
+
+  The PIT is used to generate interrupts and at any given time will be
+  programmed to interrupt when the next timer is to expire or on the
+  next 1/HZ tick.  For this reason it is best to not use this timer as
+  the wall clock timer.  This timer has a resolution of 838 nano
+  seconds.  THIS OPTION SHOULD ONLY BE USED IF BOTH ACPI AND TSC ARE
+  NOT AVAILABLE.
+
+  The TSC runs at the cpu clock rate (i.e. its resolution is 1/CPU
+  clock) and it has a very low access time.  However, it is subject,
+  in some (incorrect) processors, to throttling to cool the cpu, and
+  to other slow downs during power management.  If your cpu is correct
+  and does not change the TSC frequency for throttling or power
+  management this is the best clock timer.
+
+  The ACPI pm timer is available on systems with Advanced Configuration
+  and Power Interface support.  The pm timer is available on these
+  systems even if you don't use or enable ACPI in the software or the
+  BIOS (but see Default ACPI pm timer address).  The timer has a
+  resolution of about 280 nanoseconds, however, the access time is a bit
+  higher that that of the TSC.  Since it is part of ACPI it is intended
+  to keep track of time while the system is under power management, thus
+  it is not subject to the problems of the TSC.
+
+  If you enable the ACPI pm timer and it can not be found, it is
+  possible that your BIOS is not producing the ACPI table or that your
+  machine does not support ACPI.  In the former case, see "Default ACPI
+  pm timer address".  If the timer is not found the boot will fail when
+  trying to calibrate the delay timer.
+
+Default ACPI pm timer address
+CONFIG_HIGH_RES_TIMER_ACPI_PM_ADD
+  This option is available for use on systems where the BIOS does not
+  generate the ACPI tables if ACPI is not enabled.  For example some
+  BIOSes will not generate the ACPI tables if APM is enabled.  The ACPI
+  pm timer is still available but can not be found by the software.
+  This option allows you to supply the needed address.  When the high
+  resolution timers code finds a valid ACPI pm timer address it reports
+  it in the boot messages log (look for lines that begin with
+  "High-res-timers:").  You can turn on the ACPI support in the BIOS,
+  boot the system and find this value.  You can then enter it at
+  configure time.  Both the report and the entry are in decimal.
+
 CONFIG_X86
   This is Linux's home port.  Linux was originally native to the Intel
   386, and runs on all the later x86 processors including the Intel
arch/i386/config.in +18 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/config.in linux/arch/i386/config.in
@@ -156,6 +156,23 @@
 bool 'Huge TLB Page Support' CONFIG_HUGETLB_PAGE
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Configure High-Resolution-Timers' CONFIG_HIGH_RES_TIMERS
+#
+# We assume that if the box doesn't have a TSC it doesn't have ACPI either.
+#
+if [ "$CONFIG_HIGH_RES_TIMERS" = "y" -a "$CONFIG_X86_TSC" = "y" ]; then
+	choice 'Clock source?' \
+		"ACPI-pm-timer  CONFIG_HIGH_RES_TIMER_ACPI_PM  \
+		Time-stamp-counter/TSC  CONFIG_HIGH_RES_TIMER_TSC \
+		Programable-interrupt-timer/PIT CONFIG_HIGH_RES_TIMER_PIT" Time-stamp-counter/TSC
+else
+	if [ "$CONFIG_HIGH_RES_TIMERS" = "y" ]; then
+		define_bool CONFIG_HIGH_RES_TIMER_PIT y
+        fi
+fi
+if [ "$CONFIG_HIGH_RES_TIMER_ACPI_PM" = "y" ]; then
+	int 'Default ACPI pm timer address' CONFIG_HIGH_RES_TIMER_ACPI_PM_ADD 0
+fi 
 bool 'Preemptible Kernel' CONFIG_PREEMPT
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC
@@ -355,6 +372,7 @@
 else
    define_bool CONFIG_BLK_DEV_HD n
 fi
+
 endmenu
 
 mainmenu_option next_comment
arch/i386/kernel/apic.c +13 -3
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
@@ -800,7 +800,7 @@
  * P5 APIC double write bug.
  */
 
-#define APIC_DIVISOR 16
+#define APIC_DIVISOR 1
 
 void __setup_APIC_LVTT(unsigned int clocks)
 {
@@ -811,12 +811,12 @@
 	apic_write_around(APIC_LVTT, lvtt1_value);
 
 	/*
-	 * Divide PICLK by 16
+	 * Divide PICLK by 1
 	 */
 	tmp_value = apic_read(APIC_TDCR);
 	apic_write_around(APIC_TDCR, (tmp_value
 				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
-				| APIC_TDR_DIV_16);
+				| APIC_TDR_DIV_1);
 
 	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
 }
@@ -1021,10 +1021,20 @@
 		 * Interrupts are already masked off at this point.
 		 */
 		prof_counter[cpu] = prof_multiplier[cpu];
+		/* 
+		 * deal with profiling later...
+		 */
+#ifndef CONFIG_HIGH_RES_TIMERS
 		if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
 			__setup_APIC_LVTT(calibration_result/prof_counter[cpu]);
 			prof_old_multiplier[cpu] = prof_counter[cpu];
 		}
+#else
+		/*
+		* This is the 1/HZ count, can be changed by HRT code.
+		*/
+		__setup_APIC_LVTT(calibration_result);
+#endif
 
 #ifdef CONFIG_SMP
 		update_process_times(user_mode(regs));
arch/i386/kernel/time.c +97 -25

194 lines not on this page · raw message

arch/i386/kernel/timers/Makefile +6 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/kernel/timers/Makefile linux/arch/i386/kernel/timers/Makefile
@@ -6,6 +6,12 @@
 
 obj-y += timer_tsc.o
 obj-y += timer_pit.o
+obj-$(CONFIG_X86_TSC) -= timer_pit.o
+obj-$(CONFIG_HIGH_RES_TIMERS) -= timer_tsc.o
 obj-$(CONFIG_X86_CYCLONE)   += timer_cyclone.o
+obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += hrtimer_pm.o
+obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += high-res-tbxfroot.o
+obj-$(CONFIG_HIGH_RES_TIMER_TSC) += hrtimer_tsc.o
+obj-$(CONFIG_HIGH_RES_TIMER_PIT) += hrtimer_pit.o
 
 include $(TOPDIR)/Rules.make
arch/i386/kernel/timers/high-res-tbxfroot.c +272 -0

272 lines not on this page · raw message

arch/i386/kernel/timers/hrtimer_pit.c +163 -0

163 lines not on this page · raw message

arch/i386/kernel/timers/hrtimer_pm.c +196 -0

196 lines not on this page · raw message

arch/i386/kernel/timers/hrtimer_tsc.c +288 -0

288 lines not on this page · raw message

arch/i386/kernel/timers/timer.c +18 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/kernel/timers/timer.c linux/arch/i386/kernel/timers/timer.c
@@ -1,15 +1,32 @@
 #include <linux/kernel.h>
+#include <linux/hrtime.h>
 #include <asm/timer.h>
-
+/*
+ * export this here so it can be used by more than one clock source
+ */
+unsigned long fast_gettimeoffset_quotient;
 /* list of externed timers */
 extern struct timer_opts timer_pit;
 extern struct timer_opts timer_tsc;
+extern struct timer_opts hrtimer_tsc;
+extern struct timer_opts hrtimer_pm;
+extern struct timer_opts hrtimer_pit;
 
 /* list of timers, ordered by preference, NULL terminated */
 static struct timer_opts* timers[] = {
+#ifdef CONFIG_HIGH_RES_TIMERS
+#ifdef CONFIG_HIGH_RES_TIMER_ACPI_PM
+	&hrtimer_pm,
+#elif  CONFIG_HIGH_RES_TIMER_TSC
+	&hrtimer_tsc,
+#elif  CONFIG_HIGH_RES_TIMER_PIT
+	&hrtimer_pit,
+#endif
+#else
 	&timer_tsc,
 #ifndef CONFIG_X86_TSC
 	&timer_pit,
+#endif
 #endif
 	NULL,
 };
arch/i386/kernel/timers/timer_pit.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/kernel/timers/timer_pit.c linux/arch/i386/kernel/timers/timer_pit.c
@@ -9,6 +9,7 @@
 #include <asm/mpspec.h>
 #include <asm/timer.h>
 #include <asm/io.h>
+#include <linux/hrtime.h>
 
 extern spinlock_t i8259A_lock;
 extern spinlock_t i8253_lock;
arch/i386/kernel/timers/timer_tsc.c +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/kernel/timers/timer_tsc.c linux/arch/i386/kernel/timers/timer_tsc.c
@@ -26,7 +26,7 @@
  * Equal to 2^32 * (1 / (clocks per usec) ).
  * Initialized in time_init.
  */
-unsigned long fast_gettimeoffset_quotient;
+extern unsigned long fast_gettimeoffset_quotient;
 
 static unsigned long get_offset_tsc(void)
 {
arch/i386/mach-generic/do_timer.h +5 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/arch/i386/mach-generic/do_timer.h linux/arch/i386/mach-generic/do_timer.h
@@ -14,6 +14,11 @@
 static inline void do_timer_interrupt_hook(struct pt_regs *regs)
 {
 	do_timer(regs);
+        IF_HIGH_RES(
+                if (!(new_jiffie() & 1))
+                        return;
+                jiffies_intr = 0;
+                )
 /*
  * In the SMP case we use the local APIC timer interrupt to do the
  * profiling, except when we simulate SMP mode on a uniprocessor
include/asm-i386/hrtime-M386.h +247 -0

247 lines not on this page · raw message

include/asm-i386/hrtime-M586.h +165 -0

165 lines not on this page · raw message

include/asm-i386/hrtime-Macpi.h +177 -0

177 lines not on this page · raw message

include/asm-i386/hrtime.h +486 -0

486 lines not on this page · raw message

include/asm-i386/sc_math.h +143 -0

143 lines not on this page · raw message

include/asm-i386/signal.h +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/include/asm-i386/signal.h linux/include/asm-i386/signal.h
@@ -3,6 +3,8 @@
 
 #include <linux/types.h>
 #include <linux/linkage.h>
+#include <linux/time.h>
+#include <asm/ptrace.h>
 
 /* Avoid too many header ordering problems.  */
 struct siginfo;
kernel/posix-timers.c +5 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-core/kernel/posix-timers.c linux/kernel/posix-timers.c
@@ -186,6 +186,11 @@
 	unsigned long sec = tp->tv_sec;
 	long nsec = tp->tv_nsec + res - 1;
 
+	if( nsec > NSEC_PER_SEC){
+		sec++;
+		nsec -= NSEC_PER_SEC;
+	}
+
 	/*
 	 * A note on jiffy overflow: It is possible for the system to
 	 * have been up long enough for the jiffies quanity to overflow.
#1 lore raw
Quoted 11 lines · george anzinger

This patch, in conjunction with the "core" high-res-timers patch implements high resolution timers on the i386 platforms. The high-res-timers use the periodic interrupt to "remind" the system to look at the clock. The clock should be relatively high resolution (1 micro second or better). This patch allows configuring of three possible clocks, the TSC, the ACPI pm timer, or the Programmable interrupt timer (PIT). Most of the changes in this patch are in the arch/i386/kernel/timer/* code.

Any suggestions on making this patch "more friendly" with 2.5.44-ac3? Apparently some of his patch mucked around in the timers source files as well as defining completely opposite macros in arch/i386/kernel/timers/Makefile. I might of missed it, but I didn't notice anything in his changelog which would jump out at me, except for some of the Cyrix fixes. I'm going to give it a shot, but I thought I'd ask as well.

Cheers,
Nicholas

#2 lore raw

Re: [PATCH 2/3] ac3 fix High-res-timers part 2 (x86 platform code) take 7

Quoted 14 lines · Nicholas Wourms
Quoted 11 lines · george anzinger

This patch, in conjunction with the "core" high-res-timers patch implements high resolution timers on the i386 platforms. The high-res-timers use the periodic interrupt to "remind" the system to look at the clock. The clock should be relatively high resolution (1 micro second or better). This patch allows configuring of three possible clocks, the TSC, the ACPI pm timer, or the Programmable interrupt timer (PIT). Most of the changes in this patch are in the arch/i386/kernel/timer/* code.

Quoted 7 lines

Any suggestions on making this patch "more friendly" with 2.5.44-ac3? Apparently some of his patch mucked around in the timers source files as well as defining completely opposite macros in arch/i386/kernel/timers/Makefile. I might of missed it, but I didn't notice anything in his changelog which would jump out at me, except for some of the Cyrix fixes. I'm going to give it a shot, but I thought I'd ask as well.

This is what I think it should look like, but I confess I am guessing that make will do the += -= in the order presented.

Just apply the attached patch after the "hrtimers-i386" patch and it should fix every thing up.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/kernel/timers/Makefile +6 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-ac3-hr-base/arch/i386/kernel/timers/Makefile linux/arch/i386/kernel/timers/Makefile
@@ -7,5 +7,10 @@
 obj-$(CONFIG_X86_TSC)		+= timer_tsc.o
 obj-$(CONFIG_X86_PIT)		+= timer_pit.o
 obj-$(CONFIG_X86_CYCLONE)	+= timer_cyclone.o
-
+obj-$(CONFIG_HIGH_RES_TIMERS) -= timer_tsc.o
+obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += hrtimer_pm.o
+obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += high-res-tbxfroot.o
+obj-$(CONFIG_HIGH_RES_TIMER_TSC) += hrtimer_tsc.o
+obj-$(CONFIG_HIGH_RES_TIMER_PIT) += hrtimer_pit.o
+ 
 include $(TOPDIR)/Rules.make
arch/i386/kernel/timers/timer.c +17 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-ac3-hr-base/arch/i386/kernel/timers/timer.c linux/arch/i386/kernel/timers/timer.c
@@ -1,17 +1,34 @@
 #include <linux/kernel.h>
 #include <asm/timer.h>
+/*
+ * export this here so it can be used by more than one clock source
+ */
+unsigned long fast_gettimeoffset_quotient;
 
 /* list of externed timers */
 extern struct timer_opts timer_pit;
 extern struct timer_opts timer_tsc;
+extern struct timer_opts hrtimer_tsc;
+extern struct timer_opts hrtimer_pm;
+extern struct timer_opts hrtimer_pit;
 
 /* list of timers, ordered by preference, NULL terminated */
 static struct timer_opts* timers[] = {
+#ifdef CONFIG_HIGH_RES_TIMERS
+#ifdef CONFIG_HIGH_RES_TIMER_ACPI_PM
+	&hrtimer_pm,
+#elif  CONFIG_HIGH_RES_TIMER_TSC
+	&hrtimer_tsc,
+#elif  CONFIG_HIGH_RES_TIMER_PIT
+	&hrtimer_pit,
+#endif
+#else
 #ifdef CONFIG_X86_TSC
 	&timer_tsc,
 #endif
 #ifdef CONFIG_X86_PIT
 	&timer_pit,
+#endif
 #endif
 	NULL,
 };
arch/i386/kernel/timers/timer_pit.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-ac3-hr-base/arch/i386/kernel/timers/timer_pit.c linux/arch/i386/kernel/timers/timer_pit.c
@@ -11,6 +11,7 @@
 #include <asm/smp.h>
 #include <asm/io.h>
 #include <asm/arch_hooks.h>
+#include <linux/hrtime.h>
 
 extern spinlock_t i8259A_lock;
 extern spinlock_t i8253_lock;
#3 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 7

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.44

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86)
platform
*posixhr The changes to the POSIX clocks & timers
patch to
use high-res timers

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-x86/include/linux/sched.h linux/include/linux/sched.h
@@ -281,6 +281,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };

Only in linux-2.5.44-x86/include/linux: sched.hx

kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

#4 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 8

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.44-bk1

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86)
platform
*posixhr The changes to the POSIX clocks & timers
patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
kernel/posix-timers.c +155 -5
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-bk1-i386/kernel/posix-timers.c linux/kernel/posix-timers.c
@@ -23,6 +23,7 @@
 #include <linux/posix-timers.h>
 #include <linux/compiler.h>
 #include <linux/id_reuse.h>
+#include <linux/hrtime.h>
 
 #ifndef div_long_long_rem
 #include <asm/div64.h>
@@ -33,7 +34,7 @@
 		       result; })
 
 #endif	 /* ifndef div_long_long_rem */
-
+#define CONFIGURE_MIN_INTERVAL 500000
 /*
  * Management arrays for POSIX timers.	 Timers are kept in slab memory
  * Timer ids are allocated by an external routine that keeps track of the
@@ -156,6 +157,7 @@
 
 int do_posix_clock_monotonic_settime(struct timespec *tp);
 
+IF_HIGH_RES(static int high_res_guard = 0;)
 /* 
  * Initialize everything, well, just everything in Posix clocks/timers ;)
  */
@@ -174,6 +176,15 @@
 	posix_timers_cache = kmem_cache_create("posix_timers_cache",
 		sizeof(struct k_itimer), 0, 0, 0, 0);
 	idr_init(&posix_timers_id);
+	IF_HIGH_RES(clock_realtime.res = CONFIG_HIGH_RES_RESOLUTION;
+		    register_posix_clock(CLOCK_REALTIME_HR,&clock_realtime);
+		    clock_monotonic.res = CONFIG_HIGH_RES_RESOLUTION;
+		    register_posix_clock(CLOCK_MONOTONIC_HR,&clock_monotonic);
+		    high_res_guard = nsec_to_arch_cycles(CONFIGURE_MIN_INTERVAL);
+		);
+#ifdef	 final_clock_init
+	final_clock_init();	  // defined by arch header file
+#endif
 	return 0;
 }
 
@@ -214,8 +225,23 @@
 	 * We trust that the optimizer will use the remainder from the 
 	 * above div in the following operation as long as they are close. 
 	 */
-	return	0;
+	return	 (nsec_to_arch_cycles(nsec % (NSEC_PER_SEC / HZ)));
+}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static void tstotimer(struct itimerspec * time, struct k_itimer * timer)
+{
+	int res = posix_clocks[timer->it_clock].res;
+
+	timer->it_timer.sub_expires = tstojiffie(&time->it_value,
+						 res,
+						 &timer->it_timer.expires);
+	timer->it_sub_incr = tstojiffie(&time->it_interval,
+					res,
+					(unsigned long*) &timer->it_incr);
+	if ((unsigned long)timer->it_incr > MAX_JIFFY_OFFSET)
+		timer->it_incr = MAX_JIFFY_OFFSET;
 }
+#else
 static void tstotimer(struct itimerspec * time, struct k_itimer * timer)
 {
 	int res = posix_clocks[timer->it_clock].res;
@@ -228,6 +254,7 @@
 }
  
 
+#endif
 
 /* PRECONDITION:
  * timr->it_lock must be locked
@@ -265,6 +292,47 @@
 	}
 }
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+/*
+ * This bit of code is to protect the system from being consumed by
+ * repeating timer expirations.	 We detect overrun and adjust the
+ * next time to be at least high_res_guard out. We clock the overrun
+ * but only AFTER the next expire as it has not really happened yet.
+ *
+ * Careful, only do this if the timer repeat time is less than
+ * high_res_guard AND we have fallen behind.
+
+ * All this will go away with signal delivery callback...
+ */
+
+static inline void  do_overrun_protect(struct k_itimer *timr)
+{
+	timr->it_overrun_deferred = 0;
+
+	if (! timr->it_incr &&
+	    (high_res_guard > timr->it_sub_incr)){
+		int offset = quick_update_jiffies_sub( timr->it_timer.expires);
+
+		offset -= timr->it_timer.sub_expires;
+		// touch_nmi_watchdog();
+		offset += high_res_guard;
+		if (offset <= 0){
+			return;
+		}
+		// expire time is in the past (or within the guard window)
+
+		timr->it_overrun_deferred = (offset / timr->it_sub_incr) - 1;
+		timr->it_timer.sub_expires += 
+			offset - (offset % timr->it_sub_incr);
+				     
+		while ((timr->it_timer.sub_expires -  cycles_per_jiffies) >= 0){
+			timr->it_timer.sub_expires -= cycles_per_jiffies;
+			timr->it_timer.expires++;
+		}
+	}
+}
+
+#endif
 /* 
  * Notify the task and set up the timer for the next expiration (if applicable).
  * This function requires that the k_itimer structure it_lock is taken.
@@ -277,7 +345,8 @@
 
 	/* Set up the timer for the next interval (if there is one) */
 	if ((interval = timr->it_incr) == 0){
-		{
+		IF_HIGH_RES(if(timr->it_sub_incr == 0)
+			){
 			set_timer_inactive(timr);
 			return;
 		}
@@ -285,6 +354,13 @@
 	if (interval > (unsigned long) LONG_MAX)
 		interval = LONG_MAX;
 	timr->it_timer.expires += interval;
+	IF_HIGH_RES(timr->it_timer.sub_expires += timr->it_sub_incr;
+		    if ((timr->it_timer.sub_expires - cycles_per_jiffies) >= 0){
+			    timr->it_timer.sub_expires -= cycles_per_jiffies;
+			    timr->it_timer.expires++;
+		    }
+		    do_overrun_protect(timr);
+		);
 	add_timer(&timr->it_timer);
 }
 
@@ -543,17 +619,39 @@
 
 	do {
 		expires = timr->it_timer.expires;  
+		IF_HIGH_RES(sub_expires = timr->it_timer.sub_expires);
 	} while ((volatile long)(timr->it_timer.expires) != expires);
 
+	IF_HIGH_RES(write_lock(&xtime_lock);
+		    update_jiffies_sub());
 	if (expires && timer_pending(&timr->it_timer)){
 		expires -= jiffies;
+		IF_HIGH_RES(sub_expires -=  sub_jiffie());
 	}else{
 		sub_expires = expires = 0;
 	}
+	IF_HIGH_RES( write_unlock(&xtime_lock));
 
 	jiffies_to_timespec(expires, &cur_setting->it_value);
 	jiffies_to_timespec(timr->it_incr, &cur_setting->it_interval);
 
+	IF_HIGH_RES(cur_setting->it_value.tv_nsec += 
+		    arch_cycles_to_nsec( sub_expires);
+		    if (cur_setting->it_value.tv_nsec < 0){
+			    cur_setting->it_value.tv_nsec += NSEC_PER_SEC;
+			    cur_setting->it_value.tv_sec--;
+		    }
+		    if ((cur_setting->it_value.tv_nsec - NSEC_PER_SEC) >= 0){
+			    cur_setting->it_value.tv_nsec -= NSEC_PER_SEC;
+			    cur_setting->it_value.tv_sec++;
+		    }
+		    cur_setting->it_interval.tv_nsec += 
+		    arch_cycles_to_nsec(timr->it_sub_incr);
+		    if ((cur_setting->it_interval.tv_nsec - NSEC_PER_SEC) >= 0){
+			    cur_setting->it_interval.tv_nsec -= NSEC_PER_SEC;
+			    cur_setting->it_interval.tv_sec++;
+		    }
+		);	     
 	if (cur_setting->it_value.tv_sec < 0){
 		cur_setting->it_value.tv_nsec = 1;
 		cur_setting->it_value.tv_sec = 0;
@@ -699,6 +797,7 @@
 
 	/* disable the timer */
 	timr->it_incr = 0;
+	IF_HIGH_RES(timr->it_sub_incr = 0);
 	/* 
 	 * careful here.  If smp we could be in the "fire" routine which will
 	 * be spinning as we hold the lock.  But this is ONLY an SMP issue.
@@ -723,6 +822,7 @@
 	if ((new_setting->it_value.tv_sec == 0) &&
 	    (new_setting->it_value.tv_nsec == 0)) {
 		timr->it_timer.expires = 0;
+		IF_HIGH_RES(timr->it_timer.sub_expires = 0 );
 		return 0;
 	}
 
@@ -743,10 +843,12 @@
 	 * For some reason the timer does not fire immediately if expires is
 	 * equal to jiffies, so the timer callback function is called directly.
 	 */
+#ifndef	 CONFIG_HIGH_RES_TIMERS
 	if (timr->it_timer.expires == jiffies) {
 		posix_timer_fire(timr);
 		return 0;
 	}
+#endif
 	timr->it_overrun_deferred = 
 		timr->it_overrun_last = 
 		timr->it_overrun = 0;
@@ -808,6 +910,7 @@
 static inline int do_timer_delete(struct k_itimer  *timer)
 {
 	timer->it_incr = 0;
+	IF_HIGH_RES(timer->it_sub_incr = 0);
 #ifdef CONFIG_SMP
 	if ( timer_active(timer) && ! del_timer(&timer->it_timer)){
 		/*
@@ -905,8 +1008,25 @@
 		return clock->clock_get(tp);
 	}
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+	{
+		unsigned long flags;
+		write_lock_irqsave(&xtime_lock, flags);
+		update_jiffies_sub();
+		update_real_wall_time();  
+		tp->tv_sec = xtime.tv_sec;
+		tp->tv_nsec = xtime.tv_nsec;
+		tp->tv_nsec += arch_cycles_to_nsec(sub_jiffie());
+		write_unlock_irqrestore(&xtime_lock, flags);
+		if ( tp->tv_nsec >  NSEC_PER_SEC ){
+			tp->tv_nsec -= NSEC_PER_SEC ;
+			tp->tv_sec++;
+		}
+	}
+#else
 	do_gettimeofday((struct timeval*)tp);
 	tp->tv_nsec *= NSEC_PER_USEC;
+#endif
 	return 0;
 }
 
@@ -921,8 +1041,9 @@
 {
 	long sub_sec;
 	u64 jiffies_64_f;
+	IF_HIGH_RES(long sub_jiff_offset;)
 
-#if (BITS_PER_LONG > 32) 
+#if (BITS_PER_LONG > 32) && !defined(CONFIG_HIGH_RES_TIMERS)
 
 	jiffies_64_f = jiffies_64;
 
@@ -936,6 +1057,8 @@
 		read_lock_irqsave(&xtime_lock, flags);
 		jiffies_64_f = jiffies_64;
 
+		IF_HIGH_RES(sub_jiff_offset =	
+			    quick_update_jiffies_sub(jiffies));
 
 		read_unlock_irqrestore(&xtime_lock, flags);
 	}
@@ -944,14 +1067,34 @@
 	do {
 		jiffies_f = jiffies;
 		barrier();
+		IF_HIGH_RES(
+			sub_jiff_offset = 
+			quick_update_jiffies_sub(jiffies_f));
 		jiffies_64_f = jiffies_64;
 	} while (unlikely(jiffies_f != jiffies));
 
+#else /* 64 bit long and high-res but no SMP if I did the Venn right */
+	do {
+		jiffies_64_f = jiffies_64;
+		barrier();
+		sub_jiff_offset = quick_update_jiffies_sub(jiffies_64_f);
+	} while (unlikely(jiffies_64_f != jiffies_64));
 
 #endif
-	tp->tv_sec = div_long_long_rem(jiffies_64_f,HZ,&sub_sec);
+	/*
+	 * Remember that quick_update_jiffies_sub() can return more
+	 * than a jiffies worth of cycles...
+	 */
+	IF_HIGH_RES(
+		while ( unlikely(sub_jiff_offset > cycles_per_jiffies)){
+			sub_jiff_offset -= cycles_per_jiffies;
+			jiffies_64_f++;
+		}
+		)
+		tp->tv_sec = div_long_long_rem(jiffies_64_f,HZ,&sub_sec);
 
 	tp->tv_nsec = sub_sec * (NSEC_PER_SEC / HZ);
+	IF_HIGH_RES(tp->tv_nsec += arch_cycles_to_nsec(sub_jiff_offset));
 	return 0;
 }
 
@@ -1110,6 +1253,7 @@
 			 * del_timer_sync() will return 0, thus
 			 * active is zero... and so it goes.
 			 */
+			IF_HIGH_RES(new_timer.sub_expires = )
 
 				tstojiffie(&t,
 					   posix_clocks[which_clock].res,
@@ -1131,9 +1275,15 @@
 	}
 	if (active && rmtp ) {
 		unsigned long jiffies_f = jiffies;
+		IF_HIGH_RES(
+			long sub_jiff = 
+			quick_update_jiffies_sub(jiffies_f));
 
 		jiffies_to_timespec(new_timer.expires - jiffies_f, &t);
 
+		IF_HIGH_RES(t.tv_nsec += 
+			    arch_cycles_to_nsec(new_timer.sub_expires -
+						sub_jiff));
 		while (t.tv_nsec < 0){
 			t.tv_nsec += NSEC_PER_SEC;
 			t.tv_sec--;

Binary files linux-2.5.44-bk1-i386/scripts/fixdep and linux/scripts/fixdep differ

#5 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 8

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.44-bk1

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86)
platform
*posixhr The changes to the POSIX clocks & timers
patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
kernel/posix-timers.c +155 -5
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-bk1-i386/kernel/posix-timers.c linux/kernel/posix-timers.c
@@ -23,6 +23,7 @@
 #include <linux/posix-timers.h>
 #include <linux/compiler.h>
 #include <linux/id_reuse.h>
+#include <linux/hrtime.h>
 
 #ifndef div_long_long_rem
 #include <asm/div64.h>
@@ -33,7 +34,7 @@
 		       result; })
 
 #endif	 /* ifndef div_long_long_rem */
-
+#define CONFIGURE_MIN_INTERVAL 500000
 /*
  * Management arrays for POSIX timers.	 Timers are kept in slab memory
  * Timer ids are allocated by an external routine that keeps track of the
@@ -156,6 +157,7 @@
 
 int do_posix_clock_monotonic_settime(struct timespec *tp);
 
+IF_HIGH_RES(static int high_res_guard = 0;)
 /* 
  * Initialize everything, well, just everything in Posix clocks/timers ;)
  */
@@ -174,6 +176,15 @@
 	posix_timers_cache = kmem_cache_create("posix_timers_cache",
 		sizeof(struct k_itimer), 0, 0, 0, 0);
 	idr_init(&posix_timers_id);
+	IF_HIGH_RES(clock_realtime.res = CONFIG_HIGH_RES_RESOLUTION;
+		    register_posix_clock(CLOCK_REALTIME_HR,&clock_realtime);
+		    clock_monotonic.res = CONFIG_HIGH_RES_RESOLUTION;
+		    register_posix_clock(CLOCK_MONOTONIC_HR,&clock_monotonic);
+		    high_res_guard = nsec_to_arch_cycles(CONFIGURE_MIN_INTERVAL);
+		);
+#ifdef	 final_clock_init
+	final_clock_init();	  // defined by arch header file
+#endif
 	return 0;
 }
 
@@ -214,8 +225,23 @@
 	 * We trust that the optimizer will use the remainder from the 
 	 * above div in the following operation as long as they are close. 
 	 */
-	return	0;
+	return	 (nsec_to_arch_cycles(nsec % (NSEC_PER_SEC / HZ)));
+}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static void tstotimer(struct itimerspec * time, struct k_itimer * timer)
+{
+	int res = posix_clocks[timer->it_clock].res;
+
+	timer->it_timer.sub_expires = tstojiffie(&time->it_value,
+						 res,
+						 &timer->it_timer.expires);
+	timer->it_sub_incr = tstojiffie(&time->it_interval,
+					res,
+					(unsigned long*) &timer->it_incr);
+	if ((unsigned long)timer->it_incr > MAX_JIFFY_OFFSET)
+		timer->it_incr = MAX_JIFFY_OFFSET;
 }
+#else
 static void tstotimer(struct itimerspec * time, struct k_itimer * timer)
 {
 	int res = posix_clocks[timer->it_clock].res;
@@ -228,6 +254,7 @@
 }
  
 
+#endif
 
 /* PRECONDITION:
  * timr->it_lock must be locked
@@ -265,6 +292,47 @@
 	}
 }
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+/*
+ * This bit of code is to protect the system from being consumed by
+ * repeating timer expirations.	 We detect overrun and adjust the
+ * next time to be at least high_res_guard out. We clock the overrun
+ * but only AFTER the next expire as it has not really happened yet.
+ *
+ * Careful, only do this if the timer repeat time is less than
+ * high_res_guard AND we have fallen behind.
+
+ * All this will go away with signal delivery callback...
+ */
+
+static inline void  do_overrun_protect(struct k_itimer *timr)
+{
+	timr->it_overrun_deferred = 0;
+
+	if (! timr->it_incr &&
+	    (high_res_guard > timr->it_sub_incr)){
+		int offset = quick_update_jiffies_sub( timr->it_timer.expires);
+
+		offset -= timr->it_timer.sub_expires;
+		// touch_nmi_watchdog();
+		offset += high_res_guard;
+		if (offset <= 0){
+			return;
+		}
+		// expire time is in the past (or within the guard window)
+
+		timr->it_overrun_deferred = (offset / timr->it_sub_incr) - 1;
+		timr->it_timer.sub_expires += 
+			offset - (offset % timr->it_sub_incr);
+				     
+		while ((timr->it_timer.sub_expires -  cycles_per_jiffies) >= 0){
+			timr->it_timer.sub_expires -= cycles_per_jiffies;
+			timr->it_timer.expires++;
+		}
+	}
+}
+
+#endif
 /* 
  * Notify the task and set up the timer for the next expiration (if applicable).
  * This function requires that the k_itimer structure it_lock is taken.
@@ -277,7 +345,8 @@
 
 	/* Set up the timer for the next interval (if there is one) */
 	if ((interval = timr->it_incr) == 0){
-		{
+		IF_HIGH_RES(if(timr->it_sub_incr == 0)
+			){
 			set_timer_inactive(timr);
 			return;
 		}
@@ -285,6 +354,13 @@
 	if (interval > (unsigned long) LONG_MAX)
 		interval = LONG_MAX;
 	timr->it_timer.expires += interval;
+	IF_HIGH_RES(timr->it_timer.sub_expires += timr->it_sub_incr;
+		    if ((timr->it_timer.sub_expires - cycles_per_jiffies) >= 0){
+			    timr->it_timer.sub_expires -= cycles_per_jiffies;
+			    timr->it_timer.expires++;
+		    }
+		    do_overrun_protect(timr);
+		);
 	add_timer(&timr->it_timer);
 }
 
@@ -543,17 +619,39 @@
 
 	do {
 		expires = timr->it_timer.expires;  
+		IF_HIGH_RES(sub_expires = timr->it_timer.sub_expires);
 	} while ((volatile long)(timr->it_timer.expires) != expires);
 
+	IF_HIGH_RES(write_lock(&xtime_lock);
+		    update_jiffies_sub());
 	if (expires && timer_pending(&timr->it_timer)){
 		expires -= jiffies;
+		IF_HIGH_RES(sub_expires -=  sub_jiffie());
 	}else{
 		sub_expires = expires = 0;
 	}
+	IF_HIGH_RES( write_unlock(&xtime_lock));
 
 	jiffies_to_timespec(expires, &cur_setting->it_value);
 	jiffies_to_timespec(timr->it_incr, &cur_setting->it_interval);
 
+	IF_HIGH_RES(cur_setting->it_value.tv_nsec += 
+		    arch_cycles_to_nsec( sub_expires);
+		    if (cur_setting->it_value.tv_nsec < 0){
+			    cur_setting->it_value.tv_nsec += NSEC_PER_SEC;
+			    cur_setting->it_value.tv_sec--;
+		    }
+		    if ((cur_setting->it_value.tv_nsec - NSEC_PER_SEC) >= 0){
+			    cur_setting->it_value.tv_nsec -= NSEC_PER_SEC;
+			    cur_setting->it_value.tv_sec++;
+		    }
+		    cur_setting->it_interval.tv_nsec += 
+		    arch_cycles_to_nsec(timr->it_sub_incr);
+		    if ((cur_setting->it_interval.tv_nsec - NSEC_PER_SEC) >= 0){
+			    cur_setting->it_interval.tv_nsec -= NSEC_PER_SEC;
+			    cur_setting->it_interval.tv_sec++;
+		    }
+		);	     
 	if (cur_setting->it_value.tv_sec < 0){
 		cur_setting->it_value.tv_nsec = 1;
 		cur_setting->it_value.tv_sec = 0;
@@ -699,6 +797,7 @@
 
 	/* disable the timer */
 	timr->it_incr = 0;
+	IF_HIGH_RES(timr->it_sub_incr = 0);
 	/* 
 	 * careful here.  If smp we could be in the "fire" routine which will
 	 * be spinning as we hold the lock.  But this is ONLY an SMP issue.
@@ -723,6 +822,7 @@
 	if ((new_setting->it_value.tv_sec == 0) &&
 	    (new_setting->it_value.tv_nsec == 0)) {
 		timr->it_timer.expires = 0;
+		IF_HIGH_RES(timr->it_timer.sub_expires = 0 );
 		return 0;
 	}
 
@@ -743,10 +843,12 @@
 	 * For some reason the timer does not fire immediately if expires is
 	 * equal to jiffies, so the timer callback function is called directly.
 	 */
+#ifndef	 CONFIG_HIGH_RES_TIMERS
 	if (timr->it_timer.expires == jiffies) {
 		posix_timer_fire(timr);
 		return 0;
 	}
+#endif
 	timr->it_overrun_deferred = 
 		timr->it_overrun_last = 
 		timr->it_overrun = 0;
@@ -808,6 +910,7 @@
 static inline int do_timer_delete(struct k_itimer  *timer)
 {
 	timer->it_incr = 0;
+	IF_HIGH_RES(timer->it_sub_incr = 0);
 #ifdef CONFIG_SMP
 	if ( timer_active(timer) && ! del_timer(&timer->it_timer)){
 		/*
@@ -905,8 +1008,25 @@
 		return clock->clock_get(tp);
 	}
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+	{
+		unsigned long flags;
+		write_lock_irqsave(&xtime_lock, flags);
+		update_jiffies_sub();
+		update_real_wall_time();  
+		tp->tv_sec = xtime.tv_sec;
+		tp->tv_nsec = xtime.tv_nsec;
+		tp->tv_nsec += arch_cycles_to_nsec(sub_jiffie());
+		write_unlock_irqrestore(&xtime_lock, flags);
+		if ( tp->tv_nsec >  NSEC_PER_SEC ){
+			tp->tv_nsec -= NSEC_PER_SEC ;
+			tp->tv_sec++;
+		}
+	}
+#else
 	do_gettimeofday((struct timeval*)tp);
 	tp->tv_nsec *= NSEC_PER_USEC;
+#endif
 	return 0;
 }
 
@@ -921,8 +1041,9 @@
 {
 	long sub_sec;
 	u64 jiffies_64_f;
+	IF_HIGH_RES(long sub_jiff_offset;)
 
-#if (BITS_PER_LONG > 32) 
+#if (BITS_PER_LONG > 32) && !defined(CONFIG_HIGH_RES_TIMERS)
 
 	jiffies_64_f = jiffies_64;
 
@@ -936,6 +1057,8 @@
 		read_lock_irqsave(&xtime_lock, flags);
 		jiffies_64_f = jiffies_64;
 
+		IF_HIGH_RES(sub_jiff_offset =	
+			    quick_update_jiffies_sub(jiffies));
 
 		read_unlock_irqrestore(&xtime_lock, flags);
 	}
@@ -944,14 +1067,34 @@
 	do {
 		jiffies_f = jiffies;
 		barrier();
+		IF_HIGH_RES(
+			sub_jiff_offset = 
+			quick_update_jiffies_sub(jiffies_f));
 		jiffies_64_f = jiffies_64;
 	} while (unlikely(jiffies_f != jiffies));
 
+#else /* 64 bit long and high-res but no SMP if I did the Venn right */
+	do {
+		jiffies_64_f = jiffies_64;
+		barrier();
+		sub_jiff_offset = quick_update_jiffies_sub(jiffies_64_f);
+	} while (unlikely(jiffies_64_f != jiffies_64));
 
 #endif
-	tp->tv_sec = div_long_long_rem(jiffies_64_f,HZ,&sub_sec);
+	/*
+	 * Remember that quick_update_jiffies_sub() can return more
+	 * than a jiffies worth of cycles...
+	 */
+	IF_HIGH_RES(
+		while ( unlikely(sub_jiff_offset > cycles_per_jiffies)){
+			sub_jiff_offset -= cycles_per_jiffies;
+			jiffies_64_f++;
+		}
+		)
+		tp->tv_sec = div_long_long_rem(jiffies_64_f,HZ,&sub_sec);
 
 	tp->tv_nsec = sub_sec * (NSEC_PER_SEC / HZ);
+	IF_HIGH_RES(tp->tv_nsec += arch_cycles_to_nsec(sub_jiff_offset));
 	return 0;
 }
 
@@ -1110,6 +1253,7 @@
 			 * del_timer_sync() will return 0, thus
 			 * active is zero... and so it goes.
 			 */
+			IF_HIGH_RES(new_timer.sub_expires = )
 
 				tstojiffie(&t,
 					   posix_clocks[which_clock].res,
@@ -1131,9 +1275,15 @@
 	}
 	if (active && rmtp ) {
 		unsigned long jiffies_f = jiffies;
+		IF_HIGH_RES(
+			long sub_jiff = 
+			quick_update_jiffies_sub(jiffies_f));
 
 		jiffies_to_timespec(new_timer.expires - jiffies_f, &t);
 
+		IF_HIGH_RES(t.tv_nsec += 
+			    arch_cycles_to_nsec(new_timer.sub_expires -
+						sub_jiff));
 		while (t.tv_nsec < 0){
 			t.tv_nsec += NSEC_PER_SEC;
 			t.tv_sec--;

Binary files linux-2.5.44-bk1-i386/scripts/fixdep and linux/scripts/fixdep differ

#6 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 8

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.44-bk3

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86)
platform
*posixhr The changes to the POSIX clocks & timers
patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-bk2-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -281,6 +281,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

#7 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 8

In reply to george anzinger

Thus endth the corrections. Correct patch attached.

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.44-bk3

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86)
platform
*posixhr The changes to the POSIX clocks & timers
patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.44-bk3-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -281,6 +281,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

#8 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 10

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.45

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86)
platform
*posixhr The changes to the POSIX clocks & timers
patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/Kconfig +95 -3
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-i386/arch/i386/Kconfig linux/arch/i386/Kconfig
@@ -315,6 +315,98 @@
 
 	  If you don't know what to do here, say N.
 
+config HIGH_RES_TIMERS
+	bool "Configure High-Resolution-Timers"
+	help
+	  POSIX timers are available by default.  This option enables
+	  high resolution POSIX timers.  With this option the resolution
+	  is at least 1 micro second.  High resolution is not free.  If
+	  enabled this option will add a small overhead each time a
+	  timer expires that is not on a 1/HZ tick boundry.  If no such
+	  timers are used the overhead is nil.
+
+	  This option enables two additional POSIX CLOCKS,
+	  CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR.  Note that this
+	  option does not change the resolution of CLOCK_REALTIME or
+	  CLOCK_MONOTONIC which remain at 1/HZ resolution.
+
+choice
+	prompt "Clock source?"
+	default HIGH_RES_TIMER_TSC
+	help 
+	  This option allows you to choose the wall clock timer for your
+	  system.  With high resolution timers on the x86 platforms it
+	  is best to keep the interrupt generating timer separate from
+	  the time keeping timer.  On x86 platforms there are three
+	  possible sources implemented for the wall clock.  These are:
+ 
+  	  <timer>				<resolution>
+ 	  ACPI power management (pm) timer	~280 nano seconds
+  	  TSC (Time Stamp Counter)		1/CPU clock
+ 	  PIT (Programmable Interrupt Timer)	~838 nano seconds
+
+	  The PIT is used to generate interrupts and at any given time
+	  will be programmed to interrupt when the next timer is to
+	  expire or on the next 1/HZ tick.  For this reason it is best
+	  to not use this timer as the wall clock timer.  This timer has
+	  a resolution of 838 nano seconds.  THIS OPTION SHOULD ONLY BE
+	  USED IF BOTH ACPI AND TSC ARE NOT AVAILABLE.
+
+	  The TSC runs at the cpu clock rate (i.e. its resolution is
+	  1/CPU clock) and it has a very low access time.  However, it
+	  is subject, in some (incorrect) processors, to throttling to
+	  cool the cpu, and to other slow downs during power management.
+	  If your cpu is correct and does not change the TSC frequency
+	  for throttling or power management this is the best clock
+	  timer.
+
+	  The ACPI pm timer is available on systems with Advanced
+	  Configuration and Power Interface support.  The pm timer is
+	  available on these systems even if you don't use or enable
+	  ACPI in the software or the BIOS (but see Default ACPI pm
+	  timer address).  The timer has a resolution of about 280
+	  nanoseconds, however, the access time is a bit higher that
+	  that of the TSC.  Since it is part of ACPI it is intended to
+	  keep track of time while the system is under power management,
+	  thus it is not subject to the problems of the TSC.
+
+	  If you enable the ACPI pm timer and it can not be found, it is
+	  possible that your BIOS is not producing the ACPI table or
+	  that your machine does not support ACPI.  In the former case,
+	  see "Default ACPI pm timer address".  If the timer is not
+	  found the boot will fail when trying to calibrate the delay
+	  timer.
+
+config HIGH_RES_TIMER_ACPI_PM
+	bool "ACPI-pm-timer"
+	
+config HIGH_RES_TIMER_TSC
+	bool "Time-stamp-counter/TSC"
+	depends on X86_TSC
+
+config HIGH_RES_TIMER_PIT
+	bool "Programable-interrupt-timer/PIT"
+	  
+endchoice	  
+
+config HIGH_RES_TIMER_ACPI_PM_ADD
+	int "Default ACPI pm timer address"
+	depends on HIGH_RES_TIMER_ACPI_PM
+	default 0
+	help
+	  This option is available for use on systems where the BIOS
+	  does not generate the ACPI tables if ACPI is not enabled.  For
+	  example some BIOSes will not generate the ACPI tables if APM
+	  is enabled.  The ACPI pm timer is still available but can not
+	  be found by the software.  This option allows you to supply
+	  the needed address.  When the high resolution timers code
+	  finds a valid ACPI pm timer address it reports it in the boot
+	  messages log (look for lines that begin with
+	  "High-res-timers:").  You can turn on the ACPI support in the
+	  BIOS, boot the system and find this value.  You can then enter
+	  it at configure time.  Both the report and the entry are in
+	  decimal.
+
 config PREEMPT
 	bool "Preemptible Kernel"
 	help
@@ -1613,7 +1705,7 @@
 	  somewhat, as all symbols have to be loaded into the kernel image.
 
 config KGDB
-	bool 'Include kgdb kernel debugger' 
+	bool "Include kgdb kernel debugger" 
 	depends on DEBUG_KERNEL
 	help  
 	  If you say Y here, the system will be compiled with the debug
@@ -1634,7 +1726,7 @@
 
 choice
 	depends on KGDB
-    	prompt 'Debug serial port BAUD' 
+    	prompt "Debug serial port BAUD" 
 	default KGDB_115200BAUD
 	help  
 	  Gdb and the kernel stub need to agree on the baud rate to be
@@ -1782,7 +1874,7 @@
 	  serial driver to be configured.
 
 config KGDB_SYSRQ
-	bool "Turn on SysRq "G" command to do a break?"
+	bool "Turn on SysRq 'G' command to do a break?"
 	depends on KGDB
 	default y
 	help
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -281,6 +281,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

Binary files linux-2.5.45-i386/scripts/fixdep and linux/scripts/fixdep differ Binary files linux-2.5.45-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ

#9 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 10

In reply to george anzinger

Previous 3/3 take 10 had extra config stuff. This patch should have no config changes.

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.45

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86)
platform
*posixhr The changes to the POSIX clocks & timers
patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -281,6 +281,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

Binary files linux-2.5.45-i386/scripts/fixdep and linux/scripts/fixdep differ Binary files linux-2.5.45-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ

#10 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 11

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.45-bk1

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86) platform
*posixhr The changes to the POSIX clocks & timers patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/kernel/entry.S +14 -8
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
@@ -41,7 +41,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/errno.h>
@@ -240,7 +239,7 @@
 	pushl %eax			# save orig_eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebx)
-	cmpl $(NR_syscalls), %eax
+	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 					# system call tracing in operation
 	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebx)
@@ -316,7 +315,7 @@
 	xorl %edx,%edx
 	call do_syscall_trace
 	movl ORIG_EAX(%esp), %eax
-	cmpl $(NR_syscalls), %eax
+	cmpl $(nr_syscalls), %eax
 	jnae syscall_call
 	jmp syscall_exit
 
@@ -764,11 +763,18 @@
 	.long sys_exit_group
 	.long sys_lookup_dcookie
 	.long sys_epoll_create
-	.long sys_epoll_ctl	/* 255 */
+	.long sys_epoll_ctl		/* 255 */
 	.long sys_epoll_wait
  	.long sys_remap_file_pages
+ 	.long sys_timer_create
+ 	.long sys_timer_settime
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun	/* 260 */
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep	/* 265 */
+ 
 
-
-	.rept NR_syscalls-(.-sys_call_table)/4
-		.long sys_ni_syscall
-	.endr
+nr_syscalls=(.-sys_call_table)/4
arch/i386/kernel/time.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
@@ -131,6 +131,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_unlock_irq(&xtime_lock);
+	clock_was_set();
 }
 
 /*
arch/i386/kernel/timers/timer_tsc.c +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/arch/i386/kernel/timers/timer_tsc.c linux/arch/i386/kernel/timers/timer_tsc.c
@@ -26,7 +26,7 @@
  * Equal to 2^32 * (1 / (clocks per usec) ).
  * Initialized in time_init.
  */
-static unsigned long fast_gettimeoffset_quotient;
+unsigned long fast_gettimeoffset_quotient;
 
 static unsigned long get_offset_tsc(void)
 {
fs/exec.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/fs/exec.c linux/fs/exec.c
@@ -756,6 +756,7 @@
 			
 	flush_signal_handlers(current);
 	flush_old_files(current->files);
+	exit_itimers(current);
 
 	return 0;
 
include/asm-generic/siginfo.h +8 -4
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/asm-generic/siginfo.h linux/include/asm-generic/siginfo.h
@@ -43,8 +43,9 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
+			int _overrun;		/* overrun count */
+			sigval_t _sigval;	/* same as below */
 		} _timer;
 
 		/* POSIX.1b signals */
@@ -86,8 +87,8 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
-#define si_timer1	_sifields._timer._timer1
-#define si_timer2	_sifields._timer._timer2
+#define si_tid		_sifields._timer._tid
+#define si_overrun	_sifields._timer._overrun
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
@@ -221,6 +222,7 @@
 #define SIGEV_SIGNAL	0	/* notify via signal */
 #define SIGEV_NONE	1	/* other notification: meaningless */
 #define SIGEV_THREAD	2	/* deliver via thread creation */
+#define SIGEV_THREAD_ID 4	/* deliver to thread */
 
 #define SIGEV_MAX_SIZE	64
 #ifndef SIGEV_PAD_SIZE
@@ -235,6 +237,7 @@
 	int sigev_notify;
 	union {
 		int _pad[SIGEV_PAD_SIZE];
+		 int _tid;
 
 		struct {
 			void (*_function)(sigval_t);
@@ -247,6 +250,7 @@
 
 #define sigev_notify_function	_sigev_un._sigev_thread._function
 #define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+#define sigev_notify_thread_id	 _sigev_un._tid
 
 #ifdef __KERNEL__
 
include/asm-i386/posix_types.h +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h
@@ -22,6 +22,8 @@
 typedef long		__kernel_time_t;
 typedef long		__kernel_suseconds_t;
 typedef long		__kernel_clock_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef unsigned short	__kernel_uid16_t;
include/asm-i386/signal.h +74 -0

83 lines not on this page · raw message

include/asm-i386/unistd.h +9 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
@@ -262,6 +262,15 @@
 #define __NR_sys_epoll_ctl	255
 #define __NR_sys_epoll_wait	256
 #define __NR_remap_file_pages	257
+#define __NR_timer_create	258
+#define __NR_timer_settime	(__NR_timer_create+1)
+#define __NR_timer_gettime	(__NR_timer_create+2)
+#define __NR_timer_getoverrun	(__NR_timer_create+3)
+#define __NR_timer_delete	(__NR_timer_create+4)
+#define __NR_clock_settime	(__NR_timer_create+5)
+#define __NR_clock_gettime	(__NR_timer_create+6)
+#define __NR_clock_getres	(__NR_timer_create+7)
+#define __NR_clock_nanosleep	(__NR_timer_create+8)
 
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
include/linux/id_reuse.h +119 -0

119 lines not on this page · raw message

include/linux/init_task.h +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/linux/init_task.h linux/include/linux/init_task.h
@@ -93,6 +93,7 @@
 	.sig		= &init_signals,				\
 	.pending	= { NULL, &tsk.pending.head, {{0}}},		\
 	.blocked	= {{0}},					\
+	 .posix_timers	 = LIST_HEAD_INIT(tsk.posix_timers),		   \
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
include/linux/posix-timers.h +18 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -0,0 +1,18 @@
+#ifndef _linux_POSIX_TIMERS_H
+#define _linux_POSIX_TIMERS_H
+
+struct k_clock {
+	 int  res;		    /* in nano seconds */
+	 int ( *clock_set)(struct timespec *tp);
+	 int ( *clock_get)(struct timespec *tp);
+	 int ( *nsleep)(   int flags, 
+			   struct timespec*new_setting,
+			   struct itimerspec *old_setting);
+	 int ( *timer_set)(struct k_itimer *timr, int flags,
+			   struct itimerspec *new_setting,
+			   struct itimerspec *old_setting);
+	 int  ( *timer_del)(struct k_itimer *timr);
+	 void ( *timer_get)(struct k_itimer *timr,
+			   struct itimerspec *cur_setting);
+};
+#endif
include/linux/sched.h +20 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/linux/sched.h linux/include/linux/sched.h
@@ -269,6 +269,25 @@
 typedef struct prio_array prio_array_t;
 struct backing_dev_info;
 
+/* POSIX.1b interval timer structure. */
+struct k_itimer {
+	struct list_head list;		 /* free/ allocate list */
+	spinlock_t it_lock;
+	clockid_t it_clock;		/* which timer type */
+	timer_t it_id;			/* timer id */
+	int it_overrun;			/* overrun on pending signal  */
+	int it_overrun_last;		 /* overrun on last delivered signal */
+	int it_overrun_deferred;	 /* overrun on pending timer interrupt */
+	int it_sigev_notify;		 /* notify word of sigevent struct */
+	int it_sigev_signo;		 /* signo word of sigevent struct */
+	sigval_t it_sigev_value;	 /* value word of sigevent struct */
+	unsigned long it_incr;		/* interval specified in jiffies */
+	struct task_struct *it_process;	/* process to send signal to */
+	struct timer_list it_timer;
+};
+
+
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -331,6 +350,7 @@
 	unsigned long it_real_value, it_prof_value, it_virt_value;
 	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 	struct timer_list real_timer;
+	struct list_head posix_timers; /* POSIX.1b Interval Timers */
 	unsigned long utime, stime, cutime, cstime;
 	unsigned long start_time;
 	long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
include/linux/signal.h +30 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/linux/signal.h linux/include/linux/signal.h
@@ -224,6 +224,36 @@
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs);
 #endif
+/*
+ * We would like the asm/signal.h code to define these so that the using
+ * function can call do_signal().  In loo of that, we define a genaric
+ * version that pretends that do_signal() was called and delivered a signal.
+ * To see how this is used, see nano_sleep() in timer.c and the i386 version
+ * in asm_i386/signal.h.
+ */
+#ifndef PT_REGS_ENTRY
+#define PT_REGS_ENTRY(type,name,p1_type,p1, p2_type,p2) \
+type name(p1_type p1,p2_type p2)\
+{
+#endif
+#ifndef _do_signal
+#define _do_signal() 1
+#endif
+#ifndef NANOSLEEP_ENTRY
+#define NANOSLEEP_ENTRY(a) asmlinkage long sys_nanosleep( struct timespec* rqtp, \
+							  struct timespec * rmtp) \
+{ a
+#endif
+#ifndef CLOCK_NANOSLEEP_ENTRY
+#define CLOCK_NANOSLEEP_ENTRY(a) asmlinkage long sys_clock_nanosleep( \
+			       clockid_t which_clock,	   \
+			       int flags,		   \
+			       const struct timespec *rqtp, \
+			       struct timespec *rmtp)	    \
+{ a
+ 
+#endif
+
 
 #endif /* __KERNEL__ */
 
include/linux/sys.h +1 -2
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/linux/sys.h linux/include/linux/sys.h
@@ -2,9 +2,8 @@
 #define _LINUX_SYS_H
 
 /*
- * system call entry points ... but not all are defined
+ * This file is no longer used or needed
  */
-#define NR_syscalls 260
 
 /*
  * These are system calls that will be removed at some time
include/linux/time.h +35 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/linux/time.h linux/include/linux/time.h
@@ -38,6 +38,19 @@
  */
 #define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
 
+/* Parameters used to convert the timespec values */
+#ifndef USEC_PER_SEC
+#define USEC_PER_SEC (1000000L)
+#endif
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC (1000000000L)
+#endif
+
+#ifndef NSEC_PER_USEC
+#define NSEC_PER_USEC (1000L)
+#endif
+
 static __inline__ unsigned long
 timespec_to_jiffies(struct timespec *value)
 {
@@ -124,6 +137,8 @@
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
 extern void do_settimeofday(struct timeval *tv);
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern void clock_was_set(void); // call when ever the clock is set
 #endif
 
 #define FD_SETSIZE		__FD_SETSIZE
@@ -149,5 +164,25 @@
 	struct	timeval it_interval;	/* timer interval */
 	struct	timeval it_value;	/* current value */
 };
+
+
+/*
+ * The IDs of the various system clocks (for POSIX.1b interval timers).
+ */
+#define CLOCK_REALTIME		  0
+#define CLOCK_MONOTONIC	  1
+#define CLOCK_PROCESS_CPUTIME_ID 2
+#define CLOCK_THREAD_CPUTIME_ID	 3
+#define CLOCK_REALTIME_HR	 4
+#define CLOCK_MONOTONIC_HR	  5
+
+#define MAX_CLOCKS 6
+
+/*
+ * The various flags for setting POSIX.1b interval timers.
+ */
+
+#define TIMER_ABSTIME 0x01
+
 
 #endif
include/linux/types.h +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/include/linux/types.h linux/include/linux/types.h
@@ -23,6 +23,8 @@
 typedef __kernel_daddr_t	daddr_t;
 typedef __kernel_key_t		key_t;
 typedef __kernel_suseconds_t	suseconds_t;
+typedef __kernel_timer_t	timer_t;
+typedef __kernel_clockid_t	clockid_t;
 
 #ifdef __KERNEL__
 typedef __kernel_uid32_t	uid_t;
kernel/Makefile +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/kernel/Makefile linux/kernel/Makefile
@@ -10,7 +10,7 @@
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \
-	    rcupdate.o
+	    rcupdate.o posix-timers.o id_reuse.o
 
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
kernel/exit.c +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/kernel/exit.c linux/kernel/exit.c
@@ -410,6 +410,7 @@
 	mmdrop(active_mm);
 }
 
+
 /*
  * Turn us into a lazy TLB process if we
  * aren't already..
@@ -647,6 +648,7 @@
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	exit_namespace(tsk);
+	exit_itimers(tsk);
 	exit_thread();
 
 	if (current->leader)
kernel/fork.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.45-bk1-kb/kernel/fork.c linux/kernel/fork.c
@@ -784,6 +784,7 @@
 		goto bad_fork_cleanup_files;
 	if (copy_sighand(clone_flags, p))
 		goto bad_fork_cleanup_fs;
+	INIT_LIST_HEAD(&p->posix_timers);
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
 	if (copy_namespace(clone_flags, p))
kernel/id_reuse.c +198 -0

198 lines not on this page · raw message

kernel/posix-timers.c +1156 -0

1,156 lines not on this page · raw message

kernel/signal.c +35 -12

77 lines not on this page · raw message

kernel/timer.c +39 -15

139 lines not on this page · raw message

#11 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 12

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.44 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.46

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86) platform
*posixhr The changes to the POSIX clocks & timers patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.46-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -283,6 +283,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

Binary files linux-2.5.46-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.46-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#12 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 13

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.46-bk1

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86) platform
*posixhr The changes to the POSIX clocks & timers patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.46-bk1-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -281,6 +281,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

Binary files linux-2.5.46-bk1-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.46-bk1-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#13 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 14

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.47

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86) platform
*posixhr The changes to the POSIX clocks & timers patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.47-i386g/include/linux/sched.h linux/include/linux/sched.h
@@ -291,6 +291,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

Binary files linux-2.5.47-i386g/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.47-i386g/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#14 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 15

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c.

Concerns and on going work:

The kernel interface to the signal delivery code and it's need for &regs causes the nanosleep and clock_nanosleep code to be very messy. The supplied interface works for the x86 platform and provides the hooks for other platforms to connect (see .../include/asm-i386/signal.h for details), but a much cleaner solution is desired.

This patch guards against overload by limiting the repeat interval of timers to a fixed value (currently 0.5 ms). A suggested change, and one I am working on, is to not put the timer back in the timer list until the user's signal handler has completed processing the current expiry. This requires a call back from the signal completion code, again a platform dependent thing, BUT it has the advantage of automatically adjusting the interval to match the hardware, the system overhead and the current load. In all cases, the standard says we need to account for the overruns, but by not getting the timer interrupt code involved in useless spinning, we just bump the overrun, saving a LOT of overhead.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing"® to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.48

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent)
changes
i386 The high-res changes for the i386 (x86) platform
*hrposix The changes to the POSIX clocks & timers patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.48-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -289,6 +289,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +155 -5

309 lines not on this page · raw message

Binary files linux-2.5.48-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.48-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#15 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 16

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.48-bk2

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +33 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.48-bk2-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,38 @@
 	 void ( *timer_get)(struct k_itimer *timr,
 			   struct itimerspec *cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct{ 
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)){
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+              
+#else
 struct now_struct{ 
 	unsigned long jiffies;
 };
@@ -26,4 +58,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif // CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.48-bk2-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -289,6 +289,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +109 -7

260 lines not on this page · raw message

Binary files linux-2.5.48-bk2-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.48-bk2-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#16 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 17

In reply to george anzinger

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.49

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +33 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.49-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,38 @@
 	 void ( *timer_get)(struct k_itimer *timr,
 			   struct itimerspec *cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct{ 
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)){
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+              
+#else
 struct now_struct{ 
 	unsigned long jiffies;
 };
@@ -26,4 +58,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif // CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.49-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -290,6 +290,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +109 -7

260 lines not on this page · raw message

Binary files linux-2.5.49-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.49-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#17 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 18

In reply to george anzinger

Still hungry? Have some turkey! ;)

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.50

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +33 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,38 @@
 	 void ( *timer_get)(struct k_itimer *timr,
 			   struct itimerspec *cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct{ 
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)){
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+              
+#else
 struct now_struct{ 
 	unsigned long jiffies;
 };
@@ -26,4 +58,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif // CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -290,6 +290,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +109 -7

260 lines not on this page · raw message

Binary files linux-2.5.50-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.50-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.50-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#18 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 19

In reply to george anzinger

And this finishs the high res timers code.

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.50-bk5

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +33 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,38 @@
 	 void ( *timer_get)(struct k_itimer *timr,
 			   struct itimerspec *cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct{ 
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)){
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+              
+#else
 struct now_struct{ 
 	unsigned long jiffies;
 };
@@ -26,4 +58,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif // CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -290,6 +290,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
kernel/posix-timers.c +109 -7

260 lines not on this page · raw message

Binary files linux-2.5.50-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.50-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.50-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#19 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 20

In reply to george anzinger

And this finishs the high res timers code.

I had to add arg3 to the restart_block to handle the two word restart time...

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.50-bk7

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/kernel/entry.S +14 -8
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
@@ -41,7 +41,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/errno.h>
@@ -239,7 +238,7 @@
 	pushl %eax			# save orig_eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebx)
-	cmpl $(NR_syscalls), %eax
+	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 					# system call tracing in operation
 	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebx)
@@ -315,7 +314,7 @@
 	xorl %edx,%edx
 	call do_syscall_trace
 	movl ORIG_EAX(%esp), %eax
-	cmpl $(NR_syscalls), %eax
+	cmpl $(nr_syscalls), %eax
 	jnae syscall_call
 	jmp syscall_exit
 
@@ -769,8 +768,15 @@
 	.long sys_epoll_wait
  	.long sys_remap_file_pages
  	.long sys_set_tid_address
-
-
-	.rept NR_syscalls-(.-sys_call_table)/4
-		.long sys_ni_syscall
-	.endr
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+ 
+ 
+nr_syscalls=(.-sys_call_table)/4
arch/i386/kernel/time.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
@@ -132,6 +132,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_unlock_irq(&xtime_lock);
+	clock_was_set();
 }
 
 /*
fs/exec.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/fs/exec.c linux/fs/exec.c
@@ -779,6 +779,7 @@
 			
 	flush_signal_handlers(current);
 	flush_old_files(current->files);
+	exit_itimers(current);
 
 	return 0;
 
include/asm-generic/siginfo.h +12 -4
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-generic/siginfo.h linux/include/asm-generic/siginfo.h
@@ -43,8 +43,11 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
+			int _overrun;		/* overrun count */
+			char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
+			sigval_t _sigval;	/* same as below */
+			int _sys_private;       /* not to be passed to user */
 		} _timer;
 
 		/* POSIX.1b signals */
@@ -86,8 +89,9 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
-#define si_timer1	_sifields._timer._timer1
-#define si_timer2	_sifields._timer._timer2
+#define si_tid		_sifields._timer._tid
+#define si_overrun	_sifields._timer._overrun
+#define si_sys_private  _sifields._timer._sys_private
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
@@ -221,6 +225,7 @@
 #define SIGEV_SIGNAL	0	/* notify via signal */
 #define SIGEV_NONE	1	/* other notification: meaningless */
 #define SIGEV_THREAD	2	/* deliver via thread creation */
+#define SIGEV_THREAD_ID 4	/* deliver to thread */
 
 #define SIGEV_MAX_SIZE	64
 #ifndef SIGEV_PAD_SIZE
@@ -235,6 +240,7 @@
 	int sigev_notify;
 	union {
 		int _pad[SIGEV_PAD_SIZE];
+		 int _tid;
 
 		struct {
 			void (*_function)(sigval_t);
@@ -247,10 +253,12 @@
 
 #define sigev_notify_function	_sigev_un._sigev_thread._function
 #define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+#define sigev_notify_thread_id	 _sigev_un._tid
 
 #ifdef __KERNEL__
 
 struct siginfo;
+void do_schedule_next_timer(struct siginfo *info);
 
 #ifndef HAVE_ARCH_COPY_SIGINFO
 
include/asm-i386/posix_types.h +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h
@@ -22,6 +22,8 @@
 typedef long		__kernel_time_t;
 typedef long		__kernel_suseconds_t;
 typedef long		__kernel_clock_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef unsigned short	__kernel_uid16_t;
include/asm-i386/signal.h +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-i386/signal.h linux/include/asm-i386/signal.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/linkage.h>
+#include <linux/time.h>
 
 /* Avoid too many header ordering problems.  */
 struct siginfo;
include/asm-i386/unistd.h +9 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
@@ -264,6 +264,15 @@
 #define __NR_sys_epoll_wait	256
 #define __NR_remap_file_pages	257
 #define __NR_set_tid_address	258
+#define __NR_timer_create	259
+#define __NR_timer_settime	(__NR_timer_create+1)
+#define __NR_timer_gettime	(__NR_timer_create+2)
+#define __NR_timer_getoverrun	(__NR_timer_create+3)
+#define __NR_timer_delete	(__NR_timer_create+4)
+#define __NR_clock_settime	(__NR_timer_create+5)
+#define __NR_clock_gettime	(__NR_timer_create+6)
+#define __NR_clock_getres	(__NR_timer_create+7)
+#define __NR_clock_nanosleep	(__NR_timer_create+8)
 
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
include/linux/id_reuse.h +119 -0

119 lines not on this page · raw message

include/linux/init_task.h +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/init_task.h linux/include/linux/init_task.h
@@ -93,6 +93,7 @@
 	.sig		= &init_signals,				\
 	.pending	= { NULL, &tsk.pending.head, {{0}}},		\
 	.blocked	= {{0}},					\
+	 .posix_timers	 = LIST_HEAD_INIT(tsk.posix_timers),		   \
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
include/linux/posix-timers.h +30 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -0,0 +1,30 @@
+#ifndef _linux_POSIX_TIMERS_H
+#define _linux_POSIX_TIMERS_H
+
+struct k_clock {
+	int res;		/* in nano seconds */
+	int (*clock_set) (struct timespec * tp);
+	int (*clock_get) (struct timespec * tp);
+	int (*nsleep) (int flags,
+		       struct timespec * new_setting,
+		       struct itimerspec * old_setting);
+	int (*timer_set) (struct k_itimer * timr, int flags,
+			  struct itimerspec * new_setting,
+			  struct itimerspec * old_setting);
+	int (*timer_del) (struct k_itimer * timr);
+	void (*timer_get) (struct k_itimer * timr,
+			   struct itimerspec * cur_setting);
+};
+struct now_struct {
+	unsigned long jiffies;
+};
+
+#define posix_get_now(now) (now)->jiffies = jiffies;
+#define posix_time_before(timer, now) \
+                      time_before((timer)->expires, (now)->jiffies)
+
+#define posix_bump_timer(timr) do { \
+                        (timr)->it_timer.expires += (timr)->it_incr; \
+                        (timr)->it_overrun++;               \
+                       }while (0)
+#endif
include/linux/sched.h +21 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/sched.h linux/include/linux/sched.h
@@ -276,6 +276,25 @@
 typedef struct prio_array prio_array_t;
 struct backing_dev_info;
 
+/* POSIX.1b interval timer structure. */
+struct k_itimer {
+	struct list_head list;		 /* free/ allocate list */
+	spinlock_t it_lock;
+	clockid_t it_clock;		/* which timer type */
+	timer_t it_id;			/* timer id */
+	int it_overrun;			/* overrun on pending signal  */
+	int it_overrun_last;		 /* overrun on last delivered signal */
+	int it_requeue_pending;          /* waiting to requeue this timer */
+	int it_sigev_notify;		 /* notify word of sigevent struct */
+	int it_sigev_signo;		 /* signo word of sigevent struct */
+	sigval_t it_sigev_value;	 /* value word of sigevent struct */
+	unsigned long it_incr;		/* interval specified in jiffies */
+	struct task_struct *it_process;	/* process to send signal to */
+	struct timer_list it_timer;
+};
+
+
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -339,6 +358,7 @@
 	unsigned long it_real_value, it_prof_value, it_virt_value;
 	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 	struct timer_list real_timer;
+	struct list_head posix_timers; /* POSIX.1b Interval Timers */
 	unsigned long utime, stime, cutime, cstime;
 	unsigned long start_time;
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
@@ -579,6 +599,7 @@
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
 extern void __exit_sighand(struct task_struct *);
+extern void exit_itimers(struct task_struct *);
 
 extern void reparent_to_init(void);
 extern void daemonize(void);
include/linux/signal.h +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/signal.h linux/include/linux/signal.h
@@ -224,7 +224,7 @@
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs);
 #endif
-
+#define FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
include/linux/sys.h +1 -2
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/sys.h linux/include/linux/sys.h
@@ -2,9 +2,8 @@
 #define _LINUX_SYS_H
 
 /*
- * system call entry points ... but not all are defined
+ * This file is no longer used or needed
  */
-#define NR_syscalls 260
 
 /*
  * These are system calls that will be removed at some time
include/linux/time.h +35 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/time.h linux/include/linux/time.h
@@ -40,6 +40,19 @@
  */
 #define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
 
+/* Parameters used to convert the timespec values */
+#ifndef USEC_PER_SEC
+#define USEC_PER_SEC (1000000L)
+#endif
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC (1000000000L)
+#endif
+
+#ifndef NSEC_PER_USEC
+#define NSEC_PER_USEC (1000L)
+#endif
+
 static __inline__ unsigned long
 timespec_to_jiffies(struct timespec *value)
 {
@@ -138,6 +151,8 @@
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
 extern void do_settimeofday(struct timeval *tv);
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern void clock_was_set(void); // call when ever the clock is set
 extern long do_nanosleep(struct timespec *t);
 extern long do_utimes(char * filename, struct timeval * times);
 #endif
@@ -165,5 +180,25 @@
 	struct	timeval it_interval;	/* timer interval */
 	struct	timeval it_value;	/* current value */
 };
+
+
+/*
+ * The IDs of the various system clocks (for POSIX.1b interval timers).
+ */
+#define CLOCK_REALTIME		  0
+#define CLOCK_MONOTONIC	  1
+#define CLOCK_PROCESS_CPUTIME_ID 2
+#define CLOCK_THREAD_CPUTIME_ID	 3
+#define CLOCK_REALTIME_HR	 4
+#define CLOCK_MONOTONIC_HR	  5
+
+#define MAX_CLOCKS 6
+
+/*
+ * The various flags for setting POSIX.1b interval timers.
+ */
+
+#define TIMER_ABSTIME 0x01
+
 
 #endif
include/linux/types.h +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/types.h linux/include/linux/types.h
@@ -23,6 +23,8 @@
 typedef __kernel_daddr_t	daddr_t;
 typedef __kernel_key_t		key_t;
 typedef __kernel_suseconds_t	suseconds_t;
+typedef __kernel_timer_t	timer_t;
+typedef __kernel_clockid_t	clockid_t;
 
 #ifdef __KERNEL__
 typedef __kernel_uid32_t	uid_t;
kernel/Makefile +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/Makefile linux/kernel/Makefile
@@ -10,7 +10,7 @@
 	    exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \
-	    rcupdate.o intermodule.o extable.o
+	    rcupdate.o intermodule.o extable.o posix-timers.o id_reuse.o
 
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
kernel/exit.c +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/exit.c linux/kernel/exit.c
@@ -411,6 +411,7 @@
 	mmdrop(active_mm);
 }
 
+
 /*
  * Turn us into a lazy TLB process if we
  * aren't already..
@@ -659,6 +660,7 @@
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	exit_namespace(tsk);
+	exit_itimers(tsk);
 	exit_thread();
 
 	if (current->leader)
kernel/fork.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/fork.c linux/kernel/fork.c
@@ -810,6 +810,7 @@
 		goto bad_fork_cleanup_files;
 	if (copy_sighand(clone_flags, p))
 		goto bad_fork_cleanup_fs;
+	INIT_LIST_HEAD(&p->posix_timers);
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
 	if (copy_namespace(clone_flags, p))
kernel/id_reuse.c +194 -0

194 lines not on this page · raw message

kernel/posix-timers.c +1311 -0

1,311 lines not on this page · raw message

kernel/signal.c +31 -9
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/signal.c linux/kernel/signal.c
@@ -457,8 +457,6 @@
 		if (!collect_signal(sig, pending, info))
 			sig = 0;
 				
-		/* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER,
-		   we need to xchg out the timer overrun values.  */
 	}
 	recalc_sigpending();
 
@@ -473,6 +471,7 @@
  */
 int dequeue_signal(sigset_t *mask, siginfo_t *info)
 {
+	int ret;
 	/*
 	 * Here we handle shared pending signals. To implement the full
 	 * semantics we need to unqueue and resend them. It will likely
@@ -483,7 +482,13 @@
 		if (signr)
 			__send_sig_info(signr, info, current);
 	}
-	return __dequeue_signal(&current->pending, mask, info);
+	ret = __dequeue_signal(&current->pending, mask, info);
+	if ( ret &&
+	     ((info->si_code & __SI_MASK) == __SI_TIMER) &&
+	     info->si_sys_private){
+		do_schedule_next_timer(info);
+	}
+	return ret;
 }
 
 static int rm_from_queue(int sig, struct sigpending *s)
@@ -622,6 +627,7 @@
 static int send_signal(int sig, struct siginfo *info, struct sigpending *signals)
 {
 	struct sigqueue * q = NULL;
+	int ret = 0;
 
 	/*
 	 * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -665,17 +671,26 @@
 				copy_siginfo(&q->info, info);
 				break;
 		}
-	} else if (sig >= SIGRTMIN && info && (unsigned long)info != 1
+	} else {
+		if (sig >= SIGRTMIN && info && (unsigned long)info != 1
 		   && info->si_code != SI_USER)
 		/*
 		 * Queue overflow, abort.  We may abort if the signal was rt
 		 * and sent by user using something other than kill().
 		 */
-		return -EAGAIN;
+			return -EAGAIN;
+
+		if (((unsigned long)info > 1) && (info->si_code == SI_TIMER))
+			/*
+			 * Set up a return to indicate that we dropped 
+			 * the signal.
+			 */
+			ret = info->si_sys_private;
+	}
 
 out_set:
 	sigaddset(&signals->signal, sig);
-	return 0;
+	return ret;
 }
 
 /*
@@ -715,7 +730,7 @@
 {
 	int retval = send_signal(sig, info, &t->pending);
 
-	if (!retval && !sigismember(&t->blocked, sig))
+	if ((retval >= 0) && !sigismember(&t->blocked, sig))
 		signal_wake_up(t);
 
 	return retval;
@@ -751,6 +766,12 @@
 
 	handle_stop_signal(sig, t);
 
+	if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))
+		/*
+		 * Set up a return to indicate that we dropped the signal.
+		 */
+		ret = info->si_sys_private;
+
 	/* Optimize away the signal, if it's a signal that can be
 	   handled immediately (ie non-blocked and untraced) and
 	   that is ignored (either explicitly or by default).  */
@@ -1477,8 +1498,9 @@
 		err |= __put_user(from->si_uid, &to->si_uid);
 		break;
 	case __SI_TIMER:
-		err |= __put_user(from->si_timer1, &to->si_timer1);
-		err |= __put_user(from->si_timer2, &to->si_timer2);
+		 err |= __put_user(from->si_tid, &to->si_tid);
+		 err |= __put_user(from->si_overrun, &to->si_overrun);
+		 err |= __put_user(from->si_ptr, &to->si_ptr);
 		break;
 	case __SI_POLL:
 		err |= __put_user(from->si_band, &to->si_band);
kernel/timer.c +17 -14
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/timer.c linux/kernel/timer.c
@@ -49,12 +49,11 @@
 	struct list_head vec[TVR_SIZE];
 } tvec_root_t;
 
-typedef struct timer_list timer_t;
 
 struct tvec_t_base_s {
 	spinlock_t lock;
 	unsigned long timer_jiffies;
-	timer_t *running_timer;
+	struct timer_list *running_timer;
 	tvec_root_t tv1;
 	tvec_t tv2;
 	tvec_t tv3;
@@ -67,7 +66,7 @@
 /* Fake initialization */
 static DEFINE_PER_CPU(tvec_base_t, tvec_bases) = { SPIN_LOCK_UNLOCKED };
 
-static void check_timer_failed(timer_t *timer)
+static void check_timer_failed(struct timer_list *timer)
 {
 	static int whine_count;
 	if (whine_count < 16) {
@@ -85,13 +84,13 @@
 	timer->magic = TIMER_MAGIC;
 }
 
-static inline void check_timer(timer_t *timer)
+static inline void check_timer(struct timer_list *timer)
 {
 	if (timer->magic != TIMER_MAGIC)
 		check_timer_failed(timer);
 }
 
-static inline void internal_add_timer(tvec_base_t *base, timer_t *timer)
+static inline void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
 {
 	unsigned long expires = timer->expires;
 	unsigned long idx = expires - base->timer_jiffies;
@@ -143,7 +142,7 @@
  * Timers with an ->expired field in the past will be executed in the next
  * timer tick. It's illegal to add an already pending timer.
  */
-void add_timer(timer_t *timer)
+void add_timer(struct timer_list *timer)
 {
 	int cpu = get_cpu();
 	tvec_base_t *base = &per_cpu(tvec_bases, cpu);
@@ -201,7 +200,7 @@
  * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
  * active timer returns 1.)
  */
-int mod_timer(timer_t *timer, unsigned long expires)
+int mod_timer(struct timer_list *timer, unsigned long expires)
 {
 	tvec_base_t *old_base, *new_base;
 	unsigned long flags;
@@ -278,7 +277,7 @@
  * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
  * active timer returns 1.)
  */
-int del_timer(timer_t *timer)
+int del_timer(struct timer_list *timer)
 {
 	unsigned long flags;
 	tvec_base_t *base;
@@ -317,7 +316,7 @@
  *
  * The function returns whether it has deactivated a pending timer or not.
  */
-int del_timer_sync(timer_t *timer)
+int del_timer_sync(struct timer_list *timer)
 {
 	tvec_base_t *base;
 	int i, ret = 0;
@@ -360,9 +359,9 @@
 	 * detach them individually, just clear the list afterwards.
 	 */
 	while (curr != head) {
-		timer_t *tmp;
+		struct timer_list *tmp;
 
-		tmp = list_entry(curr, timer_t, entry);
+		tmp = list_entry(curr, struct timer_list, entry);
 		if (tmp->base != base)
 			BUG();
 		next = curr->next;
@@ -401,9 +400,9 @@
 		if (curr != head) {
 			void (*fn)(unsigned long);
 			unsigned long data;
-			timer_t *timer;
+			struct timer_list *timer;
 
-			timer = list_entry(curr, timer_t, entry);
+			timer = list_entry(curr, struct timer_list, entry);
  			fn = timer->function;
  			data = timer->data;
 
@@ -505,6 +504,7 @@
 	if (xtime.tv_sec % 86400 == 0) {
 	    xtime.tv_sec--;
 	    time_state = TIME_OOP;
+	    clock_was_set();
 	    printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n");
 	}
 	break;
@@ -513,6 +513,7 @@
 	if ((xtime.tv_sec + 1) % 86400 == 0) {
 	    xtime.tv_sec++;
 	    time_state = TIME_WAIT;
+	    clock_was_set();
 	    printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n");
 	}
 	break;
@@ -965,7 +966,7 @@
  */
 signed long schedule_timeout(signed long timeout)
 {
-	timer_t timer;
+	struct timer_list timer;
 	unsigned long expire;
 
 	switch (timeout)
@@ -1020,6 +1021,7 @@
 {
 	return current->pid;
 }
+#ifndef FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP
 
 static long nanosleep_restart(struct restart_block *restart)
 {
@@ -1078,6 +1080,7 @@
 	}
 	return ret;
 }
+#endif // ! FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP
 
 /*
  * sys_sysinfo - fill in sysinfo struct

Binary files linux-2.5.50-bk7-kb/scripts/kallsyms and linux/scripts/kallsyms differ Binary files linux-2.5.50-bk7-kb/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.50-bk7-kb/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.50-bk7-kb/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#20 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 3 lines · george anzinger
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +0 -0

Maybe I'm thick, but this whole id_resue layer seems rather obscure.

As it is being positioned as a general-purpose utility it needs API documentation as well as a general description.

Quoted 1 line

+extern inline void update_bitmap(struct idr_layer *p, int bit)

Please use static inline, not extern inline. If only for consistency, and to lessen the amount of stuff which needs to be fixed up by those of us who like to use `-fno-inline' occasionally.

Quoted 1 line

+extern inline void update_bitmap_set(struct idr_layer *p, int bit)

A lot of the functions in this header are too large to be inlined.

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 4 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +4 -0
+extern inline void idr_lock(struct idr *idp)
+{
+       spin_lock(&idp->id_slock);
+}

Please, just open-code the locking. This simply makes it harder to follow the main code.

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 3 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +3 -0
+
+static struct idr_layer *id_free;
+static int id_free_cnt;

hm. We seem to have a global private freelist here. Is the more SMP-friendly slab not suitable?

Quoted 8 lines

...

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +7 -0
+static int sub_alloc(struct idr_layer *p, int shift, void *ptr)
+{
+       int bitmap = p->bitmap;
+       int v, n;
+
+       n = ffz(bitmap);
+       if (shift == 0) {

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 10 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +10 -0
+               p->ary[n] = (struct idr_layer *)ptr;
+               __set_bit(n, &p->bitmap);
+               return(n);
+       }
+       if (!p->ary[n])
+               p->ary[n] = alloc_layer();
+       v = sub_alloc(p->ary[n], shift-IDR_BITS, ptr);
+       update_bitmap_set(p, n);
+       return(v + (n << shift));
+}

Recursion!

Quoted 1 line

+void idr_init(struct idr *idp)

Please tell us a bit about this id layer: what problems it solves, how it solves them, why it is needed and why existing kernel facilities are unsuitable.

Thanks.

#21 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

Quoted 10 lines · Andrew Morton

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 3 lines · george anzinger
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +0 -0

Maybe I'm thick, but this whole id_resue layer seems rather obscure.

As it is being positioned as a general-purpose utility it needs API documentation as well as a general description.

Hm... This whole thing came up to solve and issue related to having a finite number of timers. The ID layer is just a way of saving a pointer to a given "thing" (a timer structure in this case) in a way that it can be recovered quickly. It is really just a tree structure with 32 branches (or is it sizeof long branches) at each node. There is a bit map to indicate if any free slots are available and if so under which branch. This makes allocation of a new ID quite fast. The "reuse" thing is there to separate it from the original code which "attempted" to not reuse and ID for some time.

Quoted 6 lines
Quoted 2 lines

+extern inline void update_bitmap(struct idr_layer *p, int bit)

Please use static inline, not extern inline. If only for consistency, and to lessen the amount of stuff which needs to be fixed up by those of us who like to use `-fno-inline' occasionally.

OK, no problem.

Quoted 4 lines
Quoted 2 lines

+extern inline void update_bitmap_set(struct idr_layer *p, int bit)

A lot of the functions in this header are too large to be inlined.

Hm... What is "too large", i.e. how much code. Also, is it used more than once? I will look at this.

Quoted 8 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 5 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +4 -0
+extern inline void idr_lock(struct idr *idp)
+{
+       spin_lock(&idp->id_slock);
+}

Please, just open-code the locking. This simply makes it harder to follow the main code.

But makes it easy to change the lock method, to, for example, use irq or irqsave or "shudder" RCU.

Quoted 7 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 4 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +3 -0
+
+static struct idr_layer *id_free;
+static int id_free_cnt;

hm. We seem to have a global private freelist here. Is the more SMP-friendly slab not suitable?

There is a short local free list to avoid calling slab with a spinlock held. Only enough entries are kept to allocate a new node at each branch from the root to leaf, and only for this reason.

Quoted 13 lines
Quoted 13 lines

...

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +11 -0
+static int sub_alloc(struct idr_layer *p, int shift, void *ptr)
+{
+       int bitmap = p->bitmap;
+       int v, n;
+
+       n = ffz(bitmap);
+       if (shift == 0) {
+               p->ary[n] = (struct idr_layer *)ptr;
+               __set_bit(n, &p->bitmap);
+               return(n);
+       }
Quoted 8 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 6 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +6 -0
+       if (!p->ary[n])
+               p->ary[n] = alloc_layer();
+       v = sub_alloc(p->ary[n], shift-IDR_BITS, ptr);
+       update_bitmap_set(p, n);
+       return(v + (n << shift));
+}

Recursion!

Yes, it is a tree after all.

Quoted 7 lines
Quoted 2 lines

+void idr_init(struct idr *idp)

Please tell us a bit about this id layer: what problems it solves, how it solves them, why it is needed and why existing kernel facilities are unsuitable.

The prior version of the code had a CONFIG option to set the maximum number of timers. This caused enough memory to be "compiled" in to keep pointers to this many timers. The ID layer was invented (by Jim Houston, by the way) to eliminate this CONFIG thing. If I were to ask for a capability from slab that would eliminate the need for this it would be the ability to, given an address and a slab pool, to validate that the address was "live" and from that pool. I.e. that the address is a pointer to currently allocated block from that memory pool. With this, I could just pass the address to the user as the timer_id. As it is, I need a way to give the user a handle that he can pass back that will allow me to quickly find his timer and, along the way, validate that he was not spoofing, or just plain confused.

So what the ID layer does is pass back an available <id> (which I can pass to the user) while storing a pointer to the timer which is <id>ed. Later, given the <id>, it passes back the pointer, or NULL if the id is not in use.

As I said above, the pointers are kept in "nodes" of 32 along with a few bits of overhead, and these are arranged in a dynamic tree which grows as the number of allocated timers increases. The depth of the tree is 1 for up to 32 , 2 for up to 1024, and so on. The depth can never get beyond 5, by which time the system will, long since, be out of memory. At this time the leaf nodes are release when empty but the branch nodes are not. (This is an enhancement saved for later, if it seems useful.)

I am open to a better method that solves the problem...

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
#22 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

Quoted 48 lines · george anzinger
Quoted 10 lines · Andrew Morton

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 3 lines · george anzinger
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +0 -0

Maybe I'm thick, but this whole id_resue layer seems rather obscure.

As it is being positioned as a general-purpose utility it needs API documentation as well as a general description.

Hm... This whole thing came up to solve and issue related to having a finite number of timers. The ID layer is just a way of saving a pointer to a given "thing" (a timer structure in this case) in a way that it can be recovered quickly. It is really just a tree structure with 32 branches (or is it sizeof long branches) at each node. There is a bit map to indicate if any free slots are available and if so under which branch. This makes allocation of a new ID quite fast. The "reuse" thing is there to separate it from the original code which "attempted" to not reuse and ID for some time.

Quoted 6 lines
Quoted 2 lines

+extern inline void update_bitmap(struct idr_layer *p, int bit)

Please use static inline, not extern inline. If only for consistency, and to lessen the amount of stuff which needs to be fixed up by those of us who like to use `-fno-inline' occasionally.

OK, no problem.

Quoted 4 lines
Quoted 2 lines

+extern inline void update_bitmap_set(struct idr_layer *p, int bit)

A lot of the functions in this header are too large to be inlined.

Hm... What is "too large", i.e. how much code. Also, is it used more than once? I will look at this.

Quoted 8 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 5 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +4 -0
+extern inline void idr_lock(struct idr *idp)
+{
+       spin_lock(&idp->id_slock);
+}

Please, just open-code the locking. This simply makes it harder to follow the main code.

Quoted 2 lines

But makes it easy to change the lock method, to, for example, use irq or irqsave or "shudder" RCU.

Oh, I forgot, I needed to export the locking but did not want to export the structure details. See lock_timer() in posix_timers.c (in the same patch which should by the POSIX timers patch, sigh).

Quoted 8 lines
Quoted 7 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 4 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +3 -0
+
+static struct idr_layer *id_free;
+static int id_free_cnt;

hm. We seem to have a global private freelist here. Is the more SMP-friendly slab not suitable?

Quoted 4 lines

There is a short local free list to avoid calling slab with a spinlock held. Only enough entries are kept to allocate a new node at each branch from the root to leaf, and only for this reason.

Oh, and yes, you are right, this should be a private free list. I will move it inside the structure...

Thanks, good find.

-g

Quoted 73 lines
Quoted 13 lines
Quoted 13 lines

...

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +11 -0
+static int sub_alloc(struct idr_layer *p, int shift, void *ptr)
+{
+       int bitmap = p->bitmap;
+       int v, n;
+
+       n = ffz(bitmap);
+       if (shift == 0) {
+               p->ary[n] = (struct idr_layer *)ptr;
+               __set_bit(n, &p->bitmap);
+               return(n);
+       }
Quoted 8 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 6 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +6 -0
+       if (!p->ary[n])
+               p->ary[n] = alloc_layer();
+       v = sub_alloc(p->ary[n], shift-IDR_BITS, ptr);
+       update_bitmap_set(p, n);
+       return(v + (n << shift));
+}

Recursion!

Yes, it is a tree after all.

Quoted 7 lines
Quoted 2 lines

+void idr_init(struct idr *idp)

Please tell us a bit about this id layer: what problems it solves, how it solves them, why it is needed and why existing kernel facilities are unsuitable.

The prior version of the code had a CONFIG option to set the maximum number of timers. This caused enough memory to be "compiled" in to keep pointers to this many timers. The ID layer was invented (by Jim Houston, by the way) to eliminate this CONFIG thing. If I were to ask for a capability from slab that would eliminate the need for this it would be the ability to, given an address and a slab pool, to validate that the address was "live" and from that pool. I.e. that the address is a pointer to currently allocated block from that memory pool. With this, I could just pass the address to the user as the timer_id. As it is, I need a way to give the user a handle that he can pass back that will allow me to quickly find his timer and, along the way, validate that he was not spoofing, or just plain confused.

So what the ID layer does is pass back an available <id> (which I can pass to the user) while storing a pointer to the timer which is <id>ed. Later, given the <id>, it passes back the pointer, or NULL if the id is not in use.

As I said above, the pointers are kept in "nodes" of 32 along with a few bits of overhead, and these are arranged in a dynamic tree which grows as the number of allocated timers increases. The depth of the tree is 1 for up to 32 , 2 for up to 1024, and so on. The depth can never get beyond 5, by which time the system will, long since, be out of memory. At this time the leaf nodes are release when empty but the branch nodes are not. (This is an enhancement saved for later, if it seems useful.)

I am open to a better method that solves the problem...

--
George Anzinger [email protected]
High-res-timers:
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
#23 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

In reply to george anzinger
Quoted 13 lines · george anzinger
Quoted 10 lines · Andrew Morton

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 3 lines · george anzinger
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +0 -0

Maybe I'm thick, but this whole id_resue layer seems rather obscure.

As it is being positioned as a general-purpose utility it needs API documentation as well as a general description.

Quoted 11 lines

Hm... This whole thing came up to solve and issue related to having a finite number of timers. The ID layer is just a way of saving a pointer to a given "thing" (a timer structure in this case) in a way that it can be recovered quickly. It is really just a tree structure with 32 branches (or is it sizeof long branches) at each node. There is a bit map to indicate if any free slots are available and if so under which branch. This makes allocation of a new ID quite fast. The "reuse" thing is there to separate it from the original code which "attempted" to not reuse and ID for some time.

Sounds a bit like the pid allocator?

Is the "don't reuse an ID for some time" requirement still there?

I think you can use radix trees for this. Just put the pointer to your "thing" direct into the tree. The space overhead will be about the same.

radix-trees do not currently have a "find next empty slot from this offset" function but that is quite straightforward. Not quite as fast, unless an occupancy bitmap is added to the radix-tree node. That's something whcih I have done before - in fact it was an array of occupancy maps so I could do an efficient in-order gang lookup of "all dirty pages from this offset" and "all locked pages from this offset". It was before its time, and mouldered.

Quoted 4 lines

...

Quoted 1 line

A lot of the functions in this header are too large to be inlined.

Hm... What is "too large", i.e. how much code.

A few lines, I suspect.

Quoted 1 line

Also, is it used more than once?

Don't trust the compiler too much ;) Uninlining mpage_writepage() saved a couple of hundred bytes of code, even though it has only one call site.

Quoted 6 lines

...

Quoted 2 lines

Please, just open-code the locking. This simply makes it harder to follow the main code.

But makes it easy to change the lock method, to, for example, use irq or irqsave or "shudder" RCU.

A diligent programmer would visit all sites as part of that conversion anyway.

Quoted 8 lines
Quoted 7 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 4 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +3 -0
+
+static struct idr_layer *id_free;
+static int id_free_cnt;

hm. We seem to have a global private freelist here. Is the more SMP-friendly slab not suitable?

Quoted 4 lines

There is a short local free list to avoid calling slab with a spinlock held. Only enough entries are kept to allocate a new node at each branch from the root to leaf, and only for this reason.

Fair enough. There are similar requirements elsewhere and the plan there is to create a page reservation API, so you can ensure that the page allocator will be able to provide at least N pages. Then take the lock and go for it.

I have code for that which is about to bite the bit bucket. But the
new version should be in place soon. Other users will be radix tree
nodes, pte_chains and mm_chains (shared pagetable patch).

Quoted 5 lines

...

Quoted 2 lines

Recursion!

Yes, it is a tree after all.

lib/radix_tree.c does everything iteratively.

Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

+void idr_init(struct idr *idp)

Please tell us a bit about this id layer: what problems it solves, how it solves them, why it is needed and why existing kernel facilities are unsuitable.

Quoted 11 lines

The prior version of the code had a CONFIG option to set the maximum number of timers. This caused enough memory to be "compiled" in to keep pointers to this many timers. The ID layer was invented (by Jim Houston, by the way) to eliminate this CONFIG thing. If I were to ask for a capability from slab that would eliminate the need for this it would be the ability to, given an address and a slab pool, to validate that the address was "live" and from that pool. I.e. that the address is a pointer to currently allocated block from that memory pool. With this, I could just pass the address to the user as the timer_id.

That might cause problems with 64-bit kernel/32-bit userspace. Passing out kernel addresses in this way may have other problems..

Quoted 9 lines

As it is, I need a way to give
the user a handle that he can pass back that will allow me to quickly find his timer and, along the way, validate that he was not spoofing, or just plain confused.

So what the ID layer does is pass back an available <id> (which I can pass to the user) while storing a pointer to the timer which is <id>ed. Later, given the <id>, it passes back the pointer, or NULL if the id is not in use.

OK.

Quoted 11 lines

As I said above, the pointers are kept in "nodes" of 32 along with a few bits of overhead, and these are arranged in a dynamic tree which grows as the number of allocated timers increases. The depth of the tree is 1 for up to 32 , 2 for up to 1024, and so on. The depth can never get beyond 5, by which time the system will, long since, be out of memory. At this time the leaf nodes are release when empty but the branch nodes are not. (This is an enhancement saved for later, if it seems useful.)

I am open to a better method that solves the problem...

It seems reasonable. It would be nice to be able to use radix trees, but that's a lot of work if the patch isn't going anywhere.

If radix trees are unsuitable then yes, dressing this up as a new core kernel capability (documentation! separate patch!) would be appropriate.

But I suspect the radix-tree _will_ suit, and it would be nice to grow the usefulness of radix-trees rather than creating similar-but-different trees. We can do whizzy things with radix-trees; more than at present.

Of course, that was only a teeny part of your patch. I just happened to spy it as it flew past. Given that you're at rev 20, perhaps a splitup and more accessible presentation would help.

#24 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

Quoted 27 lines · Andrew Morton
Quoted 13 lines · george anzinger
Quoted 10 lines · Andrew Morton

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 3 lines · george anzinger
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +0 -0

Maybe I'm thick, but this whole id_resue layer seems rather obscure.

As it is being positioned as a general-purpose utility it needs API documentation as well as a general description.

Quoted 11 lines

Hm... This whole thing came up to solve and issue related to having a finite number of timers. The ID layer is just a way of saving a pointer to a given "thing" (a timer structure in this case) in a way that it can be recovered quickly. It is really just a tree structure with 32 branches (or is it sizeof long branches) at each node. There is a bit map to indicate if any free slots are available and if so under which branch. This makes allocation of a new ID quite fast. The "reuse" thing is there to separate it from the original code which "attempted" to not reuse and ID for some time.

Quoted 3 lines

Sounds a bit like the pid allocator?

Is the "don't reuse an ID for some time" requirement still there?

I don't see the need for the "don't reuse an ID for some time" thing and it looked like what Jim had messed up the book keeping AND it also looked like it failed to actually work. All of this convinced me that the added complexity was just not worth it.

Quoted 5 lines

I think you can use radix trees for this. Just put the pointer to your "thing" direct into the tree. The space overhead will be about the same.

Quoted 7 lines

radix-trees do not currently have a "find next empty slot from this offset" function but that is quite straightforward. Not quite as fast, unless an occupancy bitmap is added to the radix-tree node. That's something whcih I have done before - in fact it was an array of occupancy maps so I could do an efficient in-order gang lookup of "all dirty pages from this offset" and "all locked pages from this offset". It was before its time, and mouldered.

Gosh, I think this is what I have. Is it already in the kernel tree somewhere? Oh, I found it. I will look at this, tomorrow...

-g

Quoted 119 lines
Quoted 5 lines

...

Quoted 1 line

A lot of the functions in this header are too large to be inlined.

Hm... What is "too large", i.e. how much code.

A few lines, I suspect.

Quoted 1 line

Also, is it used more than once?

Don't trust the compiler too much ;) Uninlining mpage_writepage() saved a couple of hundred bytes of code, even though it has only one call site.

Quoted 6 lines

...

Quoted 2 lines

Please, just open-code the locking. This simply makes it harder to follow the main code.

But makes it easy to change the lock method, to, for example, use irq or irqsave or "shudder" RCU.

A diligent programmer would visit all sites as part of that conversion anyway.

Quoted 8 lines
Quoted 7 lines

include/linux/id_reuse.h Sat Dec 7 21:37:58 2002

Quoted 4 lines
include/linux/id_reuse.h Sat Dec 7 21:37:58 2002 renamed from include/linux/id_reuse.h Wed Dec 31 16:00:00 1969 +3 -0
+
+static struct idr_layer *id_free;
+static int id_free_cnt;

hm. We seem to have a global private freelist here. Is the more SMP-friendly slab not suitable?

Quoted 4 lines

There is a short local free list to avoid calling slab with a spinlock held. Only enough entries are kept to allocate a new node at each branch from the root to leaf, and only for this reason.

Fair enough. There are similar requirements elsewhere and the plan there is to create a page reservation API, so you can ensure that the page allocator will be able to provide at least N pages. Then take the lock and go for it.

I have code for that which is about to bite the bit bucket. But the
new version should be in place soon. Other users will be radix tree
nodes, pte_chains and mm_chains (shared pagetable patch).

Quoted 5 lines

...

Quoted 2 lines

Recursion!

Yes, it is a tree after all.

lib/radix_tree.c does everything iteratively.

Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

+void idr_init(struct idr *idp)

Please tell us a bit about this id layer: what problems it solves, how it solves them, why it is needed and why existing kernel facilities are unsuitable.

Quoted 11 lines

The prior version of the code had a CONFIG option to set the maximum number of timers. This caused enough memory to be "compiled" in to keep pointers to this many timers. The ID layer was invented (by Jim Houston, by the way) to eliminate this CONFIG thing. If I were to ask for a capability from slab that would eliminate the need for this it would be the ability to, given an address and a slab pool, to validate that the address was "live" and from that pool. I.e. that the address is a pointer to currently allocated block from that memory pool. With this, I could just pass the address to the user as the timer_id.

That might cause problems with 64-bit kernel/32-bit userspace. Passing out kernel addresses in this way may have other problems..

Quoted 9 lines

As it is, I need a way to give
the user a handle that he can pass back that will allow me to quickly find his timer and, along the way, validate that he was not spoofing, or just plain confused.

So what the ID layer does is pass back an available <id> (which I can pass to the user) while storing a pointer to the timer which is <id>ed. Later, given the <id>, it passes back the pointer, or NULL if the id is not in use.

OK.

Quoted 11 lines

As I said above, the pointers are kept in "nodes" of 32 along with a few bits of overhead, and these are arranged in a dynamic tree which grows as the number of allocated timers increases. The depth of the tree is 1 for up to 32 , 2 for up to 1024, and so on. The depth can never get beyond 5, by which time the system will, long since, be out of memory. At this time the leaf nodes are release when empty but the branch nodes are not. (This is an enhancement saved for later, if it seems useful.)

I am open to a better method that solves the problem...

It seems reasonable. It would be nice to be able to use radix trees, but that's a lot of work if the patch isn't going anywhere.

If radix trees are unsuitable then yes, dressing this up as a new core kernel capability (documentation! separate patch!) would be appropriate.

But I suspect the radix-tree _will_ suit, and it would be nice to grow the usefulness of radix-trees rather than creating similar-but-different trees. We can do whizzy things with radix-trees; more than at present.

Of course, that was only a teeny part of your patch. I just happened to spy it as it flew past. Given that you're at rev 20, perhaps a splitup and more accessible presentation would help.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
#25 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

Quoted 10 lines · george anzinger

...

Quoted 7 lines

radix-trees do not currently have a "find next empty slot from this offset" function but that is quite straightforward. Not quite as fast, unless an occupancy bitmap is added to the radix-tree node. That's something whcih I have done before - in fact it was an array of occupancy maps so I could do an efficient in-order gang lookup of "all dirty pages from this offset" and "all locked pages from this offset". It was before its time, and mouldered.

Quoted 4 lines

Gosh, I think this is what I have. Is it already in the kernel tree somewhere? Oh, I found it. I will look at this, tomorrow...

A simple way of doing the "find an empty slot" is to descend the tree, following the trail of nodes which have `count < 64' until you hit the bottom. At each node you'll need to walk the slots[] array to locate the first empty one.

That's quite a few cache misses. It can be optimised by adding a 64-bit DECLARE_BITMAP to struct radix_tree_node. This actually obsoletes count', because you can just replace the test for zero count with a test for all 64 bits are zero'.

Such a search would be an extension to or variant of radix_tree_gang_lookup. Something like the (old, untested) code below.

But it's a big job. First thing to do is to write a userspace test harness for the radix-tree code. That's something I need to do anyway, because radix_tree_gang_lookup fails for offests beyond the 8TB mark, and it's such a pita fixing that stuff in-kernel.

Good luck ;)

 include/linux/radix-tree.h |   11 ++
 lib/radix-tree.c           |  209 ++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 191 insertions(+), 29 deletions(-)
lib/radix-tree.c renamed from lib/radix-tree.c~radix_tree_tagged_lookup +181 -28
@@ -32,9 +32,11 @@
 #define RADIX_TREE_MAP_SHIFT  6
 #define RADIX_TREE_MAP_SIZE  (1UL << RADIX_TREE_MAP_SHIFT)
 #define RADIX_TREE_MAP_MASK  (RADIX_TREE_MAP_SIZE-1)
+#define NR_TAGS	((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG)
 
 struct radix_tree_node {
 	unsigned int	count;
+	unsigned long	tags[NR_TAGS];
 	void		*slots[RADIX_TREE_MAP_SIZE];
 };
 
@@ -221,15 +223,70 @@ void *radix_tree_lookup(struct radix_tre
 }
 EXPORT_SYMBOL(radix_tree_lookup);
 
+/**
+ * radix_tree_tag - tag an existing node
+ * @root:		radix tree root
+ * @index:		index key
+ *
+ * Tag a path down to a known-to-exist item.
+ */
+void radix_tree_tag(struct radix_tree_root *root, unsigned long index)
+{
+	unsigned int height, shift;
+	struct radix_tree_node **slot;
+
+	height = root->height;
+	if (index > radix_tree_maxindex(height))
+		return;
+
+	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
+	slot = &root->rnode;
+	root->tag = 1;
+
+	while (height > 0) {
+		unsigned int offset;
+
+		BUG_ON(*slot == NULL);
+		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+		if (slot != &root->rnode) {
+			if (!test_bit(offset, (*slot)->tags))
+				set_bit(offset, (*slot)->tags);
+		}
+		slot = (struct radix_tree_node **)((*slot)->slots + offset);
+		shift -= RADIX_TREE_MAP_SHIFT;
+		height--;
+	}
+}
+EXPORT_SYMBOL(radix_tree_tag);
+
+enum tag_mode {
+	TM_NONE,
+	TM_TEST,
+	TM_TEST_CLEAR,
+};
+
+static inline int tags_clear(struct radix_tree_node *node)
+{
+	int i;
+
+	for (i = 0; i < NR_TAGS; i++) {
+		if (node->tags[i])
+			return 0;
+	}
+	return 1;
+}
+
 static /* inline */ unsigned int
 __lookup(struct radix_tree_root *root, void **results, unsigned long index,
 	unsigned int max_items, unsigned long *next_index,
-	unsigned long max_index)
+	unsigned long max_index, enum tag_mode tag_mode)
 {
 	unsigned int nr_found = 0;
 	unsigned int shift;
 	unsigned int height = root->height;
 	struct radix_tree_node *slot;
+	struct radix_tree_node *path[RADIX_TREE_MAX_PATH];
+	struct radix_tree_node **pathp = path;
 
 	if (index > max_index)
 		return 0;
@@ -239,8 +296,12 @@ __lookup(struct radix_tree_root *root, v
 	while (height > 0) {
 		unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
 		for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
-			if (slot->slots[i] != NULL)
-				break;
+			if (slot->slots[i] != NULL) {
+				if (tag_mode == TM_NONE)
+					break;
+				if (test_bit(i, slot->tags))
+					break;
+			}
 			index &= ~((1 << shift) - 1);
 			index += 1 << shift;
 		}
@@ -248,6 +309,7 @@ __lookup(struct radix_tree_root *root, v
 			goto out;
 		height--;
 		shift -= RADIX_TREE_MAP_SHIFT;
+		*pathp++ = slot;
 		if (height == 0) {
 			/* Bottom level: grab some items */
 			unsigned long j;
@@ -257,36 +319,46 @@ __lookup(struct radix_tree_root *root, v
 			j = index & RADIX_TREE_MAP_MASK;
 			for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
 				index++;
-				if (slot->slots[j]) {
-					results[nr_found++] = slot->slots[j];
-					if (nr_found == max_items)
-						goto out;
+				if (!slot->slots[j])
+					continue;
+				if (tag_mode == TM_TEST) {
+					if (!test_bit(j, slot->tags))
+						continue;
+				}
+				if (tag_mode == TM_TEST_CLEAR) {
+					if (!test_and_clear_bit(j, slot->tags))
+						continue;
 				}
+				results[nr_found++] = slot->slots[j];
+				if (nr_found == max_items)
+					goto out;
 			}
 		}
 		slot = slot->slots[i];
 	}
 out:
+	if (tag_mode == TM_TEST_CLEAR) {
+		while (pathp > path) {
+			if (tags_clear(pathp[1])) {
+				unsigned int offset;
+
+				offset = (void **)pathp[1] - pathp[0]->slots;
+				BUG_ON(offset >= RADIX_TREE_MAP_SIZE);
+				clear_bit(offset, pathp[0]->tags);
+			} else {
+				break;
+			}
+		}
+	}
 	*next_index = index;
 	return nr_found;
 	
 }
-/**
- *	radix_tree_gang_lookup - perform multiple lookup on a radix tree
- *	@root:		radix tree root
- *	@results:	where the results of the lookup are placed
- *	@first_index:	start the lookup from this key
- *	@max_items:	place up to this many items at *results
- *
- *	Performs an index-ascending scan of the tree for present items.  Places
- *	them at *@results and returns the number of items which were placed at
- *	*@results.
- *
- *	The implementation is naive.
- */
-unsigned int
-radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
-			unsigned long first_index, unsigned int max_items)
+
+static unsigned int
+gang_lookup(struct radix_tree_root *root, void **results,
+	unsigned long first_index, unsigned int max_items,
+	enum tag_mode tag_mode)
 {
 	const unsigned long max_index = radix_tree_maxindex(root->height);
 	unsigned long cur_index = first_index;
@@ -297,18 +369,37 @@ radix_tree_gang_lookup(struct radix_tree
 	if (max_index == 0) {			/* Bah.  Special case */
 		if (first_index == 0) {
 			if (max_items > 0) {
-				*results = root->rnode;
-				ret = 1;
+				switch (tag_mode) {
+				case TM_NONE:
+					*results = root->rnode;
+					ret = 1;
+					break;
+				case TM_TEST:
+					if (root->tag) {
+						*results = root->rnode;
+						ret = 1;
+					}
+					break;
+				case TM_TEST_CLEAR:
+					if (root->tag) {
+						*results = root->rnode;
+						ret = 1;
+						root->tag = 0;
+					}
+					break;
+				}
 			}
 		}
 		goto out;
 	}
+
 	while (ret < max_items) {
 		unsigned int nr_found;
 		unsigned long next_index;	/* Index of next search */
 
 		nr_found = __lookup(root, results + ret, cur_index,
-				max_items - ret, &next_index, max_index);
+				max_items - ret, &next_index,
+				max_index, tag_mode);
 		if (nr_found == 0)
 			break;
 		ret += nr_found;
@@ -317,9 +408,70 @@ radix_tree_gang_lookup(struct radix_tree
 out:
 	return ret;
 }
+
+/**
+ * radix_tree_gang_lookup - perform multiple lookup on a radix tree
+ * @root:		radix tree root
+ * @results:		where the results of the lookup are placed
+ * @first_index:	start the lookup from this key
+ * @max_items:		place up to this many items at *results
+ *
+ * Performs an index-ascending scan of the tree for present items.  Places them
+ * at *@results and returns the number of items which were placed at *@results.
+ *
+ *	The implementation is naive.
+ */
+unsigned int
+radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
+			unsigned long first_index, unsigned int max_items)
+{
+	return gang_lookup(root, results, first_index, max_items, TM_NONE);
+}
 EXPORT_SYMBOL(radix_tree_gang_lookup);
 
 /**
+ * radix_tree_test_gang_lookup - perform multiple lookup on a radix tree
+ * @root:		radix tree root
+ * @results:		where the results of the lookup are placed
+ * @first_index:	start the lookup from this key
+ * @max_items:		place up to this many items at *results
+ *
+ * Performs an index-ascending scan of the tree for present items which are
+ * tagged.  Places them at *@results and returns the number of items which were
+ * placed at *@results.
+ */
+unsigned int
+radix_tree_test_gang_lookup(struct radix_tree_root *root, void **results,
+			unsigned long first_index, unsigned int max_items)
+{
+	return gang_lookup(root, results, first_index, max_items, TM_TEST);
+}
+EXPORT_SYMBOL(radix_tree_test_gang_lookup);
+
+/**
+ * radix_tree_test_clear_gang_lookup - perform multiple lookup on a radix tree,
+ *                                     clearing its tag tree.
+ * @root:		radix tree root
+ * @results:		where the results of the lookup are placed
+ * @first_index:	start the lookup from this key
+ * @max_items:		place up to this many items at *results
+ *
+ * Performs an index-ascending scan of the tree for present items which are
+ * tagged.  Places them at *@results and returns the number of items which were
+ * placed at *@results.
+ *
+ * The tags are cleared on the path back up from the found items.
+ */
+unsigned int
+radix_tree_test_clear_gang_lookup(struct radix_tree_root *root, void **results,
+			unsigned long first_index, unsigned int max_items)
+{
+	return gang_lookup(root, results, first_index,
+				max_items, TM_TEST_CLEAR);
+}
+EXPORT_SYMBOL(radix_tree_test_clear_gang_lookup);
+
+/**
  *	radix_tree_delete    -    delete an item from a radix tree
  *	@root:		radix tree root
  *	@index:		index key
@@ -366,7 +518,8 @@ int radix_tree_delete(struct radix_tree_
 
 EXPORT_SYMBOL(radix_tree_delete);
 
-static void radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
+static void
+radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
 {
 	memset(node, 0, sizeof(struct radix_tree_node));
 }
@@ -390,7 +543,7 @@ void __init radix_tree_init(void)
 {
 	radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
 			sizeof(struct radix_tree_node), 0,
-			SLAB_HWCACHE_ALIGN, radix_tree_node_ctor, NULL);
+			0, radix_tree_node_ctor, NULL);
 	if (!radix_tree_node_cachep)
 		panic ("Failed to create radix_tree_node cache\n");
 	radix_tree_node_pool = mempool_create(512, radix_tree_node_pool_alloc,
include/linux/radix-tree.h renamed from include/linux/radix-tree.h~radix_tree_tagged_lookup +10 -1
@@ -26,10 +26,11 @@ struct radix_tree_node;
 struct radix_tree_root {
 	unsigned int		height;
 	int			gfp_mask;
+	int			tag;	/* ugh.  dirtiness of the top node */
 	struct radix_tree_node	*rnode;
 };
 
-#define RADIX_TREE_INIT(mask)	{0, (mask), NULL}
+#define RADIX_TREE_INIT(mask)	{0, (mask), 0, NULL}
 
 #define RADIX_TREE(name, mask) \
 	struct radix_tree_root name = RADIX_TREE_INIT(mask)
@@ -38,6 +39,7 @@ struct radix_tree_root {
 do {					\
 	(root)->height = 0;		\
 	(root)->gfp_mask = (mask);	\
+	(root)->tag = 0;		\
 	(root)->rnode = NULL;		\
 } while (0)
 
@@ -48,5 +50,12 @@ extern int radix_tree_delete(struct radi
 extern unsigned int
 radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
 			unsigned long first_index, unsigned int max_items);
+extern unsigned int
+radix_tree_test_gang_lookup(struct radix_tree_root *root, void **results,
+			unsigned long first_index, unsigned int max_items);
+extern unsigned int
+radix_tree_test_clear_gang_lookup(struct radix_tree_root *root, void **results,
+			unsigned long first_index, unsigned int max_items);
+void radix_tree_tag(struct radix_tree_root *root, unsigned long index);
 
 #endif /* _LINUX_RADIX_TREE_H */

.

#26 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

Quoted 8 lines · Andrew Morton

A simple way of doing the "find an empty slot" is to descend the tree, following the trail of nodes which have `count < 64' until you hit the bottom. At each node you'll need to walk the slots[] array to locate the first empty one.
That's quite a few cache misses. It can be optimised by adding a 64-bit DECLARE_BITMAP to struct radix_tree_node. This actually obsoletes count', because you can just replace the test for zero count with a test for all 64 bits are zero'.

I found that ffz() to find the index of the not-fully-populated child node to search was efficient enough to provide a precisely K == 2*levels constant within the O(1) for accesses in all non-failure cases. Measuring by cachelines it would have been superior to provide a cacheline-sized node at each level and perform ffz by hand.

Quoted 6 lines · Andrew Morton

Such a search would be an extension to or variant of radix_tree_gang_lookup. Something like the (old, untested) code below.
But it's a big job. First thing to do is to write a userspace test harness for the radix-tree code. That's something I need to do anyway, because radix_tree_gang_lookup fails for offests beyond the 8TB mark, and it's such a pita fixing that stuff in-kernel.

Userspace test harnesses are essential for this kind of work. They were for several of mine.

Bill

#27 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

In reply to Andrew Morton
Quoted 22 lines · Andrew Morton
Quoted 10 lines · george anzinger

...

Quoted 7 lines

radix-trees do not currently have a "find next empty slot from this offset" function but that is quite straightforward. Not quite as fast, unless an occupancy bitmap is added to the radix-tree node. That's something whcih I have done before - in fact it was an array of occupancy maps so I could do an efficient in-order gang lookup of "all dirty pages from this offset" and "all locked pages from this offset". It was before its time, and mouldered.

Quoted 4 lines

Gosh, I think this is what I have. Is it already in the kernel tree somewhere? Oh, I found it. I will look at this, tomorrow...

A simple way of doing the "find an empty slot" is to descend the tree, following the trail of nodes which have `count < 64' until you hit the bottom. At each node you'll need to walk the slots[] array to locate the first empty one.

Quoted 4 lines

That's quite a few cache misses. It can be optimised by adding a 64-bit DECLARE_BITMAP to struct radix_tree_node. This actually obsoletes count', because you can just replace the test for zero count with a test for all 64 bits are zero'.

Uh, I tried something like this. The flaw is that the count is a count of used slots at in that node and does not say anything about slots in any nodes below that one. In my tree the bit map is an indication of empty leaf node slots. This means that when a leaf slot becomes free it needs to be reflected in each node in the path to that leaf and when a leaf node fills, that also needs to be reflected in each node in the path.

Quoted 10 lines

Such a search would be an extension to or variant of radix_tree_gang_lookup. Something like the (old, untested) code below.

But it's a big job. First thing to do is to write a userspace test harness for the radix-tree code. That's something I need to do anyway, because radix_tree_gang_lookup fails for offests beyond the 8TB mark, and it's such a pita fixing that stuff in-kernel.

Good luck ;)

Hm, the question becomes:
a.)Should I add code to the radix-tree to make it do what I need and, most likely take longer and be harder to debug, or b.)Should I just enhance what I have to remove the recursion, which should be rather easy to do and test, even in kernel land?

Quoted 2 lines

.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
#28 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

In reply to george anzinger

[ repost - first attempt failed to get out ]

Quoted 7 lines
Quoted 1 line

Is the "don't reuse an ID for some time" requirement still there?

I don't see the need for the "don't reuse an ID for some time" thing and it looked like what Jim had messed up the book keeping AND it also looked like it failed to actually work. All of this convinced me that the added complexity was just not worth it.

A thought: any algorithm that fails to "reuse an ID for some time" can be converted into one that does by tweaking the algorithn to return an ID with fewer bits and putting a counter (bumped on each fresh allocation of that ID) in the remaining bits. Or, one can go stateless and achieve an "almost never reuse an ID for some time" by instead inserting a freshly generated pseudo-random number in the unused ID bits.

Joe - Concurrent Computer Corporation

#29 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

Quoted 11 lines · Joe Korty

[ repost - first attempt failed to get out ]

Quoted 7 lines
Quoted 1 line

Is the "don't reuse an ID for some time" requirement still there?

I don't see the need for the "don't reuse an ID for some time" thing and it looked like what Jim had messed up the book keeping AND it also looked like it failed to actually work. All of this convinced me that the added complexity was just not worth it.

Quoted 8 lines

A thought: any algorithm that fails to "reuse an ID for some time" can be converted into one that does by tweaking the algorithn to return an ID with fewer bits and putting a counter (bumped on each fresh allocation of that ID) in the remaining bits. Or, one can go stateless and achieve an "almost never reuse an ID for some time" by instead inserting a freshly generated pseudo-random number in the unused ID bits.

With out going into a lot of detail, since I don't think I need such an animal, one would need to keep the actual id somewhere (either the node or in what it pointed to).

Perhaps a less costly way would be to keep a sequence number, say the number of items allocated so far and inserting that. I think one would want to make sure this is not a power of 2, but this may not be needed as the first freeing would generate an indexing of the number WRT to the id.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
#30 lore raw

Re: [PATCH 3/3] High-res-timers part 3 (posix to hrposix) take 20

In reply to george anzinger
Quoted 14 lines · george anzinger

...

Hm... This whole thing came up to solve and issue related to having a finite number of timers. The ID layer is just a way of saving a pointer to a given "thing" (a timer structure in this case) in a way that it can be recovered quickly. It is really just a tree structure with 32 branches (or is it sizeof long branches) at each node. There is a bit map to indicate if any free slots are available and if so under which branch. This makes allocation of a new ID quite fast. The "reuse" thing is there to separate it from the original code which "attempted" to not reuse and ID for some time.

Is the "don't reuse an ID for some time" requirement still there?

I think you can use radix trees for this. Just put the pointer to your "thing" direct into the tree. The space overhead will be about the same.

radix-trees do not currently have a "find next empty slot from this offset" function but that is quite straightforward. Not quite as fast, unless an occupancy bitmap is added to the radix-tree node. That's something whcih I have done before - in fact it was an array of occupancy maps so I could do an efficient in-order gang lookup of "all dirty pages from this offset" and "all locked pages from this offset". It was before its time, and mouldered.

Quoted 4 lines

...

Quoted 1 line

A lot of the functions in this header are too large to be inlined.

Hm... What is "too large", i.e. how much code.

A few lines, I suspect.

Quoted 1 line

Also, is it used more than once?

Don't trust the compiler too much ;) Uninlining mpage_writepage() saved a couple of hundred bytes of code, even though it has only one call site.

Quoted 6 lines

...

Quoted 2 lines

Please, just open-code the locking. This simply makes it harder to follow the main code.

But makes it easy to change the lock method, to, for example, use irq or irqsave or "shudder" RCU.

A diligent programmer would visit all sites as part of that conversion anyway.

Quoted 8 lines
Quoted 7 lines

kernel/id_reuse.c line 36

Quoted 4 lines
kernel/id_reuse.c +3 -0
+
+static struct idr_layer *id_free;
+static int id_free_cnt;

hm. We seem to have a global private freelist here. Is the more SMP-friendly slab not suitable?

Quoted 4 lines

There is a short local free list to avoid calling slab with a spinlock held. Only enough entries are kept to allocate a new node at each branch from the root to leaf, and only for this reason.

Fair enough. There are similar requirements elsewhere and the plan there is to create a page reservation API, so you can ensure that the page allocator will be able to provide at least N pages. Then take the lock and go for it.

I have code for that which is about to bite the bit bucket. But the
new version should be in place soon. Other users will be radix tree
nodes, pte_chains and mm_chains (shared pagetable patch).

Quoted 5 lines

...

Quoted 2 lines

Recursion!

Yes, it is a tree after all.

lib/radix_tree.c does everything iteratively.

Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

+void idr_init(struct idr *idp)

Please tell us a bit about this id layer: what problems it solves, how it solves them, why it is needed and why existing kernel facilities are unsuitable.

Quoted 11 lines

The prior version of the code had a CONFIG option to set the maximum number of timers. This caused enough memory to be "compiled" in to keep pointers to this many timers. The ID layer was invented (by Jim Houston, by the way) to eliminate this CONFIG thing. If I were to ask for a capability from slab that would eliminate the need for this it would be the ability to, given an address and a slab pool, to validate that the address was "live" and from that pool. I.e. that the address is a pointer to currently allocated block from that memory pool. With this, I could just pass the address to the user as the timer_id.

That might cause problems with 64-bit kernel/32-bit userspace. Passing out kernel addresses in this way may have other problems..

Quoted 9 lines

As it is, I need a way to give
the user a handle that he can pass back that will allow me to quickly find his timer and, along the way, validate that he was not spoofing, or just plain confused.

So what the ID layer does is pass back an available <id> (which I can pass to the user) while storing a pointer to the timer which is <id>ed. Later, given the <id>, it passes back the pointer, or NULL if the id is not in use.

OK.

Quoted 11 lines

As I said above, the pointers are kept in "nodes" of 32 along with a few bits of overhead, and these are arranged in a dynamic tree which grows as the number of allocated timers increases. The depth of the tree is 1 for up to 32 , 2 for up to 1024, and so on. The depth can never get beyond 5, by which time the system will, long since, be out of memory. At this time the leaf nodes are release when empty but the branch nodes are not. (This is an enhancement saved for later, if it seems useful.)

I am open to a better method that solves the problem...

It seems reasonable. It would be nice to be able to use radix trees, but that's a lot of work if the patch isn't going anywhere.

If radix trees are unsuitable then yes, dressing this up as a new core kernel capability (documentation! separate patch!) would be appropriate.

But I suspect the radix-tree _will_ suit, and it would be nice to grow the usefulness of radix-trees rather than creating similar-but-different trees. We can do whizzy things with radix-trees; more than at present.

Of course, that was only a teeny part of your patch. I just happened to spy it as it flew past. Given that you're at rev 20, perhaps a splitup and more accessible presentation would help.

#31 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 20.1

In reply to george anzinger

Oh, sh..t. Wrong patch! This is the right one.

And this finishs the high res timers code.

I had to add arg3 to the restart_block to handle the two word restart time...

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.50-bk7

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/kernel/entry.S +14 -8
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
@@ -41,7 +41,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/errno.h>
@@ -239,7 +238,7 @@
 	pushl %eax			# save orig_eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebx)
-	cmpl $(NR_syscalls), %eax
+	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 					# system call tracing in operation
 	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebx)
@@ -315,7 +314,7 @@
 	xorl %edx,%edx
 	call do_syscall_trace
 	movl ORIG_EAX(%esp), %eax
-	cmpl $(NR_syscalls), %eax
+	cmpl $(nr_syscalls), %eax
 	jnae syscall_call
 	jmp syscall_exit
 
@@ -769,8 +768,15 @@
 	.long sys_epoll_wait
  	.long sys_remap_file_pages
  	.long sys_set_tid_address
-
-
-	.rept NR_syscalls-(.-sys_call_table)/4
-		.long sys_ni_syscall
-	.endr
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+ 
+ 
+nr_syscalls=(.-sys_call_table)/4
arch/i386/kernel/time.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
@@ -132,6 +132,7 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 	write_unlock_irq(&xtime_lock);
+	clock_was_set();
 }
 
 /*
fs/exec.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/fs/exec.c linux/fs/exec.c
@@ -779,6 +779,7 @@
 			
 	flush_signal_handlers(current);
 	flush_old_files(current->files);
+	exit_itimers(current);
 
 	return 0;
 
include/asm-generic/siginfo.h +12 -4
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-generic/siginfo.h linux/include/asm-generic/siginfo.h
@@ -43,8 +43,11 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
+			int _overrun;		/* overrun count */
+			char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
+			sigval_t _sigval;	/* same as below */
+			int _sys_private;       /* not to be passed to user */
 		} _timer;
 
 		/* POSIX.1b signals */
@@ -86,8 +89,9 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
-#define si_timer1	_sifields._timer._timer1
-#define si_timer2	_sifields._timer._timer2
+#define si_tid		_sifields._timer._tid
+#define si_overrun	_sifields._timer._overrun
+#define si_sys_private  _sifields._timer._sys_private
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
@@ -221,6 +225,7 @@
 #define SIGEV_SIGNAL	0	/* notify via signal */
 #define SIGEV_NONE	1	/* other notification: meaningless */
 #define SIGEV_THREAD	2	/* deliver via thread creation */
+#define SIGEV_THREAD_ID 4	/* deliver to thread */
 
 #define SIGEV_MAX_SIZE	64
 #ifndef SIGEV_PAD_SIZE
@@ -235,6 +240,7 @@
 	int sigev_notify;
 	union {
 		int _pad[SIGEV_PAD_SIZE];
+		 int _tid;
 
 		struct {
 			void (*_function)(sigval_t);
@@ -247,10 +253,12 @@
 
 #define sigev_notify_function	_sigev_un._sigev_thread._function
 #define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+#define sigev_notify_thread_id	 _sigev_un._tid
 
 #ifdef __KERNEL__
 
 struct siginfo;
+void do_schedule_next_timer(struct siginfo *info);
 
 #ifndef HAVE_ARCH_COPY_SIGINFO
 
include/asm-i386/posix_types.h +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h
@@ -22,6 +22,8 @@
 typedef long		__kernel_time_t;
 typedef long		__kernel_suseconds_t;
 typedef long		__kernel_clock_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef unsigned short	__kernel_uid16_t;
include/asm-i386/signal.h +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-i386/signal.h linux/include/asm-i386/signal.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/linkage.h>
+#include <linux/time.h>
 
 /* Avoid too many header ordering problems.  */
 struct siginfo;
include/asm-i386/unistd.h +9 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
@@ -264,6 +264,15 @@
 #define __NR_sys_epoll_wait	256
 #define __NR_remap_file_pages	257
 #define __NR_set_tid_address	258
+#define __NR_timer_create	259
+#define __NR_timer_settime	(__NR_timer_create+1)
+#define __NR_timer_gettime	(__NR_timer_create+2)
+#define __NR_timer_getoverrun	(__NR_timer_create+3)
+#define __NR_timer_delete	(__NR_timer_create+4)
+#define __NR_clock_settime	(__NR_timer_create+5)
+#define __NR_clock_gettime	(__NR_timer_create+6)
+#define __NR_clock_getres	(__NR_timer_create+7)
+#define __NR_clock_nanosleep	(__NR_timer_create+8)
 
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
include/linux/id_reuse.h +119 -0

119 lines not on this page · raw message

include/linux/init_task.h +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/init_task.h linux/include/linux/init_task.h
@@ -93,6 +93,7 @@
 	.sig		= &init_signals,				\
 	.pending	= { NULL, &tsk.pending.head, {{0}}},		\
 	.blocked	= {{0}},					\
+	 .posix_timers	 = LIST_HEAD_INIT(tsk.posix_timers),		   \
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
include/linux/posix-timers.h +30 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -0,0 +1,30 @@
+#ifndef _linux_POSIX_TIMERS_H
+#define _linux_POSIX_TIMERS_H
+
+struct k_clock {
+	int res;		/* in nano seconds */
+	int (*clock_set) (struct timespec * tp);
+	int (*clock_get) (struct timespec * tp);
+	int (*nsleep) (int flags,
+		       struct timespec * new_setting,
+		       struct itimerspec * old_setting);
+	int (*timer_set) (struct k_itimer * timr, int flags,
+			  struct itimerspec * new_setting,
+			  struct itimerspec * old_setting);
+	int (*timer_del) (struct k_itimer * timr);
+	void (*timer_get) (struct k_itimer * timr,
+			   struct itimerspec * cur_setting);
+};
+struct now_struct {
+	unsigned long jiffies;
+};
+
+#define posix_get_now(now) (now)->jiffies = jiffies;
+#define posix_time_before(timer, now) \
+                      time_before((timer)->expires, (now)->jiffies)
+
+#define posix_bump_timer(timr) do { \
+                        (timr)->it_timer.expires += (timr)->it_incr; \
+                        (timr)->it_overrun++;               \
+                       }while (0)
+#endif
include/linux/sched.h +21 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/sched.h linux/include/linux/sched.h
@@ -276,6 +276,25 @@
 typedef struct prio_array prio_array_t;
 struct backing_dev_info;
 
+/* POSIX.1b interval timer structure. */
+struct k_itimer {
+	struct list_head list;		 /* free/ allocate list */
+	spinlock_t it_lock;
+	clockid_t it_clock;		/* which timer type */
+	timer_t it_id;			/* timer id */
+	int it_overrun;			/* overrun on pending signal  */
+	int it_overrun_last;		 /* overrun on last delivered signal */
+	int it_requeue_pending;          /* waiting to requeue this timer */
+	int it_sigev_notify;		 /* notify word of sigevent struct */
+	int it_sigev_signo;		 /* signo word of sigevent struct */
+	sigval_t it_sigev_value;	 /* value word of sigevent struct */
+	unsigned long it_incr;		/* interval specified in jiffies */
+	struct task_struct *it_process;	/* process to send signal to */
+	struct timer_list it_timer;
+};
+
+
+
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
@@ -339,6 +358,7 @@
 	unsigned long it_real_value, it_prof_value, it_virt_value;
 	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 	struct timer_list real_timer;
+	struct list_head posix_timers; /* POSIX.1b Interval Timers */
 	unsigned long utime, stime, cutime, cstime;
 	unsigned long start_time;
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
@@ -579,6 +599,7 @@
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
 extern void __exit_sighand(struct task_struct *);
+extern void exit_itimers(struct task_struct *);
 
 extern void reparent_to_init(void);
 extern void daemonize(void);
include/linux/signal.h +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/signal.h linux/include/linux/signal.h
@@ -224,7 +224,7 @@
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs);
 #endif
-
+#define FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
include/linux/sys.h +1 -2
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/sys.h linux/include/linux/sys.h
@@ -2,9 +2,8 @@
 #define _LINUX_SYS_H
 
 /*
- * system call entry points ... but not all are defined
+ * This file is no longer used or needed
  */
-#define NR_syscalls 260
 
 /*
  * These are system calls that will be removed at some time
include/linux/time.h +35 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/time.h linux/include/linux/time.h
@@ -40,6 +40,19 @@
  */
 #define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
 
+/* Parameters used to convert the timespec values */
+#ifndef USEC_PER_SEC
+#define USEC_PER_SEC (1000000L)
+#endif
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC (1000000000L)
+#endif
+
+#ifndef NSEC_PER_USEC
+#define NSEC_PER_USEC (1000L)
+#endif
+
 static __inline__ unsigned long
 timespec_to_jiffies(struct timespec *value)
 {
@@ -138,6 +151,8 @@
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
 extern void do_settimeofday(struct timeval *tv);
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern void clock_was_set(void); // call when ever the clock is set
 extern long do_nanosleep(struct timespec *t);
 extern long do_utimes(char * filename, struct timeval * times);
 #endif
@@ -165,5 +180,25 @@
 	struct	timeval it_interval;	/* timer interval */
 	struct	timeval it_value;	/* current value */
 };
+
+
+/*
+ * The IDs of the various system clocks (for POSIX.1b interval timers).
+ */
+#define CLOCK_REALTIME		  0
+#define CLOCK_MONOTONIC	  1
+#define CLOCK_PROCESS_CPUTIME_ID 2
+#define CLOCK_THREAD_CPUTIME_ID	 3
+#define CLOCK_REALTIME_HR	 4
+#define CLOCK_MONOTONIC_HR	  5
+
+#define MAX_CLOCKS 6
+
+/*
+ * The various flags for setting POSIX.1b interval timers.
+ */
+
+#define TIMER_ABSTIME 0x01
+
 
 #endif
include/linux/types.h +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/include/linux/types.h linux/include/linux/types.h
@@ -23,6 +23,8 @@
 typedef __kernel_daddr_t	daddr_t;
 typedef __kernel_key_t		key_t;
 typedef __kernel_suseconds_t	suseconds_t;
+typedef __kernel_timer_t	timer_t;
+typedef __kernel_clockid_t	clockid_t;
 
 #ifdef __KERNEL__
 typedef __kernel_uid32_t	uid_t;
kernel/Makefile +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/Makefile linux/kernel/Makefile
@@ -10,7 +10,7 @@
 	    exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \
-	    rcupdate.o intermodule.o extable.o
+	    rcupdate.o intermodule.o extable.o posix-timers.o id_reuse.o
 
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
kernel/exit.c +2 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/exit.c linux/kernel/exit.c
@@ -411,6 +411,7 @@
 	mmdrop(active_mm);
 }
 
+
 /*
  * Turn us into a lazy TLB process if we
  * aren't already..
@@ -659,6 +660,7 @@
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	exit_namespace(tsk);
+	exit_itimers(tsk);
 	exit_thread();
 
 	if (current->leader)
kernel/fork.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/fork.c linux/kernel/fork.c
@@ -810,6 +810,7 @@
 		goto bad_fork_cleanup_files;
 	if (copy_sighand(clone_flags, p))
 		goto bad_fork_cleanup_fs;
+	INIT_LIST_HEAD(&p->posix_timers);
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
 	if (copy_namespace(clone_flags, p))
kernel/id_reuse.c +194 -0

194 lines not on this page · raw message

kernel/posix-timers.c +1311 -0

1,311 lines not on this page · raw message

kernel/signal.c +31 -9
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/signal.c linux/kernel/signal.c
@@ -457,8 +457,6 @@
 		if (!collect_signal(sig, pending, info))
 			sig = 0;
 				
-		/* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER,
-		   we need to xchg out the timer overrun values.  */
 	}
 	recalc_sigpending();
 
@@ -473,6 +471,7 @@
  */
 int dequeue_signal(sigset_t *mask, siginfo_t *info)
 {
+	int ret;
 	/*
 	 * Here we handle shared pending signals. To implement the full
 	 * semantics we need to unqueue and resend them. It will likely
@@ -483,7 +482,13 @@
 		if (signr)
 			__send_sig_info(signr, info, current);
 	}
-	return __dequeue_signal(&current->pending, mask, info);
+	ret = __dequeue_signal(&current->pending, mask, info);
+	if ( ret &&
+	     ((info->si_code & __SI_MASK) == __SI_TIMER) &&
+	     info->si_sys_private){
+		do_schedule_next_timer(info);
+	}
+	return ret;
 }
 
 static int rm_from_queue(int sig, struct sigpending *s)
@@ -622,6 +627,7 @@
 static int send_signal(int sig, struct siginfo *info, struct sigpending *signals)
 {
 	struct sigqueue * q = NULL;
+	int ret = 0;
 
 	/*
 	 * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -665,17 +671,26 @@
 				copy_siginfo(&q->info, info);
 				break;
 		}
-	} else if (sig >= SIGRTMIN && info && (unsigned long)info != 1
+	} else {
+		if (sig >= SIGRTMIN && info && (unsigned long)info != 1
 		   && info->si_code != SI_USER)
 		/*
 		 * Queue overflow, abort.  We may abort if the signal was rt
 		 * and sent by user using something other than kill().
 		 */
-		return -EAGAIN;
+			return -EAGAIN;
+
+		if (((unsigned long)info > 1) && (info->si_code == SI_TIMER))
+			/*
+			 * Set up a return to indicate that we dropped 
+			 * the signal.
+			 */
+			ret = info->si_sys_private;
+	}
 
 out_set:
 	sigaddset(&signals->signal, sig);
-	return 0;
+	return ret;
 }
 
 /*
@@ -715,7 +730,7 @@
 {
 	int retval = send_signal(sig, info, &t->pending);
 
-	if (!retval && !sigismember(&t->blocked, sig))
+	if ((retval >= 0) && !sigismember(&t->blocked, sig))
 		signal_wake_up(t);
 
 	return retval;
@@ -751,6 +766,12 @@
 
 	handle_stop_signal(sig, t);
 
+	if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))
+		/*
+		 * Set up a return to indicate that we dropped the signal.
+		 */
+		ret = info->si_sys_private;
+
 	/* Optimize away the signal, if it's a signal that can be
 	   handled immediately (ie non-blocked and untraced) and
 	   that is ignored (either explicitly or by default).  */
@@ -1477,8 +1498,9 @@
 		err |= __put_user(from->si_uid, &to->si_uid);
 		break;
 	case __SI_TIMER:
-		err |= __put_user(from->si_timer1, &to->si_timer1);
-		err |= __put_user(from->si_timer2, &to->si_timer2);
+		 err |= __put_user(from->si_tid, &to->si_tid);
+		 err |= __put_user(from->si_overrun, &to->si_overrun);
+		 err |= __put_user(from->si_ptr, &to->si_ptr);
 		break;
 	case __SI_POLL:
 		err |= __put_user(from->si_band, &to->si_band);
kernel/timer.c +17 -14
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk7-kb/kernel/timer.c linux/kernel/timer.c
@@ -49,12 +49,11 @@
 	struct list_head vec[TVR_SIZE];
 } tvec_root_t;
 
-typedef struct timer_list timer_t;
 
 struct tvec_t_base_s {
 	spinlock_t lock;
 	unsigned long timer_jiffies;
-	timer_t *running_timer;
+	struct timer_list *running_timer;
 	tvec_root_t tv1;
 	tvec_t tv2;
 	tvec_t tv3;
@@ -67,7 +66,7 @@
 /* Fake initialization */
 static DEFINE_PER_CPU(tvec_base_t, tvec_bases) = { SPIN_LOCK_UNLOCKED };
 
-static void check_timer_failed(timer_t *timer)
+static void check_timer_failed(struct timer_list *timer)
 {
 	static int whine_count;
 	if (whine_count < 16) {
@@ -85,13 +84,13 @@
 	timer->magic = TIMER_MAGIC;
 }
 
-static inline void check_timer(timer_t *timer)
+static inline void check_timer(struct timer_list *timer)
 {
 	if (timer->magic != TIMER_MAGIC)
 		check_timer_failed(timer);
 }
 
-static inline void internal_add_timer(tvec_base_t *base, timer_t *timer)
+static inline void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
 {
 	unsigned long expires = timer->expires;
 	unsigned long idx = expires - base->timer_jiffies;
@@ -143,7 +142,7 @@
  * Timers with an ->expired field in the past will be executed in the next
  * timer tick. It's illegal to add an already pending timer.
  */
-void add_timer(timer_t *timer)
+void add_timer(struct timer_list *timer)
 {
 	int cpu = get_cpu();
 	tvec_base_t *base = &per_cpu(tvec_bases, cpu);
@@ -201,7 +200,7 @@
  * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
  * active timer returns 1.)
  */
-int mod_timer(timer_t *timer, unsigned long expires)
+int mod_timer(struct timer_list *timer, unsigned long expires)
 {
 	tvec_base_t *old_base, *new_base;
 	unsigned long flags;
@@ -278,7 +277,7 @@
  * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
  * active timer returns 1.)
  */
-int del_timer(timer_t *timer)
+int del_timer(struct timer_list *timer)
 {
 	unsigned long flags;
 	tvec_base_t *base;
@@ -317,7 +316,7 @@
  *
  * The function returns whether it has deactivated a pending timer or not.
  */
-int del_timer_sync(timer_t *timer)
+int del_timer_sync(struct timer_list *timer)
 {
 	tvec_base_t *base;
 	int i, ret = 0;
@@ -360,9 +359,9 @@
 	 * detach them individually, just clear the list afterwards.
 	 */
 	while (curr != head) {
-		timer_t *tmp;
+		struct timer_list *tmp;
 
-		tmp = list_entry(curr, timer_t, entry);
+		tmp = list_entry(curr, struct timer_list, entry);
 		if (tmp->base != base)
 			BUG();
 		next = curr->next;
@@ -401,9 +400,9 @@
 		if (curr != head) {
 			void (*fn)(unsigned long);
 			unsigned long data;
-			timer_t *timer;
+			struct timer_list *timer;
 
-			timer = list_entry(curr, timer_t, entry);
+			timer = list_entry(curr, struct timer_list, entry);
  			fn = timer->function;
  			data = timer->data;
 
@@ -505,6 +504,7 @@
 	if (xtime.tv_sec % 86400 == 0) {
 	    xtime.tv_sec--;
 	    time_state = TIME_OOP;
+	    clock_was_set();
 	    printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n");
 	}
 	break;
@@ -513,6 +513,7 @@
 	if ((xtime.tv_sec + 1) % 86400 == 0) {
 	    xtime.tv_sec++;
 	    time_state = TIME_WAIT;
+	    clock_was_set();
 	    printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n");
 	}
 	break;
@@ -965,7 +966,7 @@
  */
 signed long schedule_timeout(signed long timeout)
 {
-	timer_t timer;
+	struct timer_list timer;
 	unsigned long expire;
 
 	switch (timeout)
@@ -1020,6 +1021,7 @@
 {
 	return current->pid;
 }
+#ifndef FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP
 
 static long nanosleep_restart(struct restart_block *restart)
 {
@@ -1078,6 +1080,7 @@
 	}
 	return ret;
 }
+#endif // ! FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP
 
 /*
  * sys_sysinfo - fill in sysinfo struct

Binary files linux-2.5.50-bk7-kb/scripts/kallsyms and linux/scripts/kallsyms differ Binary files linux-2.5.50-bk7-kb/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.50-bk7-kb/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.50-bk7-kb/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#32 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 21

In reply to george anzinger

And this finishs the high res timers code.

Changes since last time:
<none>
-----------

I had to add arg3 to the restart_block to handle the two word restart time...

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.52-bk4

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +34 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.52-bk4-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,39 @@
 	void (*timer_get) (struct k_itimer * timr,
 			   struct itimerspec * cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct {
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void
+posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)) {
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+
+#else
 struct now_struct {
 	unsigned long jiffies;
 };
@@ -27,4 +60,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif				// CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.52-bk4-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -289,6 +289,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
include/linux/thread_info.h +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.52-bk4-i386/include/linux/thread_info.h linux/include/linux/thread_info.h
@@ -12,7 +12,7 @@
  */
 struct restart_block {
 	long (*fn)(struct restart_block *);
-	unsigned long arg0, arg1, arg2;
+	unsigned long arg0, arg1, arg2, arg3;
 };
 
 extern long do_no_restart_syscall(struct restart_block *parm);

Only in linux-2.5.52-bk4-i386/kernel: linux

kernel/posix-timers.c +115 -17

292 lines not on this page · raw message

Binary files linux-2.5.52-bk4-i386/scripts/kallsyms and linux/scripts/kallsyms differ Binary files linux-2.5.52-bk4-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.52-bk4-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.52-bk4-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#33 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 22

In reply to george anzinger

And this finishs the high res timers code.

Changes since last time:
Changed base kernel version.
-----------

I had to add arg3 to the restart_block to handle the two word restart time...

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

Patch is against 2.5.53-bk5

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +34 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.53-bk5-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,39 @@
 	void (*timer_get) (struct k_itimer * timr,
 			   struct itimerspec * cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct {
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void
+posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)) {
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+
+#else
 struct now_struct {
 	unsigned long jiffies;
 };
@@ -27,4 +60,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif				// CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.53-bk5-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -289,6 +289,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
include/linux/thread_info.h +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.53-bk5-i386/include/linux/thread_info.h linux/include/linux/thread_info.h
@@ -12,7 +12,7 @@
  */
 struct restart_block {
 	long (*fn)(struct restart_block *);
-	unsigned long arg0, arg1, arg2;
+	unsigned long arg0, arg1, arg2, arg3;
 };
 
 extern long do_no_restart_syscall(struct restart_block *parm);
kernel/posix-timers.c +115 -17

292 lines not on this page · raw message

Binary files linux-2.5.53-bk5-i386/scripts/kallsyms and linux/scripts/kallsyms differ Binary files linux-2.5.53-bk5-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.53-bk5-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.53-bk5-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#34 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 23

In reply to george anzinger

And this finishs the high res timers code.

Now for 2.5.54-bk1

Changes since last time:
-----------

I had to add arg3 to the restart_block to handle the two word restart time...

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +34 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.54-bk1-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,39 @@
 	void (*timer_get) (struct k_itimer * timr,
 			   struct itimerspec * cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct {
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void
+posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)) {
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+
+#else
 struct now_struct {
 	unsigned long jiffies;
 };
@@ -27,4 +60,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif				// CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.54-bk1-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -289,6 +289,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
include/linux/thread_info.h +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.54-bk1-i386/include/linux/thread_info.h linux/include/linux/thread_info.h
@@ -12,7 +12,7 @@
  */
 struct restart_block {
 	long (*fn)(struct restart_block *);
-	unsigned long arg0, arg1, arg2;
+	unsigned long arg0, arg1, arg2, arg3;
 };
 
 extern long do_no_restart_syscall(struct restart_block *parm);
kernel/posix-timers.c +115 -17

292 lines not on this page · raw message

Binary files linux-2.5.54-bk1-i386/lib/gen_crc32table and linux/lib/gen_crc32table differ Binary files linux-2.5.54-bk1-i386/scripts/kallsyms and linux/scripts/kallsyms differ Binary files linux-2.5.54-bk1-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.54-bk1-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.54-bk1-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ

#35 lore raw

PATCH 3/3 High-res-timers part 3 (posix to hrposix) take 24

In reply to george anzinger

And this finishs the high res timers code.

Now for 2.5.54-bk6

Changes since last time:
-----------

I had to add arg3 to the restart_block to handle the two word restart time...

This patch adds the two POSIX clocks CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR to the posix clocks & timers package. A small change is made in sched.h and the rest of the patch is against .../kernel/posix_timers.c and .../include/linux/posix_timers.h

This patch takes advantage of the timer storm protection features of the POSIX clock and timers patch.

This patch fixes the high resolution timer resolution at 1 micro second. Should this number be a CONFIG option?

I think it would be a "good thing" to move the NTP stuff to the jiffies clock. This would allow the wall clock/ jiffies clock difference to be a "fixed value" so that code that needed this would not have to read two clocks. Setting the wall clock would then just be an adjustment to this "fixed value". It would also eliminate the problem of asking for a wall clock offset and getting a jiffies clock offset. This issue is what causes the current 2.5.46 system to fail the simple:

time sleep 60

test (any value less than 60 seconds violates the standard in that it implies a timer expired early).

These patches as well as the POSIX clocks & timers patch are available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:

 core      The core kernel (i.e. platform independent)
 i386      The high-res changes for the i386 (x86) platform
*hrposix   The changes to the POSIX clocks & timers patch to

use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
include/linux/posix-timers.h +34 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.54-bk6-i386/include/linux/posix-timers.h linux/include/linux/posix-timers.h
@@ -15,6 +15,39 @@
 	void (*timer_get) (struct k_itimer * timr,
 			   struct itimerspec * cur_setting);
 };
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct now_struct {
+	unsigned long jiffies;
+	long sub_jiffie;
+};
+static inline void
+posix_get_now(struct now_struct *now)
+{
+	(now)->jiffies = jiffies;
+	(now)->sub_jiffie = quick_update_jiffies_sub((now)->jiffies);
+	while (unlikely(((now)->sub_jiffie - cycles_per_jiffies) > 0)) {
+		(now)->sub_jiffie = (now)->sub_jiffie - cycles_per_jiffies;
+		(now)->jiffies++;
+	}
+}
+
+#define posix_time_before(timer, now) \
+         ( {long diff = (long)(timer)->expires - (long)(now)->jiffies;  \
+           (diff < 0) ||                                      \
+	   ((diff == 0) && ((timer)->sub_expires < (now)->sub_jiffie)); })
+
+#define posix_bump_timer(timr) do { \
+          (timr)->it_timer.expires += (timr)->it_incr; \
+          (timr)->it_timer.sub_expires += (timr)->it_sub_incr; \
+          if (((timr)->it_timer.sub_expires - cycles_per_jiffies) >= 0){ \
+		  (timr)->it_timer.sub_expires -= cycles_per_jiffies; \
+		  (timr)->it_timer.expires++; \
+	  }                                 \
+          (timr)->it_overrun++;               \
+        }while (0)
+
+#else
 struct now_struct {
 	unsigned long jiffies;
 };
@@ -27,4 +60,5 @@
                         (timr)->it_timer.expires += (timr)->it_incr; \
                         (timr)->it_overrun++;               \
                        }while (0)
+#endif				// CONFIG_HIGH_RES_TIMERS
 #endif
include/linux/sched.h +3 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.54-bk6-i386/include/linux/sched.h linux/include/linux/sched.h
@@ -289,6 +289,9 @@
 	int it_sigev_signo;		 /* signo word of sigevent struct */
 	sigval_t it_sigev_value;	 /* value word of sigevent struct */
 	unsigned long it_incr;		/* interval specified in jiffies */
+#ifdef CONFIG_HIGH_RES_TIMERS
+        int it_sub_incr;                /* sub jiffie part of interval */
+#endif
 	struct task_struct *it_process;	/* process to send signal to */
 	struct timer_list it_timer;
 };
include/linux/thread_info.h +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.54-bk6-i386/include/linux/thread_info.h linux/include/linux/thread_info.h
@@ -12,7 +12,7 @@
  */
 struct restart_block {
 	long (*fn)(struct restart_block *);
-	unsigned long arg0, arg1, arg2;
+	unsigned long arg0, arg1, arg2, arg3;
 };
 
 extern long do_no_restart_syscall(struct restart_block *parm);
kernel/posix-timers.c +115 -17

292 lines not on this page · raw message

Binary files linux-2.5.54-bk6-i386/lib/gen_crc32table and linux/lib/gen_crc32table differ Binary files linux-2.5.54-bk6-i386/scripts/kallsyms and linux/scripts/kallsyms differ Binary files linux-2.5.54-bk6-i386/scripts/lxdialog/lxdialog and linux/scripts/lxdialog/lxdialog differ Binary files linux-2.5.54-bk6-i386/usr/gen_init_cpio and linux/usr/gen_init_cpio differ Binary files linux-2.5.54-bk6-i386/usr/initramfs_data.cpio.gz and linux/usr/initramfs_data.cpio.gz differ