[LWN Logo]

Date:   Sun, 7 Nov 1999 17:59:12 +0100 (CET)
From:   Robert de Vries <rhdv@rhdv.cistron.nl>
To:     Linus Torvalds <torvalds@transmeta.com>,
Subject: [PATCH] POSIX timers for 2.3.25

Attached you will find my latest patch to add POSIX timers to the linux
kernel.

This has been tested on i386 only. Support for all other platforms is
included but not tested. Please try this and tell me if it works or if it
doesn't.

This patch should not impact processes not using POSIX timers. The pointer
to the array of POSIX timers is left NULL. Nothing is done.
When the first timer is created and when a clone with the TIMER_CLONE flag
is called, the timer overhead is created.

The siginfo structure is slightly changed. It moves si_value out of the
_rt part of the union. si_value is used both by _rt and _timer and must
map to the same field.

As a reaction to the question if this should be in the kernel in the first
place:
IMHO, there is no way to emulate these calls in user space by using the
setitimer() system call.
For the following reasons:
a. setitimer() sends only SIGALRM, POSIX timers can send any signal.
b. setitimer() does not know about overruns, POSIX timers do.
c. setitimer() can be used only once in a given process, you can have
   upto 32 (configurable) POSIX timers at the same time in your process.
d. setitimer() cannot send extra information with its signal, POSIX timers
   can send a si_value when using RT signals.

Any comments?

Test code and some other patches can be found on:
http://www.rhdv.cistron.nl/posix.html

	Robert


diff -ruN linux-2.3.25-vanilla/arch/alpha/kernel/entry.S linux-2.3.25-devt-timer/arch/alpha/kernel/entry.S
--- linux-2.3.25-vanilla/arch/alpha/kernel/entry.S	Sun Sep  5 10:50:19 1999
+++ linux-2.3.25-devt-timer/arch/alpha/kernel/entry.S	Tue Nov  2 23:15:19 1999
@@ -1149,3 +1149,8 @@
 	.quad sys_sendfile			/* 370 */
 	.quad sys_setresgid
 	.quad sys_getresgid
+	.quad sys_timer_create
+	.quad sys_timer_settime
+	.quad sys_timer_gettime			/* 375 */
+	.quad sys_timer_getoverrun
+	.quad sys_timer_delete
diff -ruN linux-2.3.25-vanilla/arch/arm/kernel/calls.S linux-2.3.25-devt-timer/arch/arm/kernel/calls.S
--- linux-2.3.25-vanilla/arch/arm/kernel/calls.S	Sun Sep  5 10:50:20 1999
+++ linux-2.3.25-devt-timer/arch/arm/kernel/calls.S	Tue Nov  2 23:15:19 1999
@@ -200,8 +200,13 @@
 		.long	SYMBOL_NAME(sys_ni_syscall)
 		.long	SYMBOL_NAME(sys_ni_syscall)
 /* 190 */	.long	SYMBOL_NAME(sys_vfork_wrapper)
+		.long	SYMBOL_NAME(sys_timer_create)
+		.long	SYMBOL_NAME(sys_timer_settime)
+		.long	SYMBOL_NAME(sys_timer_gettime)
+		.long	SYMBOL_NAME(sys_timer_getoverrun)
+/* 195 */	.long	SYMBOL_NAME(sys_timer_delete)
 
-		.rept	NR_syscalls-186
+		.rept	NR_syscalls-195
 			.long	SYMBOL_NAME(sys_ni_syscall)
 		.endr
 #endif
diff -ruN linux-2.3.25-vanilla/arch/i386/kernel/entry.S linux-2.3.25-devt-timer/arch/i386/kernel/entry.S
--- linux-2.3.25-vanilla/arch/i386/kernel/entry.S	Tue Nov  2 19:23:57 1999
+++ linux-2.3.25-devt-timer/arch/i386/kernel/entry.S	Tue Nov  2 23:17:18 1999
@@ -592,6 +592,11 @@
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
 	.long SYMBOL_NAME(sys_getrlimit)
+	.long SYMBOL_NAME(sys_timer_create)
+	.long SYMBOL_NAME(sys_timer_settime)
+	.long SYMBOL_NAME(sys_timer_gettime)
+	.long SYMBOL_NAME(sys_timer_getoverrun)	/* 195 */
+	.long SYMBOL_NAME(sys_timer_delete)
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
@@ -599,6 +604,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-191
+	.rept NR_syscalls-196
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -ruN linux-2.3.25-vanilla/arch/m68k/kernel/entry.S linux-2.3.25-devt-timer/arch/m68k/kernel/entry.S
--- linux-2.3.25-vanilla/arch/m68k/kernel/entry.S	Thu Sep  9 20:36:53 1999
+++ linux-2.3.25-devt-timer/arch/m68k/kernel/entry.S	Tue Nov  2 23:15:19 1999
@@ -600,6 +600,11 @@
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
+	.long SYMBOL_NAME(sys_timer_create)
+	.long SYMBOL_NAME(sys_timer_settime)
+	.long SYMBOL_NAME(sys_timer_gettime)
+	.long SYMBOL_NAME(sys_timer_getoverrun)
+	.long SYMBOL_NAME(sys_timer_delete)	/* 195 */
 
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -ruN linux-2.3.25-vanilla/arch/mips/kernel/irix5sys.h linux-2.3.25-devt-timer/arch/mips/kernel/irix5sys.h
--- linux-2.3.25-vanilla/arch/mips/kernel/irix5sys.h	Sat Jun 26 02:40:12 1999
+++ linux-2.3.25-devt-timer/arch/mips/kernel/irix5sys.h	Tue Nov  2 23:15:19 1999
@@ -235,7 +235,7 @@
 SYS(irix_unimp, 0)			/* 1213  XXX timer_delete()	*/
 SYS(irix_unimp, 0)			/* 1214  XXX timer_settime()	*/
 SYS(irix_unimp, 0)			/* 1215  XXX timer_gettime()	*/
