[PATCH] Posix timers for Linux 2.3.42

From: Robert de Vries (rhdv@rhdv.cistron.nl)
Date: Tue Feb 08 2000 - 16:36:09 EST


Hi,

Attached to this e-mail you will find the latest patch to add posix timers
to the Linux kernel.

The patch has been around for a while and I have tested it a lot on the
intel platform. The patch includes support for other platforms (thanks to
Jakub Jelinek for his SPARC patches). They have not been tested, so if a
kind soul would be so friendly to give it a try?

Test code can be found on my web page
(http://www.rhdv.cistron.nl/posix.html)

Linus, please consider this for inclusion in the kernel.

Thanks in advance,

        Robert

Index: linux/arch/alpha/kernel/entry.S
diff -u linux/arch/alpha/kernel/entry.S:1.1.1.1 linux/arch/alpha/kernel/entry.S:1.1.2.1
--- linux/arch/alpha/kernel/entry.S:1.1.1.1 Sun Jan 30 22:21:39 2000
+++ linux/arch/alpha/kernel/entry.S Sun Jan 30 22:56:14 2000
@@ -1151,3 +1151,8 @@
         .quad sys_getresgid
         .quad sys_ni_syscall /* sys_dipc */
         .quad sys_shmget
+ .quad sys_timer_create /* 375 */
+ .quad sys_timer_settime
+ .quad sys_timer_gettime
+ .quad sys_timer_getoverrun
+ .quad sys_timer_delete
Index: linux/arch/arm/kernel/calls.S
diff -u linux/arch/arm/kernel/calls.S:1.1.1.2 linux/arch/arm/kernel/calls.S:1.1.2.2
--- linux/arch/arm/kernel/calls.S:1.1.1.2 Sun Jan 30 22:24:05 2000
+++ linux/arch/arm/kernel/calls.S Mon Jan 31 00:25:16 2000
@@ -226,8 +226,13 @@
                 .long SYMBOL_NAME(sys_setgid)
 /* 215 */ .long SYMBOL_NAME(sys_setfsuid)
                 .long SYMBOL_NAME(sys_setfsgid)
+ .long SYMBOL_NAME(sys_timer_create)
+ .long SYMBOL_NAME(sys_timer_settime)
+ .long SYMBOL_NAME(sys_timer_gettime)
+/* 220 */ .long SYMBOL_NAME(sys_timer_getoverrun)
+ .long SYMBOL_NAME(sys_timer_delete)
 
- .rept NR_syscalls-216
+ .rept NR_syscalls-221
                         .long SYMBOL_NAME(sys_ni_syscall)
                 .endr
 #endif
Index: linux/arch/i386/kernel/entry.S
diff -u linux/arch/i386/kernel/entry.S:1.1.1.2 linux/arch/i386/kernel/entry.S:1.1.2.2
--- linux/arch/i386/kernel/entry.S:1.1.1.2 Sun Jan 30 22:26:08 2000
+++ linux/arch/i386/kernel/entry.S Mon Jan 31 00:25:18 2000
@@ -618,6 +618,11 @@
         .long SYMBOL_NAME(sys_setfsuid) /* 215 */
         .long SYMBOL_NAME(sys_setfsgid)
         .long SYMBOL_NAME(sys_pivot_root)
+ .long SYMBOL_NAME(sys_timer_create)
+ .long SYMBOL_NAME(sys_timer_settime)
+ .long SYMBOL_NAME(sys_timer_gettime) /* 220 */
+ .long SYMBOL_NAME(sys_timer_getoverrun)
+ .long SYMBOL_NAME(sys_timer_delete)
 
 
         /*
@@ -626,6 +631,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-217
+ .rept NR_syscalls-222
                 .long SYMBOL_NAME(sys_ni_syscall)
         .endr
Index: linux/arch/m68k/kernel/entry.S
diff -u linux/arch/m68k/kernel/entry.S:1.1.1.2 linux/arch/m68k/kernel/entry.S:1.1.2.2
--- linux/arch/m68k/kernel/entry.S:1.1.1.2 Sun Jan 30 22:26:21 2000
+++ linux/arch/m68k/kernel/entry.S Mon Jan 31 00:25:21 2000
@@ -629,6 +629,11 @@
         .long SYMBOL_NAME(sys_setgid)
         .long SYMBOL_NAME(sys_setfsuid) /* 215 */
         .long SYMBOL_NAME(sys_setfsgid)
+ .long SYMBOL_NAME(sys_timer_create)
+ .long SYMBOL_NAME(sys_timer_settime) /* 215 */
+ .long SYMBOL_NAME(sys_timer_gettime)
+ .long SYMBOL_NAME(sys_timer_getoverrun)
+ .long SYMBOL_NAME(sys_timer_delete)
 
         .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
                 .long SYMBOL_NAME(sys_ni_syscall)
Index: linux/arch/mips/kernel/irix5sys.h
diff -u linux/arch/mips/kernel/irix5sys.h:1.1.1.1 linux/arch/mips/kernel/irix5sys.h:1.1.2.1
--- linux/arch/mips/kernel/irix5sys.h:1.1.1.1 Sun Jan 30 22:21:42 2000
+++ linux/arch/mips/kernel/irix5sys.h Sun Jan 30 22:56:20 2000
@@ -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*/
Index: linux/arch/mips/kernel/syscalls.h
diff -u linux/arch/mips/kernel/syscalls.h:1.1.1.1 linux/arch/mips/kernel/syscalls.h:1.1.2.1
--- linux/arch/mips/kernel/syscalls.h:1.1.1.1 Sun Jan 30 22:21:42 2000
+++ linux/arch/mips/kernel/syscalls.h Sun Jan 30 22:56:21 2000
@@ -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)
Index: linux/arch/ppc/kernel/misc.S
diff -u linux/arch/ppc/kernel/misc.S:1.1.1.2 linux/arch/ppc/kernel/misc.S:1.1.2.2
--- linux/arch/ppc/kernel/misc.S:1.1.1.2 Sun Jan 30 22:26:17 2000
+++ linux/arch/ppc/kernel/misc.S Mon Jan 31 00:25:25 2000
@@ -1068,6 +1068,11 @@
         .long sys_ni_syscall /* streams2 */
         .long sys_vfork
         .long sys_getrlimit /* 190 */
