Skip to contentSkip to conversation

alternate Posix timer patch3

PATCH New Jim Houston 1 participant 1 message Oct 24, 2002

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 alternate Posix timer patch3

Hi Everyone,

This is the third version of my spin on the Posix timers. I started with George Anzinger's patch but I have made major changes.

I have been using George's version of the patch and would be glad to see it included into the 2.5 tree. On the other hand since we don't know what might appeal to Linus it makes sense to give him a choice.

My latest change is a rewrite of nanosleep/clock_nanosleep. The hard problem here is how to restart a nanosleep if it is interrupted by a signal which is not delivered to the program. This is typically debug signals. My change leaves the timer running and arranges to have the system call restarted. The logic is similar to the existing ERESTARTNOHAND mechanism. This interface is close to what I want but the system call doesn't have a clue that its being restarted. I ended up making a small change to do_signal which should not be to painful to add to the other architectures.

It now passes most of the tests that are included in George's timers support package. The few remaining failures are test issues e.g. expecting the remaining time to be set on a nanosleep which completed normally. This field is only meaningful if the sleep is interrupted by a signal. It also passed the LTP nanosleep tests.

I sent out the first version of this patch last friday and had useful coments from Andi Kleen. I have addressed most of his concerns including a race between saving a task_struct pointer, using this pointer to send signals and the process exiting. Andi thanks for reviewing my code.

Here is a summary of my changes:

- A new queue just for Posix timers and code to
handle expiring timers. This supports high resolution without having to change the existing jiffie based timers. It also works fine with tick based time measurement.

I implemented this priority queue as a sort list with a rbtree to index the list. It is deterministic and fast.

- Change to use the slab allocator. I have removed the
config time limit on number of timers. I plan to add /proc based limits.

- A new id allocator/lookup mechanism based on a
radix tree. It includes a bitmap to summarize the portion of the tree which is in use. Currently the Posix timers patch reuses the id immediately.

- I keep the timers in seconds and nano-seconds.
I'm hoping that the system time keeping will sort itself out and the Posix timers can just be a consumer. Posix timers need two clocks - the time since boot and the wall clock time.

When I catch up on lost sleep I will play with getting this working at high resolution.

This patch works with linux- 2.5.44.

Jim Houston - Concurrent Computer Corp.

arch/i386/kernel/entry.S +9 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/arch/i386/kernel/entry.S linux.mytimers/arch/i386/kernel/entry.S
@@ -737,6 +737,15 @@
 	.long sys_free_hugepages
 	.long sys_exit_group
 	.long sys_lookup_dcookie