-SYS(irix_unimp, 0)			/* 1216  XXX timer_setoverrun()	*/
+SYS(irix_unimp, 0)			/* 1216  XXX timer_getoverrun()	*/
 SYS(sys_sched_rr_get_interval, 2)	/* 1217  sched_rr_get_interval()V*/
 SYS(sys_sched_yield, 0)			/* 1218  sched_yield()	       V*/
 SYS(sys_sched_getscheduler, 1)		/* 1219  sched_getscheduler()  V*/
diff -ruN linux-2.3.25-vanilla/arch/mips/kernel/syscalls.h linux-2.3.25-devt-timer/arch/mips/kernel/syscalls.h
--- linux-2.3.25-vanilla/arch/mips/kernel/syscalls.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/arch/mips/kernel/syscalls.h	Tue Nov  2 23:15:19 1999
@@ -225,3 +225,8 @@
 SYS(sys_sendfile, 3)
 SYS(sys_ni_syscall, 0)
 SYS(sys_ni_syscall, 0)
+SYS(sys_timer_create, 3)			/* 4210 */
+SYS(sys_timer_settime, 4)
+SYS(sys_timer_gettime, 2)
+SYS(sys_timer_getoverrun, 1)
+SYS(sys_timer_delete, 1)
diff -ruN linux-2.3.25-vanilla/arch/ppc/kernel/misc.S linux-2.3.25-devt-timer/arch/ppc/kernel/misc.S
--- linux-2.3.25-vanilla/arch/ppc/kernel/misc.S	Sun Oct 31 19:51:55 1999
+++ linux-2.3.25-devt-timer/arch/ppc/kernel/misc.S	Tue Nov  2 23:15:19 1999
@@ -1039,4 +1039,9 @@
 	.long sys_ni_syscall		/* streams1 */
 	.long sys_ni_syscall		/* streams2 */
 	.long sys_vfork
-	.space (NR_syscalls-183)*4
+	.long sys_timer_create	/* 190 */
+	.long sys_timer_settime
+	.long sys_timer_gettime
+	.long sys_timer_getoverrun
+	.long sys_timer_delete	/* 194 */
+	.space (NR_syscalls-194)*4
diff -ruN linux-2.3.25-vanilla/arch/sparc/kernel/systbls.S linux-2.3.25-devt-timer/arch/sparc/kernel/systbls.S
--- linux-2.3.25-vanilla/arch/sparc/kernel/systbls.S	Sun Sep  5 10:50:28 1999
+++ linux-2.3.25-devt-timer/arch/sparc/kernel/systbls.S	Tue Nov  2 23:15:19 1999
@@ -37,8 +37,8 @@
 /*90*/	.long sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
 /*95*/	.long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*100*/	.long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
-/*105*/	.long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
-/*110*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*105*/	.long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_timer_create, sys_timer_settime
+/*110*/	.long sys_timer_gettime, sys_timer_getoverrun, sys_timer_delete, sys_nis_syscall, sys_nis_syscall
 /*115*/	.long sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
 /*120*/	.long sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
 /*125*/	.long sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
diff -ruN linux-2.3.25-vanilla/arch/sparc64/kernel/sys_sparc32.c linux-2.3.25-devt-timer/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.3.25-vanilla/arch/sparc64/kernel/sys_sparc32.c	Sun Sep  5 10:50:31 1999
+++ linux-2.3.25-devt-timer/arch/sparc64/kernel/sys_sparc32.c	Tue Nov  2 23:15:19 1999
@@ -3849,3 +3849,113 @@
 
 	return ret;
 }