- .rept NR_syscalls-190
+ .long sys_timer_create
+ .long sys_timer_settime
+ .long sys_timer_gettime
+ .long sys_timer_getoverrun
+ .long sys_timer_delete /* 195 */
+ .rept NR_syscalls-195
                 .long sys_ni_syscall
         .endr
Index: linux/arch/sparc/kernel/systbls.S
diff -u linux/arch/sparc/kernel/systbls.S:1.1.1.4 linux/arch/sparc/kernel/systbls.S:1.1.2.3
--- linux/arch/sparc/kernel/systbls.S:1.1.1.4 Mon Feb 7 21:19:04 2000
+++ linux/arch/sparc/kernel/systbls.S Mon Feb 7 21:50:34 2000
@@ -51,8 +51,8 @@
 /*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
 /*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-/*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+/*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_timer_create
+/*170*/ .long sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun, sys_timer_delete, sys_getdents
 /*175*/ .long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
 /*185*/ .long sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
Index: linux/arch/sparc64/kernel/sys_sparc32.c
diff -u linux/arch/sparc64/kernel/sys_sparc32.c:1.1.1.3 linux/arch/sparc64/kernel/sys_sparc32.c:1.1.2.2
--- linux/arch/sparc64/kernel/sys_sparc32.c:1.1.1.3 Sun Jan 30 22:26:25 2000
+++ linux/arch/sparc64/kernel/sys_sparc32.c Mon Jan 31 00:25:30 2000
@@ -4190,3 +4190,113 @@
         fd = error;
         goto out;
 }
