diff -ruN linux-2.2.14/Makefile linux-2.2.14-timer/Makefile
--- linux-2.2.14/Makefile	Wed Mar  8 02:34:33 2000
+++ linux-2.2.14-timer/Makefile	Mon Jul 24 19:53:54 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 14
-EXTRAVERSION = -5.0
+EXTRAVERSION = -5.0t
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -ruN linux-2.2.14/arch/i386/kernel/entry.S linux-2.2.14-timer/arch/i386/kernel/entry.S
--- linux-2.2.14/arch/i386/kernel/entry.S	Fri Apr 30 17:13:37 1999
+++ linux-2.2.14-timer/arch/i386/kernel/entry.S	Wed Apr 12 19:27:57 2000
@@ -562,6 +562,18 @@
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
+	.long SYMBOL_NAME(sys_ni_syscall)		/* ugetrlimit */
+	.long SYMBOL_NAME(sys_ni_syscall)		/* mmap2 */
+	.long SYMBOL_NAME(sys_ni_syscall)		/* truncate64 */
+	.long SYMBOL_NAME(sys_ni_syscall)		/* ftruncate64 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 195 */ /* stat64 */
+	.long SYMBOL_NAME(sys_ni_syscall)		/* lstat64 */
+	.long SYMBOL_NAME(sys_ni_syscall)		/* fstat64 */
+	.long SYMBOL_NAME(sys_timer_create)
+	.long SYMBOL_NAME(sys_timer_settime)
+	.long SYMBOL_NAME(sys_timer_gettime)	/* 200 */
+	.long SYMBOL_NAME(sys_timer_getoverrun)
+	.long SYMBOL_NAME(sys_timer_delete)
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
@@ -569,6 +581,6 @@
 	 * entries. Don't panic if you notice that this hasn't
 	 * been shrunk every time we add a new system call.
 	 */
-	.rept NR_syscalls-190
+	.rept NR_syscalls-202
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -ruN linux-2.2.14/include/asm-i386/siginfo.h linux-2.2.14-timer/include/asm-i386/siginfo.h
--- linux-2.2.14/include/asm-i386/siginfo.h	Wed Mar  8 02:25:48 2000
+++ linux-2.2.14-timer/include/asm-i386/siginfo.h	Wed Apr 12 19:38:52 2000
@@ -31,13 +31,14 @@
 		struct {
 			unsigned int _timer1;
 			unsigned int _timer2;
+			sigval_t _sigval2;	/* FIXME: must map to _sigval below because it is the same */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
+			sigval_t _sigval;	/* FIXME: move out of union together with _sigval2 */
 		} _rt;
 
 		/* SIGCHLD */