+
+struct itimerspec32 {
+	struct  timespec32 it_interval;
+        struct  timespec32 it_value;
+};
+
+int good_timespec(const struct timespec *ts);
+extern struct k_itimer* lock_timer(struct task_struct *tsk, timer_t timer_id);
+static inline void unlock_timer(struct k_itimer *timr)
+{
+	spin_unlock(&timr->it_lock);
+}
+extern void do_timer_gettime(struct k_itimer *timr, struct itimerspec *cur_setting);
+extern void do_timer_settime(struct k_itimer *timr, int flags, struct itimerspec *new_setting, struct itimerspec *old_setting);
+extern int sys_timer_create(clockid_t which_clock, sigevent_t *timer_event_spec, timer_t *created_timer_id);
+
+asmlinkage int sys32_timer_create(clockid_t which_clock, sigevent_t32 *timer_event_spec, timer_t *created_timer_id);
+{
+	mm_segment_t old_fs;
+	sigevent_t tes;
+	int ret, new_timer_id;
+	
+	if (timer_event_spec) {
+		memset (&tes, 0, sizeof(tes));
+		if (get_user (tes.sigev_value.sival_int, &timer_event_spec->sigev_value.sival_int) ||
+		    __get_user (tes.sigev_signo, &timer_event_spec->sigev_signo) ||
+		    __get_user (tes.sigev_notify, &timer_event_spec->sigev_notify) ||
+		    __get_user (tes._sigev_un._sigev_thread._attribute, &timer_event_spec->_sigev_un._sigev_thread._attribute))
+			return -EFAULT;
+		/* As sigev_value is a union of 32bit int and 64bit void *, put the int twice into the ptr, so that when
+		   actually sending the signal both sival_int and sival_ptr will result in correct operation. */
+		tes.sigev_value.sival_ptr = (void *)((long)tes.sigev_value.sival_int<<32 | tes.sigev_value.sival_int);
+		old_fs = get_fs ();
+		set_fs (KERNEL_DS);
+		ret = sys_timer_create (which_clock, &tes, &new_timer_id);
+		set_fs (old_fs);
+		if (!ret) {
+			if (put_user (new_timer_id, created_timer_id))
+				return -EFAULT;
+		}
+		return ret;
+	} else
+		return sys_timer_create (which_clock, NULL, created_timer_id);
+}
+
+asmlinkage int sys32_timer_gettime(timer_t timer_id, struct itimerspec32 *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);
+	
+	if (put_user (cur_setting.it_interval.tv_sec, &setting->it_interval.tv_sec) ||
+	    __put_user (cur_setting.it_interval.tv_nsec, &setting->it_interval.tv_nsec) ||
+	    __put_user (cur_setting.it_value.tv_sec, &setting->it_value.tv_sec) ||
+	    __put_user (cur_setting.it_value.tv_nsec, &setting->it_value.tv_nsec))
+		return -EFAULT;		    
+
+	return 0;
+}
+
+asmlinkage int sys32_timer_settime(timer_t timer_id, int flags, struct itimerspec32 *new_setting,
+				   struct itimerspec32 *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 (get_user (new_spec.it_interval.tv_sec, &new_setting->it_interval.tv_sec) ||
+	    __get_user (new_spec.it_interval.tv_nsec, &new_setting->it_interval.tv_nsec) ||
+	    __get_user (new_spec.it_value.tv_sec, &new_setting->it_value.tv_sec) ||
+	    __get_user (new_spec.it_value.tv_nsec, &new_setting->it_value.tv_nsec)) {
+		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 (put_user (old_spec.it_interval.tv_sec, &old_setting->it_interval.tv_sec) ||
+		    __put_user (old_spec.it_interval.tv_nsec, &old_setting->it_interval.tv_nsec) ||
+		    __put_user (old_spec.it_value.tv_sec, &old_setting->it_value.tv_sec) ||
+		    __put_user (old_spec.it_value.tv_nsec, &old_setting->it_value.tv_nsec))
+			error = -EFAULT;
+	}
+
+out:
+	unlock_timer(timr);
+	return error;
+}
diff -ruN linux-2.3.25-vanilla/arch/sparc64/kernel/systbls.S linux-2.3.25-devt-timer/arch/sparc64/kernel/systbls.S
--- linux-2.3.25-vanilla/arch/sparc64/kernel/systbls.S	Tue Aug  3 07:07:16 1999
+++ linux-2.3.25-devt-timer/arch/sparc64/kernel/systbls.S	Tue Nov  2 23:15:19 1999
@@ -38,8 +38,8 @@
 /*90*/	.word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
 	.word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
-	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
-/*110*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys32_timer_create, sys32_timer_settime
+/*110*/ .word sys32_timer_gettime, sys_timer_getoverrun, sys_timer_delete, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
 /*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
 	.word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate
@@ -68,7 +68,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
 /*250*/	.word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-	.word sys_aplib
+/*255*/	.word sys_aplib
 
 	/* Now the 64-bit native Linux syscall table. */
 
@@ -97,8 +97,8 @@
 /*90*/	.word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
 	.word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
 /*100*/	.word sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
-	.word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
-/*110*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
+	.word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_timer_create, sys_timer_settime
+/*110*/ .word sys_timer_gettime, sys_timer_getoverrun, sys_timer_delete, sys_recvmsg, sys_sendmsg
 	.word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd
 /*120*/	.word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
 	.word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
@@ -127,7 +127,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.word sys_aplib
+/*255*/	.word sys_aplib
 
 	/* Now the 32-bit SunOS syscall table. */
 
diff -ruN linux-2.3.25-vanilla/include/asm-alpha/posix_types.h linux-2.3.25-devt-timer/include/asm-alpha/posix_types.h
--- linux-2.3.25-vanilla/include/asm-alpha/posix_types.h	Fri Aug 21 15:33:36 1998
+++ linux-2.3.25-devt-timer/include/asm-alpha/posix_types.h	Thu Nov  4 22:23:25 1999
@@ -25,6 +25,8 @@
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef unsigned long	__kernel_sigset_t;	/* at least 32 bits */
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-alpha/siginfo.h linux-2.3.25-devt-timer/include/asm-alpha/siginfo.h
--- linux-2.3.25-vanilla/include/asm-alpha/siginfo.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-alpha/siginfo.h	Thu Nov  4 21:30:08 1999
@@ -17,6 +17,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -29,15 +30,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -67,12 +66,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
diff -ruN linux-2.3.25-vanilla/include/asm-alpha/unistd.h linux-2.3.25-devt-timer/include/asm-alpha/unistd.h
--- linux-2.3.25-vanilla/include/asm-alpha/unistd.h	Sun Sep  5 10:50:49 1999
+++ linux-2.3.25-devt-timer/include/asm-alpha/unistd.h	Tue Nov  2 23:15:19 1999
@@ -310,6 +310,11 @@
 #define __NR_sendfile			370
 #define __NR_setresgid			371
 #define __NR_getresgid			372