+
+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;
+}
Index: linux/arch/sparc64/kernel/systbls.S
diff -u linux/arch/sparc64/kernel/systbls.S:1.1.1.4 linux/arch/sparc64/kernel/systbls.S:1.1.2.3
--- linux/arch/sparc64/kernel/systbls.S:1.1.1.4 Mon Feb 7 21:19:06 2000
+++ linux/arch/sparc64/kernel/systbls.S Mon Feb 7 21:50:34 2000
@@ -52,8 +52,8 @@
 /*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
         .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
- .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
-/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
+ .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys32_timer_create
+/*170*/ .word sys32_timer_settime, sys32_timer_gettime, sys32_timer_getoverrun, sys32_timer_delete, sys32_getdents
         .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
         .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
@@ -70,7 +70,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. */
 
@@ -111,8 +111,8 @@
 /*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
         .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
- .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+ .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_timer_create
+/*170*/ .word sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun, sys_timer_delete, sys_getdents
         .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
         .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
@@ -129,7 +129,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
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
Index: linux/fs/exec.c
diff -u linux/fs/exec.c:1.1.1.1 linux/fs/exec.c:1.1.2.1
--- linux/fs/exec.c:1.1.1.1 Sun Jan 30 22:21:00 2000
+++ linux/fs/exec.c Sun Jan 30 22:56:28 2000
@@ -525,6 +525,7 @@
                         
         flush_signal_handlers(current);
         flush_old_files(current->files);
+ exit_itimers(current);
         task_unlock(current);
 
         return 0;
Index: linux/include/asm-alpha/posix_types.h
diff -u linux/include/asm-alpha/posix_types.h:1.1.1.2 linux/include/asm-alpha/posix_types.h:1.1.2.2
--- linux/include/asm-alpha/posix_types.h:1.1.1.2 Sun Jan 30 22:22:53 2000
+++ linux/include/asm-alpha/posix_types.h Mon Jan 31 00:26:12 2000
@@ -23,6 +23,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 long __kernel_sigset_t; /* at least 32 bits */
Index: linux/include/asm-alpha/siginfo.h
diff -u linux/include/asm-alpha/siginfo.h:1.1.1.2 linux/include/asm-alpha/siginfo.h:1.1.2.2
--- linux/include/asm-alpha/siginfo.h:1.1.1.2 Sun Jan 30 22:25:04 2000
+++ linux/include/asm-alpha/siginfo.h Mon Jan 31 00:26:12 2000
@@ -29,8 +29,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -67,6 +68,7 @@
  */
 #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
@@ -89,8 +91,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
Index: linux/include/asm-alpha/unistd.h
diff -u linux/include/asm-alpha/unistd.h:1.1.1.1 linux/include/asm-alpha/unistd.h:1.1.2.1
--- linux/include/asm-alpha/unistd.h:1.1.1.1 Sun Jan 30 22:21:06 2000
+++ linux/include/asm-alpha/unistd.h Sun Jan 30 22:56:31 2000
@@ -311,6 +311,11 @@
 #define __NR_setresgid 371
 #define __NR_getresgid 372
 #define __NR_dipc 373
+#define __NR_timer_create 374
+#define __NR_timer_settime 375
+#define __NR_timer_gettime 376
+#define __NR_timer_getoverrun 377
+#define __NR_timer_delete 378
 
 #if defined(__LIBRARY__) && defined(__GNUC__)
 
Index: linux/include/asm-arm/posix_types.h
diff -u linux/include/asm-arm/posix_types.h:1.1.1.2 linux/include/asm-arm/posix_types.h:1.1.2.2
--- linux/include/asm-arm/posix_types.h:1.1.1.2 Sun Jan 30 22:22:59 2000
+++ linux/include/asm-arm/posix_types.h Mon Jan 31 00:26:12 2000
@@ -30,6 +30,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;
Index: linux/include/asm-arm/siginfo.h
diff -u linux/include/asm-arm/siginfo.h:1.1.1.2 linux/include/asm-arm/siginfo.h:1.1.2.2
--- linux/include/asm-arm/siginfo.h:1.1.1.2 Sun Jan 30 22:25:10 2000
+++ linux/include/asm-arm/siginfo.h Mon Jan 31 00:26:13 2000
@@ -29,8 +29,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -67,6 +68,7 @@
  */
 #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