@@ -67,6 +68,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_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
@@ -89,8 +92,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	(((siptr)->si_code <= 0) && ((siptr)->si_code != SI_TIMER))
+#define SI_FROMKERNEL(siptr)	(((siptr)->si_code > 0) || ((siptr)->si_code == SI_TIMER))
 
 /*
  * SIGILL si_codes
diff -ruN linux-2.2.14/include/asm-i386/unistd.h linux-2.2.14-timer/include/asm-i386/unistd.h
--- linux-2.2.14/include/asm-i386/unistd.h	Wed Mar  8 02:24:43 2000
+++ linux-2.2.14-timer/include/asm-i386/unistd.h	Wed Apr 12 19:22:50 2000
@@ -202,6 +202,11 @@
 #define __NR_stat64		195
 #define __NR_lstat64		196
 #define __NR_fstat64		197
+#define __NR_timer_create	198
+#define __NR_timer_settime	199
+#define __NR_timer_gettime	200
+#define __NR_timer_getoverrun	201
+#define __NR_timer_delete	202
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -ruN linux-2.2.14/include/linux/autoconf.h linux-2.2.14-timer/include/linux/autoconf.h
--- linux-2.2.14/include/linux/autoconf.h	Wed Mar  8 02:42:29 2000
+++ linux-2.2.14-timer/include/linux/autoconf.h	Thu Jan  1 01:00:00 1970
@@ -1,50 +0,0 @@
-/*
- * Try to be a little smarter about which kernel are we currently running
- */
-
-#ifndef __rh_kernel_autoconf_h__
-#define __rh_kernel_autoconf_h__
-
-/*
- * First, get the version string for the running kernel from
- * /boot/kernel.h - initscripts should create it for us
- */
-
-#include "/boot/kernel.h"
-
-/*
- * Define some nasty macros o we can construct the file names
- * we want to include
- */
-
-#if defined(__rh_autoconf_included_file__)
-#undef __rh_autoconf_included_file__
-#endif /* __rh_autoconf_included_file__ */
-
-#if defined(__BOOT_KERNEL_UP) && (__BOOT_KERNEL_UP == 1)
-#include <linux/autoconf-up.h>
-#define __rh_autoconf_included_file__ 1
-#endif /* __BOOT_KERNEL_UP */
-
-#if defined(__BOOT_KERNEL_SMP) && (__BOOT_KERNEL_SMP == 1)
-#include <linux/autoconf-smp.h>
-#define __rh_autoconf_included_file__ 1
-#endif /* __BOOT_KERNEL_SMP */
-
-#if defined(__BOOT_KERNEL_BOOT) && (__BOOT_KERNEL_BOOT == 1)
-#include <linux/autoconf-BOOT.h>
-#define __rh_autoconf_included_file__ 1
-#endif /* __BOOT_KERNEL_BOOT */
-
-#if defined(__BOOT_KERNEL_BOOTSMP) && (__BOOT_KERNEL_BOOTSMP == 1)
-#include <linux/autoconf-BOOTsmp.h>
-#define __rh_autoconf_included_file__ 1
-#endif /* __BOOT_KERNEL_BOOTSMP */
-
-#if !defined(__rh_autoconf_included_file__)
-#include <linux/autoconf-up.h>
-#else
-#undef __rh_autoconf_included_file__
-#endif /* __rh_autoconf_included_file__ */
-
-#endif /* __rh_kernel_autoconf_h__ */
diff -ruN linux-2.2.14/include/linux/limits.h linux-2.2.14-timer/include/linux/limits.h
--- linux-2.2.14/include/linux/limits.h	Tue Dec  2 22:44:40 1997
+++ linux-2.2.14-timer/include/linux/limits.h	Wed Apr 12 19:21:56 2000
@@ -14,6 +14,9 @@
 #define PATH_MAX        4095	/* # chars in a path name */
 #define PIPE_BUF        4096	/* # bytes in atomic write to a pipe */
 
+#define TIMER_MAX         32    /* # POSIX.1b timers a process may have */
+#define DELAYTIMER_MAX INT_MAX	/* # timer expiration overruns a POSIX.1b timer may have */
+
 #define RTSIG_MAX	  32
 
 #endif
diff -ruN linux-2.2.14/include/linux/modversions.h linux-2.2.14-timer/include/linux/modversions.h
--- linux-2.2.14/include/linux/modversions.h	Wed Mar  8 02:42:29 2000
+++ linux-2.2.14-timer/include/linux/modversions.h	Thu Jan  1 01:00:00 1970
@@ -1,50 +0,0 @@
-/*
- * Try to be a little smarter about which kernel are we currently running
- */
-
-#ifndef __rh_kernel_modversions_h__
-#define __rh_kernel_modversions_h__
-
-/*
- * First, get the version string for the running kernel from
- * /boot/kernel.h - initscripts should create it for us
- */
-
-#include "/boot/kernel.h"
-
-/*
- * Define some nasty macros o we can construct the file names
- * we want to include
- */
-
-#if defined(__rh_modversion_included_file__)
-#undef __rh_modversion_included_file__
-#endif /* __rh_modversion_included_file__ */
-
-#if defined(__BOOT_KERNEL_UP) && (__BOOT_KERNEL_UP == 1)
-#include <linux/modversions-up.h>
-#define __rh_modversion_included_file__ 1
-#endif /* __BOOT_KERNEL_UP */
-
-#if defined(__BOOT_KERNEL_SMP) && (__BOOT_KERNEL_SMP == 1)
-#include <linux/modversions-smp.h>
-#define __rh_modversion_included_file__ 1
-#endif /* __BOOT_KERNEL_SMP */
-
-#if defined(__BOOT_KERNEL_BOOT) && (__BOOT_KERNEL_BOOT == 1)
-#include <linux/modversions-BOOT.h>
-#define __rh_modversion_included_file__ 1
-#endif /* __BOOT_KERNEL_BOOT */
-
-#if defined(__BOOT_KERNEL_BOOTSMP) && (__BOOT_KERNEL_BOOTSMP == 1)
-#include <linux/modversions-BOOTsmp.h>
-#define __rh_modversion_included_file__ 1
-#endif /* __BOOT_KERNEL_BOOTSMP */
-
-#if !defined(__rh_modversion_included_file__)
-#include <linux/modversions-up.h>
-#else
-#undef __rh_modversion_included_file__
-#endif /* __rh_modversion_included_file__ */
-
-#endif /* __rh_kernel_autoconf_h__ */
diff -ruN linux-2.2.14/include/linux/sched.h linux-2.2.14-timer/include/linux/sched.h
--- linux-2.2.14/include/linux/sched.h	Wed Mar  8 02:35:29 2000
+++ linux-2.2.14-timer/include/linux/sched.h	Mon Jul 24 19:54:21 2000
@@ -34,6 +34,7 @@
 #define CLONE_PID	0x00001000	/* set if pid shared */
 #define CLONE_PTRACE	0x00002000	/* set if we want to let tracing continue on the child too */
 #define CLONE_VFORK	0x00004000	/* set if the parent wants the child to wake it up on mm_release */