+#define __NR_timer_create		373
+#define __NR_timer_settime		374
+#define __NR_timer_gettime		375
+#define __NR_timer_getoverrun		376
+#define __NR_timer_delete		377
 
 #if defined(__LIBRARY__) && defined(__GNUC__)
 
diff -ruN linux-2.3.25-vanilla/include/asm-arm/posix_types.h linux-2.3.25-devt-timer/include/asm-arm/posix_types.h
--- linux-2.3.25-vanilla/include/asm-arm/posix_types.h	Sat May  8 20:06:57 1999
+++ linux-2.3.25-devt-timer/include/asm-arm/posix_types.h	Thu Nov  4 22:46:28 1999
@@ -32,6 +32,8 @@
 typedef long			__kernel_clock_t;
 typedef int			__kernel_daddr_t;
 typedef char *			__kernel_caddr_t;
+typedef int			__kernel_timer_t;
+typedef int			__kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long		__kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-arm/siginfo.h linux-2.3.25-devt-timer/include/asm-arm/siginfo.h
--- linux-2.3.25-vanilla/include/asm-arm/siginfo.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-arm/siginfo.h	Thu Nov  4 21:23:34 1999
@@ -17,6 +17,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -29,15 +30,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -67,12 +66,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
diff -ruN linux-2.3.25-vanilla/include/asm-arm/unistd.h linux-2.3.25-devt-timer/include/asm-arm/unistd.h
--- linux-2.3.25-vanilla/include/asm-arm/unistd.h	Sun Oct 31 19:52:07 1999
+++ linux-2.3.25-devt-timer/include/asm-arm/unistd.h	Tue Nov  2 23:15:19 1999
@@ -198,6 +198,11 @@
 					/* 188 reserved */
 					/* 189 reserved */
 #define __NR_vfork			(__NR_SYSCALL_BASE+190)
+#define __NR_timer_create		(__NR_SYSCALL_BASE+191)
+#define __NR_timer_settime		(__NR_SYSCALL_BASE+192)
+#define __NR_timer_gettime		(__NR_SYSCALL_BASE+193)
+#define __NR_timer_getoverrun		(__NR_SYSCALL_BASE+194)
+#define __NR_timer_delete		(__NR_SYSCALL_BASE+195)
 
 #define __sys2(x) #x
 #define __sys1(x) __sys2(x)
diff -ruN linux-2.3.25-vanilla/include/asm-i386/posix_types.h linux-2.3.25-devt-timer/include/asm-i386/posix_types.h
--- linux-2.3.25-vanilla/include/asm-i386/posix_types.h	Sun Dec 27 19:39:50 1998
+++ linux-2.3.25-devt-timer/include/asm-i386/posix_types.h	Thu Nov  4 22:22:57 1999
@@ -24,6 +24,8 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-i386/siginfo.h linux-2.3.25-devt-timer/include/asm-i386/siginfo.h
--- linux-2.3.25-vanilla/include/asm-i386/siginfo.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-i386/siginfo.h	Thu Nov  4 22:46:31 1999
@@ -17,6 +17,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -29,15 +30,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -67,12 +66,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
diff -ruN linux-2.3.25-vanilla/include/asm-i386/unistd.h linux-2.3.25-devt-timer/include/asm-i386/unistd.h
--- linux-2.3.25-vanilla/include/asm-i386/unistd.h	Tue Nov  2 19:24:08 1999
+++ linux-2.3.25-devt-timer/include/asm-i386/unistd.h	Tue Nov  2 23:16:09 1999
@@ -196,6 +196,11 @@
 #define __NR_putpmsg		189	/* some people actually want streams */
 #define __NR_vfork		190
 #define __NR_ugetrlimit		191	/* SuS compliant getrlimit */
+#define __NR_timer_create	192
+#define __NR_timer_settime	193
+#define __NR_timer_gettime	194
+#define __NR_timer_getoverrun	195
+#define __NR_timer_delete	196
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -ruN linux-2.3.25-vanilla/include/asm-m68k/posix_types.h linux-2.3.25-devt-timer/include/asm-m68k/posix_types.h
--- linux-2.3.25-vanilla/include/asm-m68k/posix_types.h	Mon Aug 10 20:02:24 1998
+++ linux-2.3.25-devt-timer/include/asm-m68k/posix_types.h	Thu Nov  4 22:46:28 1999
@@ -24,6 +24,8 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-m68k/siginfo.h linux-2.3.25-devt-timer/include/asm-m68k/siginfo.h
--- linux-2.3.25-vanilla/include/asm-m68k/siginfo.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-m68k/siginfo.h	Thu Nov  4 21:29:41 1999
@@ -17,6 +17,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -29,15 +30,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -67,12 +66,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
diff -ruN linux-2.3.25-vanilla/include/asm-m68k/unistd.h linux-2.3.25-devt-timer/include/asm-m68k/unistd.h
--- linux-2.3.25-vanilla/include/asm-m68k/unistd.h	Mon Aug  9 21:27:31 1999
+++ linux-2.3.25-devt-timer/include/asm-m68k/unistd.h	Tue Nov  2 23:15:19 1999
@@ -194,6 +194,11 @@
 #define __NR_getpmsg		188	/* some people actually want streams */
 #define __NR_putpmsg		189	/* some people actually want streams */
 #define __NR_vfork		190