@@ -89,8 +91,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
Index: linux/include/asm-arm/unistd.h
diff -u linux/include/asm-arm/unistd.h:1.1.1.2 linux/include/asm-arm/unistd.h:1.1.2.2
--- linux/include/asm-arm/unistd.h:1.1.1.2 Sun Jan 30 22:22:59 2000
+++ linux/include/asm-arm/unistd.h Mon Jan 31 00:26:13 2000
@@ -223,6 +223,11 @@
 #define __NR_setgid32 (__NR_SYSCALL_BASE+214)
 #define __NR_setfsuid32 (__NR_SYSCALL_BASE+215)
 #define __NR_setfsgid32 (__NR_SYSCALL_BASE+216)
+#define __NR_timer_create (__NR_SYSCALL_BASE+217)
+#define __NR_timer_settime (__NR_SYSCALL_BASE+218)
+#define __NR_timer_gettime (__NR_SYSCALL_BASE+219)
+#define __NR_timer_getoverrun (__NR_SYSCALL_BASE+220)
+#define __NR_timer_delete (__NR_SYSCALL_BASE+221)
 
 #define __sys2(x) #x
 #define __sys1(x) __sys2(x)
Index: linux/include/asm-i386/posix_types.h
diff -u linux/include/asm-i386/posix_types.h:1.1.1.2 linux/include/asm-i386/posix_types.h:1.1.2.2
--- linux/include/asm-i386/posix_types.h:1.1.1.2 Sun Jan 30 22:22:52 2000
+++ linux/include/asm-i386/posix_types.h Mon Jan 31 00:26:15 2000
@@ -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;
Index: linux/include/asm-i386/siginfo.h
diff -u linux/include/asm-i386/siginfo.h:1.1.1.2 linux/include/asm-i386/siginfo.h:1.1.2.2
--- linux/include/asm-i386/siginfo.h:1.1.1.2 Sun Jan 30 22:25:02 2000
+++ linux/include/asm-i386/siginfo.h Mon Jan 31 00:26:15 2000
@@ -29,8 +29,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -67,6 +68,7 @@
  */
 #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
@@ -89,8 +91,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
Index: linux/include/asm-i386/unistd.h
diff -u linux/include/asm-i386/unistd.h:1.1.1.2 linux/include/asm-i386/unistd.h:1.1.2.2
--- linux/include/asm-i386/unistd.h:1.1.1.2 Sun Jan 30 22:25:02 2000
+++ linux/include/asm-i386/unistd.h Mon Jan 31 00:26:16 2000
@@ -222,6 +222,11 @@
 #define __NR_setfsuid32 215
 #define __NR_setfsgid32 216
 #define __NR_pivot_root 217
+#define __NR_timer_create 218
+#define __NR_timer_settime 219
+#define __NR_timer_gettime 220
+#define __NR_timer_getoverrun 221
+#define __NR_timer_delete 222
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
Index: linux/include/asm-m68k/posix_types.h
diff -u linux/include/asm-m68k/posix_types.h:1.1.1.2 linux/include/asm-m68k/posix_types.h:1.1.2.2
--- linux/include/asm-m68k/posix_types.h:1.1.1.2 Sun Jan 30 22:22:54 2000
+++ linux/include/asm-m68k/posix_types.h Mon Jan 31 00:26:16 2000
@@ -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;
Index: linux/include/asm-m68k/siginfo.h
diff -u linux/include/asm-m68k/siginfo.h:1.1.1.2 linux/include/asm-m68k/siginfo.h:1.1.2.2
--- linux/include/asm-m68k/siginfo.h:1.1.1.2 Sun Jan 30 22:25:04 2000
+++ linux/include/asm-m68k/siginfo.h Mon Jan 31 00:26:17 2000
@@ -29,8 +29,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -67,6 +68,7 @@
  */
 #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