+ 	.long sys_timer_create
+ 	.long sys_timer_settime	  /* 255 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime	  /* 260 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
arch/i386/kernel/signal.c +11 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/arch/i386/kernel/signal.c linux.mytimers/arch/i386/kernel/signal.c
@@ -507,6 +507,7 @@
 		/* If so, check system call restarting.. */
 		switch (regs->eax) {
 			case -ERESTARTNOHAND:
+			case -ERESTARTNANOSLP:
 				regs->eax = -EINTR;
 				break;
 
@@ -588,6 +589,16 @@
 		if (regs->eax == -ERESTARTNOHAND ||
 		    regs->eax == -ERESTARTSYS ||
 		    regs->eax == -ERESTARTNOINTR) {
+			regs->eax = regs->orig_eax;
+			regs->eip -= 2;
+		}
+		/*
+		 * If a nanosleep or clock_nanosleep is interrupted
+		 * by a non delivered signal we want to complete 
+		 * the requested delay.
+		 */
+		if (regs->eax == -ERESTARTNANOSLP) {
+			current->nanosleep_restart = RESTART_ACK;
 			regs->eax = regs->orig_eax;
 			regs->eip -= 2;
 		}
fs/exec.c +1 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/fs/exec.c linux.mytimers/fs/exec.c
@@ -756,6 +756,7 @@
 			
 	flush_signal_handlers(current);
 	flush_old_files(current->files);
+	exit_itimers(current, 0);
 
 	return 0;
 
include/asm-generic/siginfo.h +8 -4
diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/asm-generic/siginfo.h linux.mytimers/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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/asm-i386/posix_types.h linux.mytimers/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/unistd.h +9 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/asm-i386/unistd.h linux.mytimers/include/asm-i386/unistd.h
@@ -258,6 +258,15 @@
 #define __NR_free_hugepages	251
 #define __NR_exit_group		252
 #define __NR_lookup_dcookie	253
+#define __NR_timer_create	254
+#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/errno.h +1 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/errno.h linux.mytimers/include/linux/errno.h
@@ -10,6 +10,7 @@
 #define ERESTARTNOINTR	513
 #define ERESTARTNOHAND	514	/* restart if no handler.. */
 #define ENOIOCTLCMD	515	/* No ioctl command */
+#define ERESTARTNANOSLP	516
 
 /* Defined for the NFSv3 protocol */
 #define EBADHANDLE	521	/* Illegal NFS file handle */
include/linux/id2ptr.h +47 -0

47 lines not on this page · raw message

include/linux/init_task.h +6 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/init_task.h linux.mytimers/include/linux/init_task.h
@@ -93,6 +93,12 @@
 	.sig		= &init_signals,				\
 	.pending	= { NULL, &tsk.pending.head, {{0}}},		\
 	.blocked	= {{0}},					\
+	.posix_timers	= LIST_HEAD_INIT(tsk.posix_timers),		\
+	.nanosleep_tmr.it_v.it_interval.tv_sec = 0,			\
+	.nanosleep_tmr.it_v.it_interval.tv_nsec = 0,			\
+	.nanosleep_tmr.it_process = &tsk,				\
+	.nanosleep_tmr.it_type = NANOSLEEP,				\
+	.nanosleep_restart = RESTART_NONE,				\
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
include/linux/posix-timers.h +81 -0

81 lines not on this page · raw message

include/linux/sched.h +5 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/sched.h linux.mytimers/include/linux/sched.h
@@ -29,6 +29,7 @@
 #include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/pid.h>
+#include <linux/posix-timers.h>
 
 struct exec_domain;
 
@@ -333,6 +334,9 @@
 	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 */
+	struct k_itimer nanosleep_tmr;
+	int	nanosleep_restart;
 	unsigned long utime, stime, cutime, cstime;
 	unsigned long start_time;
 	long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
@@ -637,6 +641,7 @@
 
 extern void exit_mm(struct task_struct *);
 extern void exit_files(struct task_struct *);
+extern void exit_itimers(struct task_struct *, int);
 extern void exit_sighand(struct task_struct *);
 extern void __exit_sighand(struct task_struct *);
 
include/linux/sys.h +1 -1
diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/sys.h linux.mytimers/include/linux/sys.h
@@ -4,7 +4,7 @@
 /*
  * system call entry points ... but not all are defined
  */
-#define NR_syscalls 256
+#define NR_syscalls 275
 
 /*
  * These are system calls that will be removed at some time
include/linux/time.h +34 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/time.h linux.mytimers/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,7 @@
 #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);
 #endif
 
 #define FD_SETSIZE		__FD_SETSIZE
@@ -149,5 +163,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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/types.h linux.mytimers/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 -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/Makefile linux.mytimers/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 id2ptr.o
 
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
kernel/exit.c +1 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/exit.c linux.mytimers/kernel/exit.c
@@ -647,6 +647,7 @@
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	exit_namespace(tsk);
+	exit_itimers(tsk, 1);
 	exit_thread();
 
 	if (current->leader)
kernel/fork.c +6 -0
diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/fork.c linux.mytimers/kernel/fork.c
@@ -783,6 +783,12 @@
 		goto bad_fork_cleanup_files;
 	if (copy_sighand(clone_flags, p))
 		goto bad_fork_cleanup_fs;
+	INIT_LIST_HEAD(&p->posix_timers);
+	p->nanosleep_tmr.it_v.it_interval.tv_sec = 0;
+	p->nanosleep_tmr.it_v.it_interval.tv_nsec = 0;
+	p->nanosleep_tmr.it_process = p;
+	p->nanosleep_tmr.it_type = NANOSLEEP;
+	p->nanosleep_restart = RESTART_NONE;
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
 	if (copy_namespace(clone_flags, p))
kernel/id2ptr.c +223 -0

223 lines not on this page · raw message

kernel/posix-timers.c +1111 -0

1,111 lines not on this page · raw message

kernel/signal.c +35 -12

77 lines not on this page · raw message

kernel/timer.c +32 -12

116 lines not on this page · raw message