+#define __NR_timer_create	191
+#define __NR_timer_settime	192
+#define __NR_timer_gettime	193
+#define __NR_timer_getoverrun	194
+#define __NR_timer_delete	195
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
diff -ruN linux-2.3.25-vanilla/include/asm-mips/posix_types.h linux-2.3.25-devt-timer/include/asm-mips/posix_types.h
--- linux-2.3.25-vanilla/include/asm-mips/posix_types.h	Tue Oct 20 22:52:53 1998
+++ linux-2.3.25-devt-timer/include/asm-mips/posix_types.h	Thu Nov  4 22:46:28 1999
@@ -36,6 +36,8 @@
 typedef long		__kernel_clock_t;
 typedef long		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long      __kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-mips/siginfo.h linux-2.3.25-devt-timer/include/asm-mips/siginfo.h
--- linux-2.3.25-vanilla/include/asm-mips/siginfo.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-mips/siginfo.h	Thu Nov  4 21:31:49 1999
@@ -25,6 +25,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -37,15 +38,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -75,12 +74,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
diff -ruN linux-2.3.25-vanilla/include/asm-mips/unistd.h linux-2.3.25-devt-timer/include/asm-mips/unistd.h
--- linux-2.3.25-vanilla/include/asm-mips/unistd.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-mips/unistd.h	Tue Nov  2 23:15:19 1999
@@ -1196,6 +1196,11 @@
 #define __NR_sendfile			(__NR_Linux + 207)
 #define __NR_getpmsg			(__NR_Linux + 208)
 #define __NR_putpmsg			(__NR_Linux + 209)
+#define __NR_timer_create		(__NR_Linux + 210)
+#define __NR_timer_settime		(__NR_Linux + 211)
+#define __NR_timer_gettime		(__NR_Linux + 212)
+#define __NR_timer_getoverrun		(__NR_Linux + 213)
+#define __NR_timer_delete		(__NR_Linux + 214)
 
 /*
  * Offset of the last Linux flavoured syscall
diff -ruN linux-2.3.25-vanilla/include/asm-ppc/posix_types.h linux-2.3.25-devt-timer/include/asm-ppc/posix_types.h
--- linux-2.3.25-vanilla/include/asm-ppc/posix_types.h	Thu Apr 29 21:39:01 1999
+++ linux-2.3.25-devt-timer/include/asm-ppc/posix_types.h	Thu Nov  4 22:46:27 1999
@@ -24,6 +24,8 @@
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef short             __kernel_ipc_pid_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-ppc/siginfo.h linux-2.3.25-devt-timer/include/asm-ppc/siginfo.h
--- linux-2.3.25-vanilla/include/asm-ppc/siginfo.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-ppc/siginfo.h	Thu Nov  4 21:26:17 1999
@@ -17,6 +17,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -29,15 +30,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -67,12 +66,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
@@ -122,7 +121,7 @@
  * SIGSEGV si_codes
  */
 #define SEGV_MAPERR	1	/* address not mapped to object */
-#define SRGV_ACCERR	2	/* invalid permissions for mapped object */
+#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
 #define NSIGSEGV	2
 
 /*
diff -ruN linux-2.3.25-vanilla/include/asm-ppc/unistd.h linux-2.3.25-devt-timer/include/asm-ppc/unistd.h
--- linux-2.3.25-vanilla/include/asm-ppc/unistd.h	Sun Sep  5 10:50:51 1999
+++ linux-2.3.25-devt-timer/include/asm-ppc/unistd.h	Tue Nov  2 23:15:19 1999
@@ -194,6 +194,11 @@
 #define __NR_getpmsg		187	/* some people actually want streams */
 #define __NR_putpmsg		188	/* some people actually want streams */
 #define __NR_vfork		189
+#define __NR_timer_create	190
+#define __NR_timer_settime	191
+#define __NR_timer_gettime	192
+#define __NR_timer_getoverrun	193
+#define __NR_timer_delete	194
 
 #define __NR(n)	#n
 
diff -ruN linux-2.3.25-vanilla/include/asm-sh/posix_types.h linux-2.3.25-devt-timer/include/asm-sh/posix_types.h
--- linux-2.3.25-vanilla/include/asm-sh/posix_types.h	Sun Sep  5 10:50:51 1999
+++ linux-2.3.25-devt-timer/include/asm-sh/posix_types.h	Thu Nov  4 22:46:27 1999
@@ -24,6 +24,8 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef int		__kernel_timer_t;
+typedef int		__kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-sh/siginfo.h linux-2.3.25-devt-timer/include/asm-sh/siginfo.h
--- linux-2.3.25-vanilla/include/asm-sh/siginfo.h	Sun Sep  5 10:50:51 1999
+++ linux-2.3.25-devt-timer/include/asm-sh/siginfo.h	Thu Nov  4 21:23:05 1999
@@ -17,6 +17,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -29,15 +30,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -67,12 +66,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_band		_sifields._sigpoll._band
 #define si_fd		_sifields._sigpoll._fd