@@ -89,8 +91,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
Index: linux/include/asm-m68k/unistd.h
diff -u linux/include/asm-m68k/unistd.h:1.1.1.1 linux/include/asm-m68k/unistd.h:1.1.2.1
--- linux/include/asm-m68k/unistd.h:1.1.1.1 Sun Jan 30 22:21:07 2000
+++ linux/include/asm-m68k/unistd.h Sun Jan 30 22:56:33 2000
@@ -220,6 +220,11 @@
 #define __NR_setgid32 214
 #define __NR_setfsuid32 215
 #define __NR_setfsgid32 216
+#define __NR_timer_create 217
+#define __NR_timer_settime 218
+#define __NR_timer_gettime 219
+#define __NR_timer_getoverrun 220
+#define __NR_timer_delete 221
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
Index: linux/include/asm-mips/posix_types.h
diff -u linux/include/asm-mips/posix_types.h:1.1.1.1 linux/include/asm-mips/posix_types.h:1.1.2.1
--- linux/include/asm-mips/posix_types.h:1.1.1.1 Sun Jan 30 22:21:06 2000
+++ linux/include/asm-mips/posix_types.h Sun Jan 30 22:56:33 2000
@@ -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;
Index: linux/include/asm-mips/siginfo.h
diff -u linux/include/asm-mips/siginfo.h:1.1.1.2 linux/include/asm-mips/siginfo.h:1.1.2.2
--- linux/include/asm-mips/siginfo.h:1.1.1.2 Sun Jan 30 22:25:03 2000
+++ linux/include/asm-mips/siginfo.h Mon Jan 31 00:26:17 2000
@@ -37,8 +37,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -75,6 +76,7 @@
  */
 #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
@@ -97,8 +99,8 @@
 #define SI_MESGQ -4 /* sent by real time mesq state change */
 #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
Index: linux/include/asm-mips/unistd.h
diff -u linux/include/asm-mips/unistd.h:1.1.1.1 linux/include/asm-mips/unistd.h:1.1.2.1
--- linux/include/asm-mips/unistd.h:1.1.1.1 Sun Jan 30 22:21:06 2000
+++ linux/include/asm-mips/unistd.h Sun Jan 30 22:56:33 2000
@@ -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
Index: linux/include/asm-ppc/posix_types.h
diff -u linux/include/asm-ppc/posix_types.h:1.1.1.2 linux/include/asm-ppc/posix_types.h:1.1.2.2
--- linux/include/asm-ppc/posix_types.h:1.1.1.2 Sun Jan 30 22:22:57 2000
+++ linux/include/asm-ppc/posix_types.h Mon Jan 31 00:26:18 2000
@@ -21,6 +21,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 short __kernel_ipc_pid_t;
Index: linux/include/asm-ppc/siginfo.h
diff -u linux/include/asm-ppc/siginfo.h:1.1.1.2 linux/include/asm-ppc/siginfo.h:1.1.2.2
--- linux/include/asm-ppc/siginfo.h:1.1.1.2 Sun Jan 30 22:25:09 2000
+++ linux/include/asm-ppc/siginfo.h Mon Jan 31 00:26:18 2000
@@ -29,8 +29,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -67,6 +68,7 @@
  */
 #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