+#define CLONE_ITIMERS   0x00010000      /* set if POSIX.1b itimers are shared */
 
 /*
  * These are the constant used to fake the fixed-point load-average
@@ -227,6 +228,26 @@
  */
 struct user_struct;
 
+/* POSIX.1b interval timer structure. */
+struct k_itimer {
+	spinlock_t it_lock;
+	clockid_t it_clock;		/* which timer type */
+	timer_t it_id;			/* timer id */
+	int it_overrun;			/* number of signals overrun */
+	struct sigevent it_signal;	/* signal to be delivered */
+	struct timespec it_interval;	/* interval (rounded to jiffies) */
+	int it_incr;			/* interval specified in jiffies */
+	struct task_struct *it_process;	/* process to send signal to */
+	struct timer_list it_timer;
+};
+
+/* Structure to maintain the dynamically created POSIX.1b interval timers. */
+struct itimer_struct {
+	atomic_t count;
+	spinlock_t its_lock;
+	struct k_itimer *itimer[TIMER_MAX];	
+};
+
 struct task_struct {
 /* these are hardcoded - don't touch */
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
@@ -285,6 +306,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 itimer_struct *posix_timers; /* POSIX.1b Interval Timers */
 	struct tms times;
 	unsigned long start_time;
 	long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
@@ -375,6 +397,7 @@
 /* chld wait */	NULL, NULL, \
 /* timeout */	SCHED_OTHER,0,0,0,0,0,0,0, \
 /* timer */	{ NULL, NULL, 0, 0, it_real_fn }, \
+/* POSIX.1b timer */ NULL, \
 /* utime */	{0,0,0,0},0, \
 /* per CPU times */ {0, }, {0, }, \
 /* flt */	0,0,0,0,0,0, \
@@ -682,6 +705,7 @@
 extern void exit_fs(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
+extern void exit_itimers(struct task_struct *);
 
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
diff -ruN linux-2.2.14/include/linux/time.h linux-2.2.14-timer/include/linux/time.h
--- linux-2.2.14/include/linux/time.h	Wed Mar  8 02:25:48 2000
+++ linux-2.2.14-timer/include/linux/time.h	Wed Apr 12 19:21:56 2000
@@ -26,6 +26,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)
 {
@@ -34,15 +47,15 @@
 
 	if (sec >= (MAX_JIFFY_OFFSET / HZ))
 		return MAX_JIFFY_OFFSET;
-	nsec += 1000000000L / HZ - 1;
-	nsec /= 1000000000L / HZ;
+	nsec += NSEC_PER_SEC / HZ - 1;
+	nsec /= NSEC_PER_SEC / HZ;
 	return HZ * sec + nsec;
 }
 
 static __inline__ void
 jiffies_to_timespec(unsigned long jiffies, struct timespec *value)
 {
-	value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ);
+	value->tv_nsec = (jiffies % HZ) * (NSEC_PER_SEC / HZ);
 	value->tv_sec = jiffies / HZ;
 }
  