diff -ruN linux-2.3.25-vanilla/include/asm-sparc/posix_types.h linux-2.3.25-devt-timer/include/asm-sparc/posix_types.h
--- linux-2.3.25-vanilla/include/asm-sparc/posix_types.h	Thu Mar 11 01:53:37 1999
+++ linux-2.3.25-devt-timer/include/asm-sparc/posix_types.h	Thu Nov  4 22:46:26 1999
@@ -31,6 +31,8 @@
 typedef long                   __kernel_daddr_t;
 typedef long                   __kernel_off_t;
 typedef char *                 __kernel_caddr_t;
+typedef int		       __kernel_timer_t;
+typedef int		       __kernel_clockid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -ruN linux-2.3.25-vanilla/include/asm-sparc/siginfo.h linux-2.3.25-devt-timer/include/asm-sparc/siginfo.h
--- linux-2.3.25-vanilla/include/asm-sparc/siginfo.h	Tue Aug  3 07:07:16 1999
+++ linux-2.3.25-devt-timer/include/asm-sparc/siginfo.h	Thu Nov  4 21:28:35 1999
@@ -19,6 +19,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -31,15 +32,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			unsigned int _uid;	/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -70,12 +69,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_trapno	_sifields._sigfault._trapno
 #define si_band		_sifields._sigpoll._band
@@ -127,7 +126,7 @@
  * SIGSEGV si_codes
  */
 #define SEGV_MAPERR	1	/* address not mapped to object */
-#define SRGV_ACCERR	2	/* invalid permissions for mapped object */
+#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
 #define NSIGSEGV	2
 
 /*
diff -ruN linux-2.3.25-vanilla/include/asm-sparc/unistd.h linux-2.3.25-devt-timer/include/asm-sparc/unistd.h
--- linux-2.3.25-vanilla/include/asm-sparc/unistd.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/asm-sparc/unistd.h	Tue Nov  2 23:15:19 1999
@@ -123,11 +123,11 @@
 #define __NR_rt_sigtimedwait    105 /* Linux Specific                              */
 #define __NR_rt_sigqueueinfo    106 /* Linux Specific                              */
 #define __NR_rt_sigsuspend      107 /* Linux Specific                              */
-/* #define __NR_sigvec          108    SunOS Specific                              */
-/* #define __NR_sigblock        109    SunOS Specific                              */
-/* #define __NR_sigsetmask      110    SunOS Specific                              */
-/* #define __NR_sigpause        111    SunOS Specific                              */
-/* #define __NR_sigstack        112    SunOS Specific                              */
+#define __NR_timer_create	108 /* Linux Specific                              */
+#define __NR_timer_settime	109 /* Linux Specific                              */
+#define __NR_timer_gettime	110 /* Linux Specific                              */
+#define __NR_timer_getoverrun	111 /* Linux Specific                              */
+#define __NR_timer_delete	112 /* Linux Specific                              */
 #define __NR_recvmsg            113 /* Common                                      */
 #define __NR_sendmsg            114 /* Common                                      */
 /* #define __NR_vtrace          115    SunOS Specific                              */
@@ -201,9 +201,9 @@
 #define __NR_sigpending         183 /* Common                                      */
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
-/* #define __NR_pathconf        186    SunOS Specific                              */
-/* #define __NR_fpathconf       187    SunOS Specific                              */
-/* #define __NR_sysconf         188    SunOS Specific                              */
+/* #define __NR_clock_gettime	186    Linux Specific				   */
+/* #define __NR_clock_settime	187    Linux Specific				   */
+/* #define __NR_clock_getres	188    Linux Specific				   */
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
 #define __NR_personality        191 /* Linux Specific                              */
@@ -271,6 +271,8 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+/* Please don't add syscalls above 255.
+   Contact jj@ultra.linux.cz or davem@redhat.com for number assignment.  */
 
 #define _syscall0(type,name) \
 type name(void) \
diff -ruN linux-2.3.25-vanilla/include/asm-sparc64/posix_types.h linux-2.3.25-devt-timer/include/asm-sparc64/posix_types.h
--- linux-2.3.25-vanilla/include/asm-sparc64/posix_types.h	Thu Mar 11 01:53:38 1999
+++ linux-2.3.25-devt-timer/include/asm-sparc64/posix_types.h	Thu Nov  4 22:26:58 1999
@@ -29,6 +29,8 @@
 typedef int                    __kernel_daddr_t;
 typedef long                   __kernel_off_t;
 typedef char *                 __kernel_caddr_t;
+typedef int		       __kernel_timer_t;
+typedef int		       __kernel_clockid_t;
 
 /* Note this piece of asymmetry from the v9 ABI.  */
 typedef int		       __kernel_suseconds_t;
@@ -65,6 +67,8 @@
 typedef unsigned int           __kernel_caddr_t32;
 typedef long		       __kernel_loff_t32;
 typedef __kernel_fsid_t        __kernel_fsid_t32;
+typedef int		       __kernel_timer_t32;
+typedef int		       __kernel_clockid_t32;
 
 #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
 
diff -ruN linux-2.3.25-vanilla/include/asm-sparc64/siginfo.h linux-2.3.25-devt-timer/include/asm-sparc64/siginfo.h
--- linux-2.3.25-vanilla/include/asm-sparc64/siginfo.h	Tue Aug  3 07:07:16 1999
+++ linux-2.3.25-devt-timer/include/asm-sparc64/siginfo.h	Thu Nov  4 21:24:45 1999
@@ -25,6 +25,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE];
@@ -37,15 +38,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;		/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
 			uid_t _uid;		/* sender's uid */