@@ -89,8 +91,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
@@ -122,7 +124,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
 
 /*
Index: linux/include/asm-ppc/unistd.h
diff -u linux/include/asm-ppc/unistd.h:1.1.1.1 linux/include/asm-ppc/unistd.h:1.1.2.1
--- linux/include/asm-ppc/unistd.h:1.1.1.1 Sun Jan 30 22:21:08 2000
+++ linux/include/asm-ppc/unistd.h Sun Jan 30 22:56:34 2000
@@ -201,6 +201,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
 
 #define __NR(n) #n
 
Index: linux/include/asm-sh/posix_types.h
diff -u linux/include/asm-sh/posix_types.h:1.1.1.1 linux/include/asm-sh/posix_types.h:1.1.2.1
--- linux/include/asm-sh/posix_types.h:1.1.1.1 Sun Jan 30 22:21:10 2000
+++ linux/include/asm-sh/posix_types.h Sun Jan 30 22:56:34 2000
@@ -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;
Index: linux/include/asm-sh/siginfo.h
diff -u linux/include/asm-sh/siginfo.h:1.1.1.1 linux/include/asm-sh/siginfo.h:1.1.2.1
--- linux/include/asm-sh/siginfo.h:1.1.1.1 Sun Jan 30 22:21:10 2000
+++ linux/include/asm-sh/siginfo.h Sun Jan 30 22:56:34 2000
@@ -29,8 +29,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -67,6 +68,7 @@
  */
 #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
@@ -89,8 +91,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
Index: linux/include/asm-sparc/posix_types.h
diff -u linux/include/asm-sparc/posix_types.h:1.1.1.2 linux/include/asm-sparc/posix_types.h:1.1.2.2
--- linux/include/asm-sparc/posix_types.h:1.1.1.2 Sun Jan 30 22:22:55 2000
+++ linux/include/asm-sparc/posix_types.h Mon Jan 31 00:26:19 2000
@@ -13,6 +13,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_pid_t;
 typedef unsigned short __kernel_ipc_pid_t;
 typedef unsigned short __kernel_uid_t;
Index: linux/include/asm-sparc/siginfo.h
diff -u linux/include/asm-sparc/siginfo.h:1.1.1.3 linux/include/asm-sparc/siginfo.h:1.1.2.3
--- linux/include/asm-sparc/siginfo.h:1.1.1.3 Mon Feb 7 21:20:12 2000
+++ linux/include/asm-sparc/siginfo.h Mon Feb 7 21:50:36 2000
@@ -31,8 +31,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -70,6 +71,7 @@
  */
 #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
@@ -99,8 +101,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
Index: linux/include/asm-sparc/unistd.h
diff -u linux/include/asm-sparc/unistd.h:1.1.1.4 linux/include/asm-sparc/unistd.h:1.1.2.3
--- linux/include/asm-sparc/unistd.h:1.1.1.4 Mon Feb 7 21:20:12 2000
+++ linux/include/asm-sparc/unistd.h Mon Feb 7 21:50:36 2000
@@ -184,11 +184,11 @@
 /* #define __NR_exportfs 166 SunOS Specific */
 #define __NR_mount 167 /* Common */
 #define __NR_ustat 168 /* Common */
-/* #define __NR_semsys 169 SunOS Specific */
-/* #define __NR_msgsys 170 SunOS Specific */
-/* #define __NR_shmsys 171 SunOS Specific */
-/* #define __NR_auditsys 172 SunOS Specific */
-/* #define __NR_rfssys 173 SunOS Specific */
+#define __NR_timer_create 169 /* Linux Specific, semsys under SunOS */
+#define __NR_timer_settime 170 /* Linux Specific, msgsys under SunOS */
+#define __NR_timer_gettime 171 /* Linux Specific, shmsys under SunOS */
+#define __NR_timer_getoverrun 172 /* Linux Specific, auditsys under SunOS */
+#define __NR_timer_delete 173 /* Linux Specific, rfssys under SunOS */
 #define __NR_getdents 174 /* Common */
 #define __NR_setsid 175 /* Common */
 #define __NR_fchdir 176 /* Common */
@@ -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) \
Index: linux/include/asm-sparc64/posix_types.h
diff -u linux/include/asm-sparc64/posix_types.h:1.1.1.2 linux/include/asm-sparc64/posix_types.h:1.1.2.2
--- linux/include/asm-sparc64/posix_types.h:1.1.1.2 Sun Jan 30 22:22:58 2000
+++ linux/include/asm-sparc64/posix_types.h Mon Jan 31 00:26:20 2000
@@ -17,6 +17,8 @@
 typedef long __kernel_ptrdiff_t;
 typedef long __kernel_time_t;
 typedef long __kernel_clock_t;
