Hi Linus,
Please accept this patch for inclusion. The impact on the kernel is
negligible and it makes the kernel a bit more POSIX feature complete. I
have received good feedback from people who have used the patch and I have
used it a lot myself without any problems.
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.
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
up to 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.
There have been no changes to the code for almost half a year now. The code
has been shown to work on UP and SMP on x86 platforms. There is (untested)
support for most other platforms. This support is just the addition of the
system calls to the architecture dependent tables.
The patch is attached to this mail.
The change relative to the previous version (2.4.0) is only that the patch
now applies cleanly to 2.4.1.
Test code and some other patches can be found on:
http://www.rhdv.cistron.nl/posix.html
Robert
-- Robert de Vries rhdv@rhdv.cistron.nl--------------Boundary-00=_DTL639RQTGFJYIYC2N4R Content-Type: text/x-c; name="2.4.1.timer.patch" Content-Transfer-Encoding: 8bit Content-Description: POSIX timer support for 2.4.1 Content-Disposition: attachment; filename="2.4.1.timer.patch"
Index: linux/arch/alpha/kernel/entry.S diff -u linux/arch/alpha/kernel/entry.S:1.1.1.11 linux/arch/alpha/kernel/entry.S:1.1.2.9 --- linux/arch/alpha/kernel/entry.S:1.1.1.11 Sat Sep 9 12:47:21 2000 +++ linux/arch/alpha/kernel/entry.S Sun Sep 10 13:18:04 2000 @@ -1161,3 +1161,8 @@ .quad sys_mincore /* 375 */ .quad sys_pciconfig_iobase .quad sys_getdents64 + .quad sys_timer_create + .quad sys_timer_settime + .quad sys_timer_gettime /* 380 */ + .quad sys_timer_getoverrun + .quad sys_timer_delete Index: linux/arch/alpha/kernel/signal.c diff -u linux/arch/alpha/kernel/signal.c:1.1.1.5 linux/arch/alpha/kernel/signal.c:1.1.2.5 --- linux/arch/alpha/kernel/signal.c:1.1.1.5 Thu Feb 1 18:53:35 2001 +++ linux/arch/alpha/kernel/signal.c Thu Feb 1 19:13:27 2001 @@ -52,6 +52,10 @@ err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo); err |= __put_user((short)from->si_code, &to->si_code); switch (from->si_code >> 16) { + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/arm/kernel/calls.S diff -u linux/arch/arm/kernel/calls.S:1.1.1.6 linux/arch/arm/kernel/calls.S:1.1.2.6 --- linux/arch/arm/kernel/calls.S:1.1.1.6 Tue Oct 3 22:46:23 2000 +++ linux/arch/arm/kernel/calls.S Tue Oct 3 23:09:45 2000 @@ -231,8 +231,13 @@ /* 215 */ .long SYMBOL_NAME(sys_setfsuid) .long SYMBOL_NAME(sys_setfsgid) .long SYMBOL_NAME(sys_getdents64) + .long SYMBOL_NAME(sys_timer_create) + .long SYMBOL_NAME(sys_timer_settime) +/* 220 */ .long SYMBOL_NAME(sys_timer_gettime) + .long SYMBOL_NAME(sys_timer_getoverrun) + .long SYMBOL_NAME(sys_timer_delete) - .rept NR_syscalls-217 + .rept NR_syscalls-222 .long SYMBOL_NAME(sys_ni_syscall) .endr #endif Index: linux/arch/arm/kernel/signal.c diff -u linux/arch/arm/kernel/signal.c:1.1.1.10 linux/arch/arm/kernel/signal.c:1.1.2.8 --- linux/arch/arm/kernel/signal.c:1.1.1.10 Thu Feb 1 18:54:07 2001 +++ linux/arch/arm/kernel/signal.c Thu Feb 1 19:13:28 2001 @@ -57,6 +57,10 @@ switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/i386/kernel/entry.S diff -u linux/arch/i386/kernel/entry.S:1.1.1.14 linux/arch/i386/kernel/entry.S:1.1.2.13 --- linux/arch/i386/kernel/entry.S:1.1.1.14 Mon Dec 4 22:31:17 2000 +++ linux/arch/i386/kernel/entry.S Tue Dec 12 20:53:37 2000 @@ -646,6 +646,11 @@ .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ + .long SYMBOL_NAME(sys_timer_create) + .long SYMBOL_NAME(sys_timer_settime) + .long SYMBOL_NAME(sys_timer_gettime) /* 225 */ + .long SYMBOL_NAME(sys_timer_getoverrun) + .long SYMBOL_NAME(sys_timer_delete) /* * NOTE!! This doesn't have to be exact - we just have @@ -653,6 +658,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-221 + .rept NR_syscalls-227 .long SYMBOL_NAME(sys_ni_syscall) .endr Index: linux/arch/i386/kernel/signal.c diff -u linux/arch/i386/kernel/signal.c:1.1.1.10 linux/arch/i386/kernel/signal.c:1.1.2.9 --- linux/arch/i386/kernel/signal.c:1.1.1.10 Thu Feb 1 18:53:32 2001 +++ linux/arch/i386/kernel/signal.c Thu Feb 1 19:13:29 2001 @@ -50,6 +50,10 @@ switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/ia64/kernel/entry.S diff -u linux/arch/ia64/kernel/entry.S:1.1.1.11 linux/arch/ia64/kernel/entry.S:1.1.4.11 --- linux/arch/ia64/kernel/entry.S:1.1.1.11 Thu Jan 11 21:35:31 2001 +++ linux/arch/ia64/kernel/entry.S Fri Jan 12 00:35:47 2001 @@ -1247,11 +1247,11 @@ data8 sys_newfstat data8 sys_clone2 data8 sys_getdents64 - data8 ia64_ni_syscall // 1215 - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_timer_create // 1215 + data8 sys_timer_settime + data8 sys_timer_gettime + data8 sys_timer_getoverrun + data8 sys_timer_delete data8 ia64_ni_syscall // 1220 data8 ia64_ni_syscall data8 ia64_ni_syscall Index: linux/arch/ia64/kernel/signal.c diff -u linux/arch/ia64/kernel/signal.c:1.1.1.7 linux/arch/ia64/kernel/signal.c:1.1.4.8 --- linux/arch/ia64/kernel/signal.c:1.1.1.7 Thu Jan 11 21:35:32 2001 +++ linux/arch/ia64/kernel/signal.c Fri Jan 12 00:35:48 2001 @@ -180,6 +180,10 @@ err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user((short)from->si_code, &to->si_code); switch (from->si_code >> 16) { + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_FAULT >> 16: err |= __put_user(from->si_isr, &to->si_isr); case __SI_POLL >> 16: Index: linux/arch/m68k/kernel/entry.S diff -u linux/arch/m68k/kernel/entry.S:1.1.1.6 linux/arch/m68k/kernel/entry.S:1.1.2.6 --- linux/arch/m68k/kernel/entry.S:1.1.1.6 Tue Dec 12 21:10:00 2000 +++ linux/arch/m68k/kernel/entry.S Tue Dec 12 20:53:42 2000 @@ -646,6 +646,11 @@ .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .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) /* 225 */ .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) Index: linux/arch/m68k/kernel/signal.c diff -u linux/arch/m68k/kernel/signal.c:1.1.1.7 linux/arch/m68k/kernel/signal.c:1.1.2.7 --- linux/arch/m68k/kernel/signal.c:1.1.1.7 Thu Feb 1 18:53:58 2001 +++ linux/arch/m68k/kernel/signal.c Thu Feb 1 19:13:31 2001 @@ -209,6 +209,10 @@ switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/mips/kernel/irix5sys.h diff -u linux/arch/mips/kernel/irix5sys.h:1.1.1.2 linux/arch/mips/kernel/irix5sys.h:1.1.2.2 --- linux/arch/mips/kernel/irix5sys.h:1.1.1.2 Wed May 24 18:58:03 2000 +++ linux/arch/mips/kernel/irix5sys.h Wed May 24 23:33:53 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/signal.c diff -u linux/arch/mips/kernel/signal.c:1.1.1.7 linux/arch/mips/kernel/signal.c:1.1.2.6 --- linux/arch/mips/kernel/signal.c:1.1.1.7 Thu Feb 1 18:53:41 2001 +++ linux/arch/mips/kernel/signal.c Thu Feb 1 19:13:33 2001 @@ -58,6 +58,10 @@ switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/mips/kernel/syscalls.h diff -u linux/arch/mips/kernel/syscalls.h:1.1.1.4 linux/arch/mips/kernel/syscalls.h:1.1.2.4 --- linux/arch/mips/kernel/syscalls.h:1.1.1.4 Thu Aug 24 20:40:03 2000 +++ linux/arch/mips/kernel/syscalls.h Thu Aug 24 21:12:36 2000 @@ -235,3 +235,8 @@ SYS(sys_mincore, 3) SYS(sys_madvise, 3) SYS(sys_getdents64, 3) +SYS(sys_timer_create, 3) /* 4220 */ +SYS(sys_timer_settime, 4) +SYS(sys_timer_gettime, 2) +SYS(sys_timer_getoverrun, 1) +SYS(sys_timer_delete, 1) Index: linux/arch/mips64/kernel/signal.c diff -u linux/arch/mips64/kernel/signal.c:1.1.1.6 linux/arch/mips64/kernel/signal.c:1.1.2.6 --- linux/arch/mips64/kernel/signal.c:1.1.1.6 Thu Feb 1 18:54:20 2001 +++ linux/arch/mips64/kernel/signal.c Thu Feb 1 19:13:34 2001 @@ -58,6 +58,10 @@ case __SI_FAULT >> 16: err |= __put_user((long)from->si_addr, &to->si_addr); break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/ppc/kernel/misc.S diff -u linux/arch/ppc/kernel/misc.S:1.1.1.14 linux/arch/ppc/kernel/misc.S:1.1.2.12 --- linux/arch/ppc/kernel/misc.S:1.1.1.14 Thu Feb 1 18:53:46 2001 +++ linux/arch/ppc/kernel/misc.S Thu Feb 1 19:13:37 2001 @@ -1298,6 +1298,11 @@ .long sys_fcntl64 /* 204 */ .long sys_madvise /* 205 */ .long sys_mincore /* 206 */ + .long sys_timer_create /* 207 */ + .long sys_timer_settime /* 208 */ + .long sys_timer_gettime /* 209 */ + .long sys_timer_getoverrun /* 210 */ + .long sys_timer_delete /* 211 */ .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall .endr Index: linux/arch/ppc/kernel/signal.c diff -u linux/arch/ppc/kernel/signal.c:1.1.1.6 linux/arch/ppc/kernel/signal.c:1.1.2.6 --- linux/arch/ppc/kernel/signal.c:1.1.1.6 Thu Feb 1 18:53:47 2001 +++ linux/arch/ppc/kernel/signal.c Thu Feb 1 19:13:39 2001 @@ -76,6 +76,10 @@ switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/s390/kernel/entry.S diff -u linux/arch/s390/kernel/entry.S:1.1.1.3 linux/arch/s390/kernel/entry.S:1.1.2.4 --- linux/arch/s390/kernel/entry.S:1.1.1.3 Thu Aug 24 20:40:27 2000 +++ linux/arch/s390/kernel/entry.S Thu Aug 24 21:12:39 2000 @@ -604,7 +604,12 @@ .long sys_mincore .long sys_madvise .long sys_getdents64 /* 220 */ - .rept 255-220 + .long sys_timer_create + .long sys_timer_settime + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete /* 225 */ + .rept 255-225 .long sys_ni_syscall .endr Index: linux/arch/sh/kernel/signal.c diff -u linux/arch/sh/kernel/signal.c:1.1.1.10 linux/arch/sh/kernel/signal.c:1.1.2.10 --- linux/arch/sh/kernel/signal.c:1.1.1.10 Thu Feb 1 18:54:12 2001 +++ linux/arch/sh/kernel/signal.c Thu Feb 1 19:13:42 2001 @@ -53,6 +53,10 @@ switch (from->si_code >> 16) { case __SI_FAULT >> 16: break; + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/sparc/kernel/signal.c diff -u linux/arch/sparc/kernel/signal.c:1.1.1.10 linux/arch/sparc/kernel/signal.c:1.1.2.9 --- linux/arch/sparc/kernel/signal.c:1.1.1.10 Thu Feb 1 18:53:38 2001 +++ linux/arch/sparc/kernel/signal.c Thu Feb 1 19:13:43 2001 @@ -110,6 +110,10 @@ err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user((short)from->si_code, &to->si_code); switch (from->si_code >> 16) { + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/sparc/kernel/systbls.S diff -u linux/arch/sparc/kernel/systbls.S:1.1.1.10 linux/arch/sparc/kernel/systbls.S:1.1.2.9 --- linux/arch/sparc/kernel/systbls.S:1.1.1.10 Thu Aug 24 20:40:15 2000 +++ linux/arch/sparc/kernel/systbls.S Thu Aug 24 21:12:40 2000 @@ -51,8 +51,8 @@ /*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64 /*155*/ .long sys_fcntl64, 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/signal.c diff -u linux/arch/sparc64/kernel/signal.c:1.1.1.8 linux/arch/sparc64/kernel/signal.c:1.1.2.7 --- linux/arch/sparc64/kernel/signal.c:1.1.1.8 Thu Feb 1 18:54:03 2001 +++ linux/arch/sparc64/kernel/signal.c Thu Feb 1 19:13:45 2001 @@ -56,6 +56,10 @@ err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo); err |= __put_user((short)from->si_code, &to->si_code); switch (from->si_code >> 16) { + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); Index: linux/arch/sparc64/kernel/sys_sparc32.c diff -u linux/arch/sparc64/kernel/sys_sparc32.c:1.1.1.27 linux/arch/sparc64/kernel/sys_sparc32.c:1.1.2.23 --- linux/arch/sparc64/kernel/sys_sparc32.c:1.1.1.27 Thu Feb 1 18:54:02 2001 +++ linux/arch/sparc64/kernel/sys_sparc32.c Thu Feb 1 19:13:45 2001 @@ -4213,3 +4213,113 @@ } return error; } + +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.12 linux/arch/sparc64/kernel/systbls.S:1.1.2.11 --- linux/arch/sparc64/kernel/systbls.S:1.1.1.12 Thu Aug 24 20:40:19 2000 +++ linux/arch/sparc64/kernel/systbls.S Thu Aug 24 21:12:42 2000 @@ -52,8 +52,8 @@ /*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64 .word sys32_fcntl64, 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, sparc64_newuname @@ -111,8 +111,8 @@ /*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64 .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, sparc64_newuname Index: linux/fs/exec.c diff -u linux/fs/exec.c:1.1.1.22 linux/fs/exec.c:1.1.2.19 --- linux/fs/exec.c:1.1.1.22 Thu Feb 1 18:49:50 2001 +++ linux/fs/exec.c Thu Feb 1 19:14:22 2001 @@ -570,6 +570,7 @@ flush_signal_handlers(current); flush_old_files(current->files); + exit_itimers(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.3 linux/include/asm-alpha/siginfo.h:1.1.2.4 --- linux/include/asm-alpha/siginfo.h:1.1.1.3 Tue Jun 27 19:31:42 2000 +++ linux/include/asm-alpha/siginfo.h Fri Jul 21 20:39:07 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 @@ -85,7 +87,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-alpha/unistd.h diff -u linux/include/asm-alpha/unistd.h:1.1.1.6 linux/include/asm-alpha/unistd.h:1.1.2.5 --- linux/include/asm-alpha/unistd.h:1.1.1.6 Thu Feb 1 18:50:38 2001 +++ linux/include/asm-alpha/unistd.h Thu Feb 1 19:14:28 2001 @@ -315,6 +315,11 @@ #define __NR_mincore 375 #define __NR_pciconfig_iobase 376 #define __NR_getdents64 377 +#define __NR_timer_create 378 +#define __NR_timer_settime 379 +#define __NR_timer_gettime 380 +#define __NR_timer_getoverrun 381 +#define __NR_timer_delete 382 #if defined(__GNUC__) Index: linux/include/asm-arm/posix_types.h diff -u linux/include/asm-arm/posix_types.h:1.1.1.3 linux/include/asm-arm/posix_types.h:1.1.2.3 --- linux/include/asm-arm/posix_types.h:1.1.1.3 Tue Oct 3 22:43:24 2000 +++ linux/include/asm-arm/posix_types.h Tue Oct 3 23:11:28 2000 @@ -34,6 +34,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.3 linux/include/asm-arm/siginfo.h:1.1.2.4 --- linux/include/asm-arm/siginfo.h:1.1.1.3 Tue Jun 27 19:31:43 2000 +++ linux/include/asm-arm/siginfo.h Fri Jul 21 20:39:07 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 @@ -85,7 +87,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-arm/unistd.h diff -u linux/include/asm-arm/unistd.h:1.1.1.5 linux/include/asm-arm/unistd.h:1.1.2.5 --- linux/include/asm-arm/unistd.h:1.1.1.5 Thu Aug 24 20:42:27 2000 +++ linux/include/asm-arm/unistd.h Thu Aug 24 21:13:28 2000 @@ -224,6 +224,11 @@ #define __NR_setfsuid32 (__NR_SYSCALL_BASE+215) #define __NR_setfsgid32 (__NR_SYSCALL_BASE+216) #define __NR_getdents64 (__NR_SYSCALL_BASE+217) +#define __NR_timer_create (__NR_SYSCALL_BASE+218) +#define __NR_timer_settime (__NR_SYSCALL_BASE+219) +#define __NR_timer_gettime (__NR_SYSCALL_BASE+220) +#define __NR_timer_getoverrun (__NR_SYSCALL_BASE+221) +#define __NR_timer_delete (__NR_SYSCALL_BASE+222) #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.3 linux/include/asm-i386/siginfo.h:1.1.2.4 --- linux/include/asm-i386/siginfo.h:1.1.1.3 Tue Jun 27 19:31:47 2000 +++ linux/include/asm-i386/siginfo.h Fri Jul 21 20:39:08 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 @@ -85,7 +87,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-i386/unistd.h diff -u linux/include/asm-i386/unistd.h:1.1.1.4 linux/include/asm-i386/unistd.h:1.1.2.5 --- linux/include/asm-i386/unistd.h:1.1.1.4 Thu Aug 24 20:42:32 2000 +++ linux/include/asm-i386/unistd.h Tue Oct 3 23:11:34 2000 @@ -227,6 +227,11 @@ #define __NR_madvise1 219 /* delete when C lib stub is removed */ #define __NR_getdents64 220 #define __NR_fcntl64 221 +#define __NR_timer_create 223 +#define __NR_timer_settime 224 +#define __NR_timer_gettime 225 +#define __NR_timer_getoverrun 226 +#define __NR_timer_delete 227 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */ Index: linux/include/asm-ia64/posix_types.h diff -u linux/include/asm-ia64/posix_types.h:1.1.1.1 linux/include/asm-ia64/posix_types.h:1.1.4.2 --- linux/include/asm-ia64/posix_types.h:1.1.1.1 Sat Feb 12 10:18:57 2000 +++ linux/include/asm-ia64/posix_types.h Sun Mar 26 22:21:10 2000 @@ -26,6 +26,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-ia64/siginfo.h diff -u linux/include/asm-ia64/siginfo.h:1.1.1.6 linux/include/asm-ia64/siginfo.h:1.1.4.7 --- linux/include/asm-ia64/siginfo.h:1.1.1.6 Sat Nov 4 18:11:32 2000 +++ linux/include/asm-ia64/siginfo.h Mon Nov 6 17:11:58 2000 @@ -33,8 +33,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 */ @@ -74,6 +75,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 @@ -98,7 +100,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-ia64/unistd.h diff -u linux/include/asm-ia64/unistd.h:1.1.1.7 linux/include/asm-ia64/unistd.h:1.1.4.8 --- linux/include/asm-ia64/unistd.h:1.1.1.7 Thu Jan 11 21:32:42 2001 +++ linux/include/asm-ia64/unistd.h Fri Jan 12 00:37:13 2001 @@ -204,6 +204,11 @@ #define __NR_fstat 1212 #define __NR_clone2 1213 #define __NR_getdents64 1214 +#define __NR_timer_create 1215 +#define __NR_timer_settime 1216 +#define __NR_timer_gettime 1217 +#define __NR_timer_getoverrun 1218 +#define __NR_timer_delete 1219 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) 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.4 linux/include/asm-m68k/siginfo.h:1.1.2.5 --- linux/include/asm-m68k/siginfo.h:1.1.1.4 Tue Dec 12 21:06:40 2000 +++ linux/include/asm-m68k/siginfo.h Tue Dec 12 20:55:23 2000 @@ -30,8 +30,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 */ @@ -77,6 +78,7 @@ #else #define si_uid _sifields._kill._uid #endif /* __KERNEL__ */ +#define si_tid _sifields._timer._tid #define si_status _sifields._sigchld._status #define si_utime _sifields._sigchld._utime #define si_stime _sifields._sigchld._stime @@ -95,7 +97,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-m68k/unistd.h diff -u linux/include/asm-m68k/unistd.h:1.1.1.3 linux/include/asm-m68k/unistd.h:1.1.2.3 --- linux/include/asm-m68k/unistd.h:1.1.1.3 Tue Dec 12 21:06:39 2000 +++ linux/include/asm-m68k/unistd.h Tue Dec 12 20:55:25 2000 @@ -222,6 +222,11 @@ #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 #define __NR_getdents64 220 +#define __NR_timer_create 221 +#define __NR_timer_settime 222 +#define __NR_timer_gettime 223 +#define __NR_timer_getoverrun 224 +#define __NR_timer_delete 225 /* 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.4 linux/include/asm-mips/posix_types.h:1.1.2.4 --- linux/include/asm-mips/posix_types.h:1.1.1.4 Wed Jul 12 21:49:57 2000 +++ linux/include/asm-mips/posix_types.h Wed Jul 12 22:15:35 2000 @@ -32,6 +32,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; typedef unsigned short __kernel_uid16_t; typedef unsigned short __kernel_gid16_t; Index: linux/include/asm-mips/siginfo.h diff -u linux/include/asm-mips/siginfo.h:1.1.1.5 linux/include/asm-mips/siginfo.h:1.1.2.6 --- linux/include/asm-mips/siginfo.h:1.1.1.5 Tue Jun 27 19:31:51 2000 +++ linux/include/asm-mips/siginfo.h Fri Jul 21 20:39:09 2000 @@ -68,8 +68,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 */ @@ -87,6 +88,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 @@ -105,7 +107,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-mips/unistd.h diff -u linux/include/asm-mips/unistd.h:1.1.1.4 linux/include/asm-mips/unistd.h:1.1.2.4 --- linux/include/asm-mips/unistd.h:1.1.1.4 Thu Aug 24 20:42:35 2000 +++ linux/include/asm-mips/unistd.h Thu Aug 24 21:13:32 2000 @@ -1206,11 +1206,16 @@ #define __NR_mincore (__NR_Linux + 217) #define __NR_madvise (__NR_Linux + 218) #define __NR_getdents64 (__NR_Linux + 219) +#define __NR_timer_create (__NR_Linux + 220) +#define __NR_timer_settime (__NR_Linux + 221) +#define __NR_timer_gettime (__NR_Linux + 222) +#define __NR_timer_getoverrun (__NR_Linux + 223) +#define __NR_timer_delete (__NR_Linux + 224) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 219 +#define __NR_Linux_syscalls 224 #ifndef _LANGUAGE_ASSEMBLY Index: linux/include/asm-mips64/siginfo.h diff -u linux/include/asm-mips64/siginfo.h:1.1.1.3 linux/include/asm-mips64/siginfo.h:1.1.2.4 --- linux/include/asm-mips64/siginfo.h:1.1.1.3 Tue Jun 27 19:32:13 2000 +++ linux/include/asm-mips64/siginfo.h Fri Jul 21 20:39:09 2000 @@ -68,8 +68,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 */ @@ -87,6 +88,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 @@ -105,7 +107,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-ppc/posix_types.h diff -u linux/include/asm-ppc/posix_types.h:1.1.1.5 linux/include/asm-ppc/posix_types.h:1.1.2.5 --- linux/include/asm-ppc/posix_types.h:1.1.1.5 Tue Jun 27 19:31:53 2000 +++ linux/include/asm-ppc/posix_types.h Wed Jul 12 22:15:38 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.5 linux/include/asm-ppc/siginfo.h:1.1.2.5 --- linux/include/asm-ppc/siginfo.h:1.1.1.5 Mon Dec 4 22:28:45 2000 +++ linux/include/asm-ppc/siginfo.h Tue Dec 12 20:55:32 2000 @@ -27,8 +27,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 */ @@ -65,6 +66,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 @@ -83,7 +85,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-ppc/unistd.h diff -u linux/include/asm-ppc/unistd.h:1.1.1.6 linux/include/asm-ppc/unistd.h:1.1.2.6 --- linux/include/asm-ppc/unistd.h:1.1.1.6 Thu Feb 1 18:50:50 2001 +++ linux/include/asm-ppc/unistd.h Thu Feb 1 19:14:32 2001 @@ -210,6 +210,11 @@ #define __NR_fcntl64 204 #define __NR_madvise 205 #define __NR_mincore 206 +#define __NR_timer_create 207 +#define __NR_timer_settime 208 +#define __NR_timer_gettime 209 +#define __NR_timer_getoverrun 210 +#define __NR_timer_delete 211 #define __NR(n) #n Index: linux/include/asm-s390/siginfo.h diff -u linux/include/asm-s390/siginfo.h:1.1.1.1 linux/include/asm-s390/siginfo.h:1.1.2.2 --- linux/include/asm-s390/siginfo.h:1.1.1.1 Sat May 13 01:04:16 2000 +++ linux/include/asm-s390/siginfo.h Fri Jul 21 20:37:01 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 Index: linux/include/asm-s390/unistd.h diff -u linux/include/asm-s390/unistd.h:1.1.1.2 linux/include/asm-s390/unistd.h:1.1.2.3 --- linux/include/asm-s390/unistd.h:1.1.1.2 Thu Aug 24 20:43:04 2000 +++ linux/include/asm-s390/unistd.h Thu Aug 24 21:13:35 2000 @@ -209,7 +209,11 @@ #define __NR_mincore 218 #define __NR_madvise 219 #define __NR_getdents64 220 - +#define __NR_timer_create 221 +#define __NR_timer_settime 222 +#define __NR_timer_gettime 223 +#define __NR_timer_getoverrun 224 +#define __NR_timer_delete 225 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */ Index: linux/include/asm-sh/posix_types.h diff -u linux/include/asm-sh/posix_types.h:1.1.1.2 linux/include/asm-sh/posix_types.h:1.1.2.2 --- linux/include/asm-sh/posix_types.h:1.1.1.2 Sat Mar 11 11:12:59 2000 +++ linux/include/asm-sh/posix_types.h Sun Mar 12 13:17:28 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; typedef unsigned short __kernel_uid16_t; typedef unsigned short __kernel_gid16_t; typedef unsigned int __kernel_uid32_t; Index: linux/include/asm-sh/siginfo.h diff -u linux/include/asm-sh/siginfo.h:1.1.1.4 linux/include/asm-sh/siginfo.h:1.1.2.5 --- linux/include/asm-sh/siginfo.h:1.1.1.4 Thu Jan 11 21:32:38 2001 +++ linux/include/asm-sh/siginfo.h Fri Jan 12 00:37:22 2001 @@ -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 @@ -85,7 +87,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 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.4 linux/include/asm-sparc/siginfo.h:1.1.2.5 --- linux/include/asm-sparc/siginfo.h:1.1.1.4 Tue Jun 27 19:31:56 2000 +++ linux/include/asm-sparc/siginfo.h Fri Jul 21 20:39:12 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 @@ -89,7 +91,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-sparc/unistd.h diff -u linux/include/asm-sparc/unistd.h:1.1.1.5 linux/include/asm-sparc/unistd.h:1.1.2.4 --- linux/include/asm-sparc/unistd.h:1.1.1.5 Thu Aug 24 20:42:42 2000 +++ linux/include/asm-sparc/unistd.h Thu Aug 24 21:13: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.4 linux/include/asm-sparc64/posix_types.h:1.1.2.4 --- linux/include/asm-sparc64/posix_types.h:1.1.1.4 Sat Nov 4 18:11:21 2000 +++ linux/include/asm-sparc64/posix_types.h Mon Nov 6 17:12:06 2000 @@ -12,6 +12,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; @@ -67,6 +69,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.4 linux/include/asm-sparc64/siginfo.h:1.1.2.5 --- linux/include/asm-sparc64/siginfo.h:1.1.1.4 Tue Jun 27 19:31:58 2000 +++ linux/include/asm-sparc64/siginfo.h Fri Jul 21 20:39:13 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 @@ -149,7 +152,7 @@ #define __SI_FAULT (3 << 16) #define __SI_CHLD (4 << 16) #define __SI_RT (5 << 16) -#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) #else #define __SI_KILL 0 #define __SI_TIMER 0 Index: linux/include/asm-sparc64/unistd.h diff -u linux/include/asm-sparc64/unistd.h:1.1.1.6 linux/include/asm-sparc64/unistd.h:1.1.2.5 --- linux/include/asm-sparc64/unistd.h:1.1.1.6 Thu Aug 24 20:42:45 2000 +++ linux/include/asm-sparc64/unistd.h Thu Aug 24 21:13: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 */ @@ -273,6 +273,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.20 linux/include/linux/sched.h:1.1.2.19 --- linux/include/linux/sched.h:1.1.1.20 Thu Feb 1 18:50:20 2001 +++ linux/include/linux/sched.h Thu Feb 1 19:14:38 2001 @@ -40,6 +40,7 @@ #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_THREAD 0x00010000 /* Same thread group? */ +#define CLONE_ITIMERS 0x00020000 /* set if POSIX.1b itimers are shared */ #define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD) @@ -275,6 +276,29 @@ extern struct user_struct root_user; #define INIT_USER (&root_user) +/* 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); +extern void itimer_struct_delete(struct itimer_struct *timers); + struct task_struct { /* * offsets of these are hardcoded elsewhere - touch with care @@ -346,6 +370,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]; @@ -460,6 +485,7 @@ real_timer: { \ function: it_real_fn \ }, \ + posix_timers: NULL, \ cap_effective: CAP_INIT_EFF_SET, \ cap_inheritable: CAP_INIT_INH_SET, \ cap_permitted: CAP_FULL_SET, \ @@ -743,6 +769,7 @@ extern void exit_mm(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.3 linux/include/linux/time.h:1.1.2.3 --- linux/include/linux/time.h:1.1.1.3 Mon Dec 4 22:28:15 2000 +++ linux/include/linux/time.h Tue Dec 12 20:55:41 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 @@ -28,6 +28,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) { @@ -36,15 +49,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; } @@ -127,5 +140,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.3 linux/include/linux/types.h:1.1.2.3 --- linux/include/linux/types.h:1.1.1.3 Sat Jul 15 11:41:56 2000 +++ linux/include/linux/types.h Sat Jul 15 11:53:20 2000 @@ -20,6 +20,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.20 linux/kernel/exit.c:1.1.2.18 --- linux/kernel/exit.c:1.1.1.20 Thu Jan 11 21:32:00 2001 +++ linux/kernel/exit.c Fri Jan 12 00:37:33 2001 @@ -294,6 +294,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.. @@ -441,6 +456,7 @@ sem_exit(); __exit_files(tsk); __exit_fs(tsk); + __exit_itimers(tsk); exit_sighand(tsk); exit_thread(); Index: linux/kernel/fork.c diff -u linux/kernel/fork.c:1.1.1.19 linux/kernel/fork.c:1.1.2.17 --- linux/kernel/fork.c:1.1.1.19 Thu Feb 1 18:50:18 2001 +++ linux/kernel/fork.c Thu Feb 1 19:14:42 2001 @@ -545,6 +545,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 also @@ -648,6 +665,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, stack_start, stack_size, p, regs); @@ -706,6 +725,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.3 linux/kernel/itimer.c:1.1.2.8 --- linux/kernel/itimer.c:1.1.1.3 Wed Jul 12 21:50:24 2000 +++ linux/kernel/itimer.c Sun Sep 10 13:19:04 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 @@ -165,6 +167,431 @@ 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; + } + } +} + +/* + * Notify the task and set up the timer for the next expiration (if applicable). + * This function requires that the k_itimer structure it_lock is taken. + */ +static void posix_timer_fire(struct k_itimer *timr) +{ + unsigned long interval; + + timer_notify_task(timr); + + /* Set up the timer for the next interval (if there is one) */ + if ((interval = timr->it_incr) == 0) return; + + if (interval > (unsigned long) LONG_MAX) + interval = LONG_MAX; + timr->it_timer.expires += interval; + add_timer(&timr->it_timer); +} + +/* + * This function gets called when a POSIX.1b interval timer expires. + * It is used as a callback from the kernel internal timer. + */ +static void posix_timer_fn(unsigned long __data) +{ + struct k_itimer *timr = (struct k_itimer *)__data; + + spin_lock(&timr->it_lock); + posix_timer_fire(timr); + 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) { + del_timer_sync(&timr->it_timer); + 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.list.next = NULL; + new_timer->it_timer.list.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_locked; + } + 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; + } + +out_locked: + 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. + */ + +static 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); + + if (copy_to_user(setting, &cur_setting, sizeof(cur_setting))) + return -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. */ +/* timr->it_lock is taken. */ +static void do_timer_settime(struct k_itimer *timr, int flags, + struct itimerspec *new_setting, + struct itimerspec *old_setting) +{ + /* disable the timer */ + del_timer_sync(&timr->it_timer); + + 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_fire(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; + + del_timer_sync(&timr->it_timer); + + spin_lock(¤t->posix_timers->its_lock); + + kfree(timr); + current->posix_timers->itimer[timer_id] = NULL; + + spin_unlock(¤t->posix_timers->its_lock); + return 0; } Index: linux/kernel/signal.c diff -u linux/kernel/signal.c:1.1.1.12 linux/kernel/signal.c:1.1.2.12 --- linux/kernel/signal.c:1.1.1.12 Thu Jan 11 21:32:00 2001 +++ linux/kernel/signal.c Fri Jan 12 00:37:34 2001 @@ -255,8 +255,6 @@ if (!collect_signal(sig, ¤t->pending, info)) sig = 0; - /* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER, - we need to xchg out the timer overrun values. */ } recalc_sigpending(current); @@ -540,6 +538,24 @@ the signal. */ if (sig < SIGRTMIN && sigismember(&t->pending.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 true, the overrun count will be increased in + itimer.c:posix_timer_fn(). */ + + if (((unsigned long)info > 1) && (info->si_code == SI_TIMER)) { + struct sigqueue *q; + for (q = t->pending.head; 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; + } + } + } ret = deliver_signal(sig, info, t); out:
--------------Boundary-00=_DTL639RQTGFJYIYC2N4R-- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/