-			sigval_t _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -77,6 +76,7 @@
 	int si_signo;
 	int si_errno;
 	int si_code;
+	sigval_t32 si_value;
 
 	union {
 		int _pad[SI_PAD_SIZE32];
@@ -89,15 +89,13 @@
 
 		/* POSIX.1b timers */
 		struct {
-			unsigned int _timer1;
-			unsigned int _timer2;
+			timer_t _tid;			/* timer id */
 		} _timer;
 
 		/* POSIX.1b signals */
 		struct {
 			__kernel_pid_t32 _pid;		/* sender's pid */
 			unsigned int _uid;		/* sender's uid */
-			sigval_t32 _sigval;
 		} _rt;
 
 		/* SIGCHLD */
@@ -130,12 +128,12 @@
  */
 #define si_pid		_sifields._kill._pid
 #define si_uid		_sifields._kill._uid
+#define si_tid		_sifields._timer._tid
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
-#define si_value	_sifields._rt._sigval
-#define si_int		_sifields._rt._sigval.sival_int
-#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_int		si_value.sival_int
+#define si_ptr		si_value.sival_ptr
 #define si_addr		_sifields._sigfault._addr
 #define si_trapno	_sifields._sigfault._trapno
 #define si_band		_sifields._sigpoll._band
@@ -187,7 +185,7 @@
  * SIGSEGV si_codes
  */
 #define SEGV_MAPERR	1	/* address not mapped to object */
-#define SRGV_ACCERR	2	/* invalid permissions for mapped object */
+#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
 #define NSIGSEGV	2
 
 /*
@@ -266,7 +264,7 @@
 #ifdef __KERNEL__
 
 typedef struct sigevent32 {
-	sigval_t sigev_value;
+	sigval_t32 sigev_value;
 	int sigev_signo;
 	int sigev_notify;
 	union {
diff -ruN linux-2.3.25-vanilla/include/asm-sparc64/unistd.h linux-2.3.25-devt-timer/include/asm-sparc64/unistd.h
--- linux-2.3.25-vanilla/include/asm-sparc64/unistd.h	Thu Aug  5 00:39:46 1999
+++ linux-2.3.25-devt-timer/include/asm-sparc64/unistd.h	Tue Nov  2 23:15:20 1999
@@ -123,11 +123,11 @@
 #define __NR_rt_sigtimedwait    105 /* Linux Specific                              */
 #define __NR_rt_sigqueueinfo    106 /* Linux Specific                              */
 #define __NR_rt_sigsuspend      107 /* Linux Specific                              */
-/* #define __NR_sigvec          108    SunOS Specific                              */
-/* #define __NR_sigblock        109    SunOS Specific                              */
-/* #define __NR_sigsetmask      110    SunOS Specific                              */
-/* #define __NR_sigpause        111    SunOS Specific                              */
-/* #define __NR_sigstack        112    SunOS Specific                              */
+#define __NR_timer_create	108 /* Linux Specific                              */
+#define __NR_timer_settime	109 /* Linux Specific                              */
+#define __NR_timer_gettime	110 /* Linux Specific                              */
+#define __NR_timer_getoverrun	111 /* Linux Specific                              */
+#define __NR_timer_delete	112 /* Linux Specific                              */
 #define __NR_recvmsg            113 /* Common                                      */
 #define __NR_sendmsg            114 /* Common                                      */
 /* #define __NR_vtrace          115    SunOS Specific                              */
@@ -201,9 +201,9 @@
 #define __NR_sigpending         183 /* Common                                      */
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
-/* #define __NR_pathconf        186    SunOS Specific                              */
-/* #define __NR_fpathconf       187    SunOS Specific                              */
-/* #define __NR_sysconf         188    SunOS Specific                              */
+/* #define __NR_clock_gettime	186    Linux Specific				   */
+/* #define __NR_clock_settime	187    Linux Specific				   */
+/* #define __NR_clock_getres	188    Linux Specific				   */
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
 #define __NR_personality        191 /* Linux Specific                              */
@@ -271,6 +271,8 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+/* Please don't add syscalls above 255.
+   Contact jj@ultra.linux.cz or davem@redhat.com for number assignment.  */
 
 #define _syscall0(type,name) \
 type name(void) \
diff -ruN linux-2.3.25-vanilla/include/linux/limits.h linux-2.3.25-devt-timer/include/linux/limits.h
--- linux-2.3.25-vanilla/include/linux/limits.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/linux/limits.h	Tue Nov  2 23:15:20 1999
@@ -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.3.25-vanilla/include/linux/sched.h linux-2.3.25-devt-timer/include/linux/sched.h
--- linux-2.3.25-vanilla/include/linux/sched.h	Sun Oct 31 19:52:08 1999
+++ linux-2.3.25-devt-timer/include/linux/sched.h	Thu Nov  4 22:46:31 1999
@@ -36,6 +36,7 @@
 #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_PARENT	0x00008000	/* set if we want to have the same parent as the cloner */
+#define CLONE_ITIMERS   0x00010000      /* set if POSIX.1b itimers are shared */
 
 /*
  * These are the constant used to fake the fixed-point load-average
@@ -262,6 +263,28 @@
  */
 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];	
+};
+
+extern struct itimer_struct *itimer_struct_new(void);
+
 struct task_struct {
 /* these are hardcoded - don't touch */
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
@@ -317,6 +340,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];
@@ -407,6 +431,7 @@
 /* chld wait */	__WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), 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, \