+typedef int __kernel_timer_t;
+typedef int __kernel_clockid_t;
 typedef int __kernel_pid_t;
 typedef int __kernel_ipc_pid_t;
 typedef unsigned int __kernel_uid_t;
@@ -72,6 +74,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)
 
Index: linux/include/asm-sparc64/siginfo.h
diff -u linux/include/asm-sparc64/siginfo.h:1.1.1.2 linux/include/asm-sparc64/siginfo.h:1.1.2.2
--- linux/include/asm-sparc64/siginfo.h:1.1.1.2 Sun Jan 30 22:25:10 2000
+++ linux/include/asm-sparc64/siginfo.h Mon Jan 31 00:26:20 2000
@@ -37,8 +37,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t _tid; /* timer id */
+ int _pad; /* padding */
+ sigval_t _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -89,8 +90,9 @@
 
                 /* POSIX.1b timers */
                 struct {
- unsigned int _timer1;
- unsigned int _timer2;
+ timer_t32 _tid; /* timer id */
+ int _pad /* padding */
+ sigval_t32 _sigval; /* same as below */
                 } _timer;
 
                 /* POSIX.1b signals */
@@ -130,6 +132,7 @@
  */
 #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
@@ -159,8 +162,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
Index: linux/include/asm-sparc64/unistd.h
diff -u linux/include/asm-sparc64/unistd.h:1.1.1.4 linux/include/asm-sparc64/unistd.h:1.1.2.3
--- linux/include/asm-sparc64/unistd.h:1.1.1.4 Mon Feb 7 21:20:14 2000
+++ linux/include/asm-sparc64/unistd.h Mon Feb 7 21:50:37 2000
@@ -184,11 +184,11 @@
 /* #define __NR_exportfs 166 SunOS Specific */
 #define __NR_mount 167 /* Common */
 #define __NR_ustat 168 /* Common */
-/* #define __NR_semsys 169 SunOS Specific */
-/* #define __NR_msgsys 170 SunOS Specific */
-/* #define __NR_shmsys 171 SunOS Specific */
-/* #define __NR_auditsys 172 SunOS Specific */
-/* #define __NR_rfssys 173 SunOS Specific */
+#define __NR_timer_create 169 /* Linux Specific, semsys under SunOS */
+#define __NR_timer_settime 170 /* Linux Specific, msgsys under SunOS */
+#define __NR_timer_gettime 171 /* Linux Specific, shmsys under SunOS */
+#define __NR_timer_getoverrun 172 /* Linux Specific, auditsys under SunOS */
+#define __NR_timer_delete 173 /* Linux Specific, rfssys under SunOS */
 #define __NR_getdents 174 /* Common */
 #define __NR_setsid 175 /* Common */
 #define __NR_fchdir 176 /* Common */
@@ -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) \
Index: linux/include/linux/limits.h
diff -u linux/include/linux/limits.h:1.1.1.1 linux/include/linux/limits.h:1.1.2.1
--- linux/include/linux/limits.h:1.1.1.1 Sun Jan 30 22:21:03 2000
+++ linux/include/linux/limits.h Sun Jan 30 22:56:36 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
Index: linux/include/linux/sched.h
diff -u linux/include/linux/sched.h:1.1.1.2 linux/include/linux/sched.h:1.1.2.2
--- linux/include/linux/sched.h:1.1.1.2 Sun Jan 30 22:22:48 2000
+++ linux/include/linux/sched.h Mon Jan 31 00:26:22 2000
@@ -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
@@ -258,6 +259,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 */
@@ -315,6 +338,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 */ 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, \
@@ -709,6 +734,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);
 