@@ -88,5 +101,24 @@
 	struct	timeval it_interval;	/* timer interval */
 	struct	timeval it_value;	/* current value */
 };
+
+
+/* 
+ * Data types for POSIX.1b interval timers.
+ */
+typedef int clockid_t;
+typedef int timer_t;
+
+/*
+ * The IDs of the various system clocks (for POSIX.1b interval timers).
+ */
+#define CLOCK_REALTIME 0
+
+/*
+ * The various flags for setting POSIX.1b interval timers.
+ */
+
+#define TIMER_ABSTIME 0x01
+
 
 #endif
diff -ruN linux-2.2.14/include/linux/version.h linux-2.2.14-timer/include/linux/version.h
--- linux-2.2.14/include/linux/version.h	Wed Mar  8 02:42:29 2000
+++ linux-2.2.14-timer/include/linux/version.h	Thu Jan  1 01:00:00 1970
@@ -1,50 +0,0 @@
-/*
- * Try to be a little smarter about which kernel are we currently running
- */
-
-#ifndef __rh_kernel_version_h__
-#define __rh_kernel_version_h__
-
-/*
- * First, get the version string for the running kernel from
- * /boot/kernel.h - initscripts should create it for us
- */
-
-#include "/boot/kernel.h"
-
-/*
- * Define some nasty macros o we can construct the file names
- * we want to include
- */
-
-#if defined(__rh_version_included_file__)
-#undef __rh_version_included_file__
-#endif /* __rh_version_included_file__ */
-
-#if defined(__BOOT_KERNEL_UP) && (__BOOT_KERNEL_UP == 1)
-#include <linux/version-up.h>
-#define __rh_version_included_file__ 1
-#endif /* __BOOT_KERNEL_UP */
-
-#if defined(__BOOT_KERNEL_SMP) && (__BOOT_KERNEL_SMP == 1)
-#include <linux/version-smp.h>
-#define __rh_version_included_file__ 1
-#endif /* __BOOT_KERNEL_SMP */
-
-#if defined(__BOOT_KERNEL_BOOT) && (__BOOT_KERNEL_BOOT == 1)
-#include <linux/version-BOOT.h>
-#define __rh_version_included_file__ 1
-#endif /* __BOOT_KERNEL_BOOT */
-
-#if defined(__BOOT_KERNEL_BOOTSMP) && (__BOOT_KERNEL_BOOTSMP == 1)
-#include <linux/version-BOOTsmp.h>
-#define __rh_version_included_file__ 1
-#endif /* __BOOT_KERNEL_BOOTSMP */
-
-#if !defined(__rh_version_included_file__)
-#include <linux/version-up.h>
-#else
-#undef __rh_version_included_file__
-#endif /* __rh_version_included_file__ */
-
-#endif /* __rh_kernel_version_h__ */
diff -ruN linux-2.2.14/kernel/exit.c linux-2.2.14-timer/kernel/exit.c
--- linux-2.2.14/kernel/exit.c	Tue Jan  4 19:12:25 2000
+++ linux-2.2.14-timer/kernel/exit.c	Wed Apr 12 19:21:56 2000
@@ -272,6 +272,34 @@
 	__exit_mm(tsk);
 }
 