@@ -703,6 +728,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 void daemonize(void);
 
diff -ruN linux-2.3.25-vanilla/include/linux/time.h linux-2.3.25-devt-timer/include/linux/time.h
--- linux-2.3.25-vanilla/include/linux/time.h	Wed Jul 28 19:30:10 1999
+++ linux-2.3.25-devt-timer/include/linux/time.h	Thu Nov  4 22:46:30 1999
@@ -1,7 +1,7 @@
 #ifndef _LINUX_TIME_H
 #define _LINUX_TIME_H
 
-#include <asm/param.h>
+#include <linux/param.h>
 #include <linux/types.h>
 
 #ifndef _STRUCT_TIMESPEC
@@ -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,18 @@
 	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
+
+/*
+ * The various flags for setting POSIX.1b interval timers.
+ */
+
+#define TIMER_ABSTIME 0x01
+
 
 #endif
diff -ruN linux-2.3.25-vanilla/include/linux/types.h linux-2.3.25-devt-timer/include/linux/types.h
--- linux-2.3.25-vanilla/include/linux/types.h	Mon Dec 28 07:18:28 1998
+++ linux-2.3.25-devt-timer/include/linux/types.h	Thu Nov  4 22:46:30 1999
@@ -18,6 +18,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;
 
 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
 typedef __kernel_loff_t		loff_t;
diff -ruN linux-2.3.25-vanilla/kernel/exit.c linux-2.3.25-devt-timer/kernel/exit.c
--- linux-2.3.25-vanilla/kernel/exit.c	Tue Nov  2 19:24:09 1999
+++ linux-2.3.25-devt-timer/kernel/exit.c	Tue Nov  2 23:15:20 1999
@@ -262,6 +262,34 @@
 	mmdrop(active_mm);
 }
 
+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);
+}
+
 /*
  * Turn us into a lazy TLB process if we
  * aren't already..
@@ -410,6 +438,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.3.25-vanilla/kernel/fork.c linux-2.3.25-devt-timer/kernel/fork.c
--- linux-2.3.25-vanilla/kernel/fork.c	Sun Oct 31 19:52:23 1999
+++ linux-2.3.25-devt-timer/kernel/fork.c	Thu Nov  4 22:40:57 1999
@@ -581,6 +581,23 @@
 	p->flags = new_flags;
 }
 
+
+static inline int copy_itimers(unsigned long clone_flags, struct task_struct * tsk)
+{
+	if (clone_flags & CLONE_ITIMERS) {
+		if (tsk->posix_timers == NULL) {
+			tsk->posix_timers = itimer_struct_new();
+			if (tsk->posix_timers == NULL) return -1;
+		}
+		atomic_inc(&tsk->posix_timers->count);
+		return 0;
+	}
+	tsk->posix_timers = NULL;
+
+	return 0;
+}
+
+
 /*
  *  Ok, this is the main fork-routine. It copies the system process
  * information (task[nr]) and sets up the necessary registers. It
@@ -687,6 +704,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(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
 	retval = copy_thread(0, clone_flags, usp, p, regs);
@@ -736,6 +755,8 @@
 		down(&sem);
 	return retval;
 
+bad_fork_cleanup_itimers:
+	exit_itimers(p);
 bad_fork_cleanup_sighand:
 	exit_sighand(p);
 bad_fork_cleanup_fs:
diff -ruN linux-2.3.25-vanilla/kernel/itimer.c linux-2.3.25-devt-timer/kernel/itimer.c
--- linux-2.3.25-vanilla/kernel/itimer.c	Sun Sep  5 10:50:55 1999
+++ linux-2.3.25-devt-timer/kernel/itimer.c	Sun Nov  7 12:28:32 1999
@@ -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
@@ -166,6 +168,410 @@
 		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;
+		info.si_tid = timr->it_id;
+		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;
+}
+
+struct itimer_struct *itimer_struct_new(void)
+{
+	struct itimer_struct *posix_timers;
+
+	posix_timers = kmalloc(sizeof(struct itimer_struct), GFP_KERNEL);
+	if (posix_timers == NULL) return NULL;
+	spin_lock_init(&posix_timers->its_lock);
+	atomic_set(&posix_timers->count, 1);
+	memset(posix_timers->itimer, 0, sizeof(posix_timers->itimer));
+	return posix_timers;
+}
+
+
+
+/* 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;
+
+	if (timers == NULL) {
+		timers = current->posix_timers = itimer_struct_new();
+		if (timers == NULL) return -EAGAIN;
+	}
+
+	printk("clock %d, timer_event_spec %x, timer_id %x\n", which_clock, timer_event_spec, created_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;
+			printk("out1");
+			goto out;
+		}
+		if (!good_sigevent(&new_timer->it_signal)) {
+			error = -EINVAL;
+			printk("out2");
+			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;
+		printk("out3");
+		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;
+		printk("out4");
+		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;
+	if (tsk->posix_timers == NULL) 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.3.25-vanilla/kernel/signal.c linux-2.3.25-devt-timer/kernel/signal.c
--- linux-2.3.25-vanilla/kernel/signal.c	Sun Oct 31 19:51:12 1999
+++ linux-2.3.25-devt-timer/kernel/signal.c	Thu Nov  4 21:33:07 1999
@@ -323,6 +323,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_tid == info->si_tid)) {
+					/* 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);
	
-- 
Robert de Vries
rhdv@rhdv.cistron.nl


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/