Index: linux/include/linux/time.h
diff -u linux/include/linux/time.h:1.1.1.1 linux/include/linux/time.h:1.1.2.1
--- linux/include/linux/time.h:1.1.1.1 Sun Jan 30 22:21:03 2000
+++ linux/include/linux/time.h Sun Jan 30 22:56:36 2000
@@ -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
Index: linux/include/linux/types.h
diff -u linux/include/linux/types.h:1.1.1.2 linux/include/linux/types.h:1.1.2.2
--- linux/include/linux/types.h:1.1.1.2 Sun Jan 30 22:22:49 2000
+++ linux/include/linux/types.h Mon Jan 31 00:26:23 2000
@@ -17,6 +17,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;
Index: linux/kernel/exit.c
diff -u linux/kernel/exit.c:1.1.1.3 linux/kernel/exit.c:1.1.2.3
--- linux/kernel/exit.c:1.1.1.3 Mon Feb 7 21:20:27 2000
+++ linux/kernel/exit.c Mon Feb 7 21:50:37 2000
@@ -262,6 +262,21 @@
         mmdrop(active_mm);
 }
 
+static inline void __exit_itimers(struct task_struct *tsk)
+{
+ struct itimer_struct *timers = tsk->posix_timers;
+
+ if (timers) {
+ itimer_struct_delete(timers);
+ tsk->posix_timers = NULL;
+ }
+}
+
+void exit_itimers(struct task_struct *tsk)
+{
+ __exit_itimers(tsk);
+}
+
 /*
  * Turn us into a lazy TLB process if we
  * aren't already..
@@ -408,6 +423,7 @@
         __exit_files(tsk);
         __exit_fs(tsk);
         __exit_sighand(tsk);
+ __exit_itimers(tsk);
         exit_thread();
         tsk->state = TASK_ZOMBIE;
         tsk->exit_code = code;
Index: linux/kernel/fork.c
diff -u linux/kernel/fork.c:1.1.1.1 linux/kernel/fork.c:1.1.2.1
--- linux/kernel/fork.c:1.1.1.1 Sun Jan 30 22:21:03 2000
+++ linux/kernel/fork.c Sun Jan 30 22:56:38 2000
@@ -582,6 +582,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
@@ -689,6 +706,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);
@@ -738,6 +757,8 @@
                 down(&sem);
         return retval;
 
+bad_fork_cleanup_itimers:
+ exit_itimers(p);
 bad_fork_cleanup_sighand:
         exit_sighand(p);
 bad_fork_cleanup_fs:
Index: linux/kernel/itimer.c
diff -u linux/kernel/itimer.c:1.1.1.1 linux/kernel/itimer.c:1.1.2.1
--- linux/kernel/itimer.c:1.1.1.1 Sun Jan 30 22:21:03 2000
+++ linux/kernel/itimer.c Sun Jan 30 22:56:38 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
@@ -166,6 +168,423 @@
                 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;
+}
+
+void itimer_struct_delete(struct itimer_struct *timers)
+{
+ int i;
+ struct k_itimer *timr;
+
+ if (atomic_dec_and_test(&timers->count)) {
+ 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);
+ }
+}
+
+
+
+/* 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;
+ }
+
+ /* 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;
+ 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;
 }
Index: linux/kernel/signal.c
diff -u linux/kernel/signal.c:1.1.1.3 linux/kernel/signal.c:1.1.2.2
--- linux/kernel/signal.c:1.1.1.3 Sun Jan 30 22:24:57 2000
+++ linux/kernel/signal.c Mon Jan 31 00:26:25 2000
@@ -298,6 +298,23 @@
         if (sig < SIGRTMIN && sigismember(&t->signal, sig))
                 goto out;
 
+ /* 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;
+ }
+ }
+ }
+
         /* Real-time signals must be queued if sent by sigqueue, or
            some other real-time mechanism. It is implementation
            defined whether kill() does so. We attempt to do so, on

-- 
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/



This archive was generated by hypermail 2b29 : Tue Feb 15 2000 - 21:00:13 EST