+static inline void __exit_itimers(struct task_struct *tsk)
+{
+	struct itimer_struct *timers = tsk->posix_timers;
+	struct k_itimer *timr;
+	int i;
+
+	if (timers == NULL) return;
+	
+	if (atomic_dec_and_test(&timers->count)) {
+		tsk->posix_timers = NULL;
+		for (i = 0; i < TIMER_MAX; i++) {
+			timr = timers->itimer[i];
+			if (timr) {
+				start_bh_atomic();
+				del_timer(&timr->it_timer);
+				end_bh_atomic();
+				kfree(timr);
+			}
+		}
+		kfree(timers);
+	}
+}
+
+void exit_itimers(struct task_struct *tsk)
+{
+	__exit_itimers(tsk);
+}
+
 /*
  * Send signals to all our closest relatives so that they know
  * to properly mourn us..
@@ -398,6 +426,7 @@
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	__exit_sighand(tsk);
+	__exit_itimers(tsk);
 	exit_thread();
 	tsk->state = TASK_ZOMBIE;
 	tsk->exit_code = code;
diff -ruN linux-2.2.14/kernel/fork.c linux-2.2.14-timer/kernel/fork.c
--- linux-2.2.14/kernel/fork.c	Wed Oct 27 02:53:42 1999
+++ linux-2.2.14-timer/kernel/fork.c	Wed Apr 12 19:21:56 2000
@@ -563,6 +563,23 @@
 	p->flags = new_flags;
 }
 
+
+static inline int copy_itimers(unsigned long clone_flags, struct task_struct * tsk)
+{
+	if (clone_flags & CLONE_ITIMERS) {
+		atomic_inc(&tsk->posix_timers->count);
+		return 0;
+	}
+
+	tsk->posix_timers = kmalloc(sizeof(*tsk->posix_timers), GFP_KERNEL);
+	if (tsk->posix_timers == NULL) return -1;
+	spin_lock_init(&tsk->posix_timers->its_lock);
+	atomic_set(&tsk->posix_timers->count, 1);
+	memset(tsk->posix_timers->itimer, 0, sizeof(tsk->posix_timers->itimer));
+	return 0;
+}
+
+
 /*
  *  Ok, this is the main fork-routine. It copies the system process
  * information (task[nr]) and sets up the necessary registers. It
@@ -673,6 +690,8 @@
 		goto bad_fork_cleanup_files;
 	if (copy_sighand(clone_flags, p))
 		goto bad_fork_cleanup_fs;
+	if (copy_itimers(clone_flags, p))
+		goto bad_fork_cleanup_itimers;
 	if (copy_mm(nr, clone_flags, p))
 		goto bad_fork_cleanup_sighand;
 	retval = copy_thread(nr, clone_flags, usp, p, regs);
@@ -732,6 +751,8 @@
 	p->mm = NULL;
 bad_fork_cleanup_sighand:
 	exit_sighand(p);
+bad_fork_cleanup_itimers:
+	exit_itimers(p);
 bad_fork_cleanup_fs:
 	exit_fs(p); /* blocking */
 bad_fork_cleanup_files:
diff -ruN linux-2.2.14/kernel/itimer.c linux-2.2.14-timer/kernel/itimer.c
--- linux-2.2.14/kernel/itimer.c	Tue Nov 24 22:51:44 1998
+++ linux-2.2.14-timer/kernel/itimer.c	Wed Apr 12 19:21:56 2000
@@ -9,14 +9,16 @@
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/time.h>
 
 #include <asm/uaccess.h>
 
 /*
- * change timeval to jiffies, trying to avoid the 
+ * change timeval to jiffies, trying to avoid the
  * most obvious overflows..
  *
- * The tv_*sec values are signed, but nothing seems to 
+ * The tv_*sec values are signed, but nothing seems to
  * indicate whether we really should use them as signed values
  * when doing itimers. POSIX doesn't mention this (but if
  * alarm() uses itimers without checking, we have to use unsigned
@@ -168,6 +170,391 @@
 		return error;
 
 	if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
-		return -EFAULT; 
+		return -EFAULT;
+	return 0;
+}
+
+/* PRECONDITION:
+ * timr->it_lock must be locked
+ */
+static void timer_notify_task(struct k_itimer *timr)
+{
+	struct siginfo info;
+	int ret;
+
+	if (timr->it_signal.sigev_notify == SIGEV_SIGNAL) {
+
+		memset(&info, 0, sizeof(info));
+
+		/* Send signal to the process that owns this timer. */
+		info.si_signo = timr->it_signal.sigev_signo;
+		info.si_errno = 0;
+		info.si_code = SI_TIMER;
+		/* TODO: if someone has better ideas what to put in 
+		 * the next two fields...
+		 * si_timer1 is currently used in signal.c to check
+		 * whether a signal from this timer is already in the signal
+		 * queue.
+		 */
+		info.si_timer1 = timr->it_id;
+		info.si_timer2 = 0;
+		info.si_value = timr->it_signal.sigev_value;
+		ret = send_sig_info(info.si_signo, &info, timr->it_process);
+		switch (ret) {
+		case 0:		/* all's well */
+			timr->it_overrun = 0;
+			break;
+		case 1:	/* signal from this timer was already in the queue */
+			timr->it_overrun++;
+			break;
+		default:
+			printk(KERN_WARNING "sending signal failed: %d\n", ret);
+			break;
+		}
+	}
+}
+
+/* This function gets called when a POSIX.1b interval timer expires. */
+static void posix_timer_fn(unsigned long __data)
+{  
+	struct k_itimer *timr = (struct k_itimer *)__data;
+	unsigned long interval;
+
+	spin_lock(&timr->it_lock);
+	
+	timer_notify_task(timr);
+
+	/* Set up the timer for the next interval (if there is one) */
+	if ((interval = timr->it_incr) == 0) goto out;
+		
+	if (interval > (unsigned long) LONG_MAX)
+		interval = LONG_MAX;
+	timr->it_timer.expires = jiffies + interval;
+	add_timer(&timr->it_timer);
+out:
+	spin_unlock(&timr->it_lock);
+}
+
+/* Find the first available slot for the new timer. */
+static int timer_find_slot(struct itimer_struct *timers)
+{
+	int i;
+
+	for (i = 0; i < TIMER_MAX; i++) {
+		if (timers->itimer[i] == NULL) return i;
+	}
+	return -1;
+}
+
+static int good_sigevent(const struct sigevent *sigev)
+{
+	switch (sigev->sigev_notify) {
+	case SIGEV_NONE:
+		break;
+	case SIGEV_SIGNAL:
+		if ((sigev->sigev_signo <= 0) ||
+		    (sigev->sigev_signo > SIGRTMAX))
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+/* Create a POSIX.1b interval timer. */
+
+asmlinkage int sys_timer_create(clockid_t which_clock,
+				struct sigevent *timer_event_spec,
+				timer_t *created_timer_id)
+{
+	int error = 0;
+	struct k_itimer *new_timer = NULL;
+	struct itimer_struct *timers = current->posix_timers;
+	int new_timer_id;
+ 
+	/* Right now, we only support CLOCK_REALTIME for timers. */
+	if (which_clock != CLOCK_REALTIME) return -EINVAL;
+
+	new_timer = (struct k_itimer *)kmalloc(sizeof(*new_timer), GFP_KERNEL);
+	if (new_timer == NULL) return -EAGAIN;
+
+	spin_lock_init(&new_timer->it_lock);
+	new_timer->it_clock = which_clock;
+	new_timer->it_incr = 0;
+	new_timer->it_overrun = 0;
+
+	if (timer_event_spec) {
+		if (copy_from_user(&new_timer->it_signal, timer_event_spec,
+				   sizeof(new_timer->it_signal))) {
+			error = -EFAULT;
+			goto out;
+		}
+		if (!good_sigevent(&new_timer->it_signal)) {
+			error = -EINVAL;
+			goto out;
+		}
+	}
+	else {
+		new_timer->it_signal.sigev_notify = SIGEV_SIGNAL;
+		new_timer->it_signal.sigev_signo = SIGALRM;
+	}
+
+	new_timer->it_interval.tv_sec = 0;
+	new_timer->it_interval.tv_nsec = 0;
+	new_timer->it_process = current;
+	new_timer->it_timer.next = NULL;
+	new_timer->it_timer.prev = NULL;
+	new_timer->it_timer.expires = 0;
+	new_timer->it_timer.data = (unsigned long)new_timer;
+	new_timer->it_timer.function = posix_timer_fn;
+
+	spin_lock(&timers->its_lock);
+
+	new_timer_id = timer_find_slot(timers);
+	if (new_timer_id == -1) {
+		error = -EAGAIN;
+		goto out;
+	}
+	new_timer->it_id = new_timer_id;
+	timers->itimer[new_timer_id] = new_timer;
+	if (timer_event_spec == NULL) {
+		new_timer->it_signal.sigev_value.sival_int = new_timer_id;
+	}
+
+	if (copy_to_user(created_timer_id, &new_timer_id, sizeof(new_timer_id))) {
+		error = -EFAULT;
+		timers->itimer[new_timer_id] = NULL;
+	}
+
+	spin_unlock(&timers->its_lock);
+out:
+	if (error) {
+		kfree(new_timer);
+	}
+	return error;
+}
+
+
+/* good_timespec
+ *
+ * This function checks the elements of a timespec structure.
+ *
+ * Arguments:
+ * ts       : Pointer to the timespec structure to check
+ *
+ * Return value:
+ * If a NULL pointer was passed in, or the tv_nsec field was less than 0 or
+ * greater than NSEC_PER_SEC, or the tv_sec field was less than 0, this
+ * function returns 0. Otherwise it returns 1.
+ */
+
+int good_timespec(const struct timespec *ts)
+{
+	if (ts == NULL) return 0;
+	if (ts->tv_sec < 0) return 0;
+	if ((ts->tv_nsec < 0) || (ts->tv_nsec >= NSEC_PER_SEC)) return 0;
+	return 1;
+}
+
+inline struct k_itimer* lock_timer(struct task_struct *tsk, timer_t timer_id)
+{
+	struct k_itimer *timr;
+
+	if ((timer_id < 0) || (timer_id >= TIMER_MAX)) return NULL;
+	spin_lock(&tsk->posix_timers->its_lock);
+	timr = tsk->posix_timers->itimer[timer_id];
+	if (timr) spin_lock(&timr->it_lock);
+	spin_unlock(&tsk->posix_timers->its_lock);
+	return timr;
+}
+
+static inline void unlock_timer(struct k_itimer *timr)
+{
+	spin_unlock(&timr->it_lock);
+}
+
+/* Get the time remaining on a POSIX.1b interval timer. */
+void do_timer_gettime(struct k_itimer *timr,
+		      struct itimerspec *cur_setting)
+{
+	unsigned long expires = timr->it_timer.expires;
+
+	if (expires) expires -= jiffies;
+	
+	jiffies_to_timespec(expires, &cur_setting->it_value);
+	cur_setting->it_interval = timr->it_interval;
+}
+
+/* Get the time remaining on a POSIX.1b interval timer. */
+asmlinkage int sys_timer_gettime(timer_t timer_id, struct itimerspec *setting)
+{
+	struct k_itimer *timr;
+	struct itimerspec cur_setting;
+
+	timr = lock_timer(current, timer_id);
+	if (!timr) return -EINVAL;
+
+	do_timer_gettime(timr, &cur_setting);
+
+	unlock_timer(timr);
+	
+	copy_to_user_ret(setting, &cur_setting, sizeof(cur_setting), -EFAULT);
+
+	return 0;
+}
+
+/* Get the number of overruns of a POSIX.1b interval timer */
+asmlinkage int sys_timer_getoverrun(timer_t timer_id)
+{
+	struct k_itimer *timr;
+	int overrun;
+
+	timr = lock_timer(current, timer_id);
+	if (!timr) return -EINVAL;
+
+	overrun = timr->it_overrun;
+	
+	unlock_timer(timr);
+
+	return overrun;
+}
+
+static void timer_value_abs_to_rel(struct timespec *val)
+{
+	struct timeval tv;
+	struct timespec ts;
+
+	do_gettimeofday(&tv);
+	ts.tv_sec = tv.tv_sec;
+	ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+
+	/* check whether the time lies in the past */
+	if ((val->tv_sec < ts.tv_sec) || 
+	    ((val->tv_sec == ts.tv_sec) &&
+	     (val->tv_nsec <= ts.tv_nsec))) {
+		/* expire immediately */
+		val->tv_sec = 0;
+		val->tv_nsec = 0;
+	}
+	else {
+		val->tv_sec -= ts.tv_sec;
+		val->tv_nsec -= ts.tv_nsec;
+		if (val->tv_nsec < 0) {
+			val->tv_nsec += NSEC_PER_SEC;
+			val->tv_sec--;
+		}
+	}
+}
+
+/* Set a POSIX.1b interval timer. */
+void do_timer_settime(struct k_itimer *timr, int flags,
+		      struct itimerspec *new_setting,
+		      struct itimerspec *old_setting)
+{
+	/* disable the timer */
+	start_bh_atomic();
+	del_timer(&timr->it_timer);
+	end_bh_atomic();
+
+	if (old_setting) {
+		do_timer_gettime(timr, old_setting);
+	}
+
+	/* switch off the timer when it_value is zero */
+	if ((new_setting->it_value.tv_sec == 0) &&
+	    (new_setting->it_value.tv_nsec == 0)) {
+		timr->it_incr = 0;
+		timr->it_timer.expires = 0;
+		timr->it_interval.tv_sec = 0;
+		timr->it_interval.tv_nsec = 0;
+		return;
+	}
+
+	timr->it_incr = timespec_to_jiffies(&new_setting->it_interval);
+	/* save the interval rounded to jiffies */
+	jiffies_to_timespec(timr->it_incr, &timr->it_interval);
+
+	if (flags & TIMER_ABSTIME) {
+		timer_value_abs_to_rel(&new_setting->it_value);
+	}
+
+	timr->it_timer.expires = timespec_to_jiffies(&new_setting->it_value) + jiffies;
+
+	/*
+	 * For some reason the timer does not fire immediately if expires is
+	 * equal to jiffies, so the timer callback function is called directly.
+	 */
+	if (timr->it_timer.expires == jiffies) {
+		posix_timer_fn((unsigned long)timr);
+	}
+	else {
+		add_timer(&timr->it_timer);
+	}
+}
+
+
+/* Set a POSIX.1b interval timer */
+asmlinkage int sys_timer_settime(timer_t timer_id, int flags,
+				 const struct itimerspec *new_setting,
+				 struct itimerspec *old_setting)
+{
+	struct k_itimer *timr;
+	struct itimerspec new_spec, old_spec;
+	int error = 0;
+
+	timr = lock_timer(current, timer_id);
+	if (!timr) return -EINVAL;
+
+	if (new_setting == NULL) {
+		error = -EINVAL;
+		goto out;
+	}
+
+	if (copy_from_user(&new_spec, new_setting, sizeof(new_spec))) {
+		error = -EFAULT;
+		goto out;
+	}
+
+	if ((!good_timespec(&new_spec.it_interval)) ||
+	    (!good_timespec(&new_spec.it_value))) {
+		error = -EINVAL;
+		goto out;
+	}
+
+	do_timer_settime(timr, flags, &new_spec,
+			 old_setting ? &old_spec : NULL);
+
+	if (old_setting) {
+		if (copy_to_user(old_setting, &old_spec, sizeof(old_spec))) {
+			error = -EFAULT;
+		}
+	}
+
+out:
+	unlock_timer(timr);
+	return error;
+}
+
+
+/* Delete a POSIX.1b interval timer. */
+asmlinkage int sys_timer_delete(timer_t timer_id)
+{
+	struct k_itimer *timr;
+
+	timr = lock_timer(current, timer_id);
+	if (!timr) return -EINVAL;
+
+	start_bh_atomic();
+	del_timer(&timr->it_timer);
+	end_bh_atomic();
+
+	spin_lock(&current->posix_timers->its_lock);
+
+	kfree(timr);
+	current->posix_timers->itimer[timer_id] = NULL;
+
+	spin_unlock(&current->posix_timers->its_lock);
+
 	return 0;
 }
diff -ruN linux-2.2.14/kernel/signal.c linux-2.2.14-timer/kernel/signal.c
--- linux-2.2.14/kernel/signal.c	Wed Mar  8 02:24:44 2000
+++ linux-2.2.14-timer/kernel/signal.c	Wed Apr 12 19:21:56 2000
@@ -329,6 +329,23 @@
 
 		struct signal_queue *q = 0;
 
+		/* In case of a POSIX timer generated signal you must check 
+		   if a signal from this timer is already in the queue.
+		   If that is is true, the overrun count will be increased in
+		   itimer.c:posix_timer_fn(). */
+
+		if (((unsigned long)info > 1) && (info->si_code == SI_TIMER)) {
+			for (q = t->sigqueue; q; q = q->next) {
+				if ((q->info.si_code == SI_TIMER) &&
+				    (q->info.si_timer1 == info->si_timer1)) {
+					/* this special value (1) is recognized
+					   only by posix_timer_fn() in itimer.c */
+					ret = 1;
+					goto out;
+				}
+			}
+		}
+
 		if (atomic_read(&nr_queued_signals) < max_queued_signals) {
 			q = (struct signal_queue *)
 			    kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
Binary files linux-2.2.14/scripts/mkdep and linux-2.2.14-timer/scripts/mkdep differ
