diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- linux-2.5.41-x862/arch/i386/kernel/entry.S Mon Oct 7 15:35:59 2002 +++ linux/arch/i386/kernel/entry.S Mon Oct 7 17:46:04 2002 @@ -760,6 +760,15 @@ .long sys_alloc_hugepages /* 250 */ .long sys_free_hugepages .long sys_exit_group + .long sys_timer_create + .long sys_timer_settime + .long sys_timer_gettime /* 255 */ + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime + .long sys_clock_getres /* 260 */ + .long sys_clock_nanosleep .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- linux-2.5.41-x862/arch/i386/kernel/time.c Mon Oct 7 17:41:46 2002 +++ linux/arch/i386/kernel/time.c Mon Oct 7 17:46:04 2002 @@ -319,6 +319,7 @@ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; write_unlock_irq(&xtime_lock); + clock_was_set(); } /* diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/fs/exec.c linux/fs/exec.c --- linux-2.5.41-x862/fs/exec.c Thu Oct 3 10:42:09 2002 +++ linux/fs/exec.c Mon Oct 7 17:46:04 2002 @@ -756,6 +756,7 @@ flush_signal_handlers(current); flush_old_files(current->files); + exit_itimers(current); return 0; diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/asm-generic/siginfo.h linux/include/asm-generic/siginfo.h --- linux-2.5.41-x862/include/asm-generic/siginfo.h Mon Sep 9 10:35:06 2002 +++ linux/include/asm-generic/siginfo.h Mon Oct 7 17:46:04 2002 @@ -31,8 +31,9 @@ /* POSIX.1b timers */ struct { - unsigned int _timer1; - unsigned int _timer2; + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + sigval_t _sigval; /* same as below */ } _timer; /* POSIX.1b signals */ @@ -71,8 +72,8 @@ */ #define si_pid _sifields._kill._pid #define si_uid _sifields._kill._uid -#define si_timer1 _sifields._timer._timer1 -#define si_timer2 _sifields._timer._timer2 +#define si_tid _sifields._timer._tid +#define si_overrun _sifields._timer._overrun #define si_status _sifields._sigchld._status #define si_utime _sifields._sigchld._utime #define si_stime _sifields._sigchld._stime @@ -91,7 +92,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 @@ -203,6 +204,7 @@ #define SIGEV_SIGNAL 0 /* notify via signal */ #define SIGEV_NONE 1 /* other notification: meaningless */ #define SIGEV_THREAD 2 /* deliver via thread creation */ +#define SIGEV_THREAD_ID 4 /* deliver to thread */ #define SIGEV_MAX_SIZE 64 #ifndef SIGEV_PAD_SIZE @@ -217,6 +219,7 @@ int sigev_notify; union { int _pad[SIGEV_PAD_SIZE]; + int _tid; struct { void (*_function)(sigval_t); @@ -229,6 +232,7 @@ #define sigev_notify_function _sigev_un._sigev_thread._function #define sigev_notify_attributes _sigev_un._sigev_thread._attribute +#define sigev_notify_thread_id _sigev_un._tid #ifdef __KERNEL__ diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h --- linux-2.5.41-x862/include/asm-i386/posix_types.h Mon Sep 9 10:35:18 2002 +++ linux/include/asm-i386/posix_types.h Mon Oct 7 17:46:04 2002 @@ -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; diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/asm-i386/signal.h linux/include/asm-i386/signal.h --- linux-2.5.41-x862/include/asm-i386/signal.h Mon Oct 7 17:41:46 2002 +++ linux/include/asm-i386/signal.h Mon Oct 7 17:46:04 2002 @@ -238,7 +238,7 @@ * set in the register PRIOR to calling do_signal(). See our answer * below...thanks to Jim Houston */ -#define FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP_NOT +#define FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP #ifdef FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- linux-2.5.41-x862/include/asm-i386/unistd.h Mon Oct 7 15:24:26 2002 +++ linux/include/asm-i386/unistd.h Mon Oct 7 17:46:04 2002 @@ -257,6 +257,15 @@ #define __NR_alloc_hugepages 250 #define __NR_free_hugepages 251 #define __NR_exit_group 252 +#define __NR_timer_create 253 +#define __NR_timer_settime (__NR_timer_create+1) +#define __NR_timer_gettime (__NR_timer_create+2) +#define __NR_timer_getoverrun (__NR_timer_create+3) +#define __NR_timer_delete (__NR_timer_create+4) +#define __NR_clock_settime (__NR_timer_create+5) +#define __NR_clock_gettime (__NR_timer_create+6) +#define __NR_clock_getres (__NR_timer_create+7) +#define __NR_clock_nanosleep (__NR_timer_create+8) /* user-visible error numbers are in the range -1 - -124: see */ diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/linux/hrtime.h linux/include/linux/hrtime.h --- linux-2.5.41-x862/include/linux/hrtime.h Mon Oct 7 17:39:58 2002 +++ linux/include/linux/hrtime.h Mon Oct 7 17:46:04 2002 @@ -10,6 +10,20 @@ * arch defines the CONFIG, it had better have the * asm/hrtime.h file in place. */ +struct k_clock { + int res; /* in nano seconds */ + int ( *clock_set)(struct timespec *tp); + int ( *clock_get)(struct timespec *tp); + int ( *nsleep)( int flags, + struct timespec*new_setting, + struct itimerspec *old_setting); + int ( *timer_set)(struct k_itimer *timr, int flags, + struct itimerspec *new_setting, + struct itimerspec *old_setting); + int ( *timer_del)(struct k_itimer *timr); + void ( *timer_get)(struct k_itimer *timr, + struct itimerspec *cur_setting); +}; /* * This gets filled in at init time, either static or dynamic. diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/linux/init_task.h linux/include/linux/init_task.h --- linux-2.5.41-x862/include/linux/init_task.h Thu Oct 3 10:42:11 2002 +++ linux/include/linux/init_task.h Mon Oct 7 17:46:04 2002 @@ -93,6 +93,7 @@ .sig = &init_signals, \ .pending = { NULL, &tsk.pending.head, {{0}}}, \ .blocked = {{0}}, \ + .posix_timers = LIST_HEAD_INIT(tsk.posix_timers), \ .alloc_lock = SPIN_LOCK_UNLOCKED, \ .switch_lock = SPIN_LOCK_UNLOCKED, \ .journal_info = NULL, \ diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/linux/sched.h linux/include/linux/sched.h --- linux-2.5.41-x862/include/linux/sched.h Mon Oct 7 15:24:31 2002 +++ linux/include/linux/sched.h Mon Oct 7 17:46:04 2002 @@ -278,6 +278,30 @@ typedef struct prio_array prio_array_t; struct backing_dev_info; +/* POSIX.1b interval timer structure. */ +struct k_itimer { + struct list_head list; /* free/ allocate list */ + spinlock_t it_lock; + clockid_t it_clock; /* which timer type */ + timer_t it_id; /* timer id */ + int it_overrun; /* overrun on pending signal */ + int it_overrun_last; /* overrun on last delivered signal */ + int it_overrun_deferred; /* overrun on pending timer interrupt */ + int it_sigev_notify; /* notify word of sigevent struct */ + int it_sigev_signo; /* signo word of sigevent struct */ + sigval_t it_sigev_value; /* value word of sigevent struct */ + unsigned long it_incr; /* interval specified in jiffies */ +#ifdef CONFIG_HIGH_RES_TIMERS + int it_sub_incr; /* sub jiffie part of interval */ +#endif + struct task_struct *it_process; /* process to send signal to */ + struct timer_list it_timer; +}; + + +//extern struct itimer_struct *itimer_struct_new(void); +extern void itimer_delete(struct k_itimer *timers); + struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ struct thread_info *thread_info; @@ -343,6 +367,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 list_head posix_timers; /* POSIX.1b Interval Timers */ unsigned long utime, stime, cutime, cstime; unsigned long start_time; long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; @@ -651,6 +676,7 @@ extern void exit_mm(struct task_struct *); extern void exit_files(struct task_struct *); +extern void exit_itimers(struct task_struct *); extern void exit_sighand(struct task_struct *); extern void __exit_sighand(struct task_struct *); diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/linux/sys.h linux/include/linux/sys.h --- linux-2.5.41-x862/include/linux/sys.h Mon Sep 9 10:35:09 2002 +++ linux/include/linux/sys.h Mon Oct 7 17:46:04 2002 @@ -4,7 +4,7 @@ /* * system call entry points ... but not all are defined */ -#define NR_syscalls 256 +#define NR_syscalls 275 /* * These are system calls that will be removed at some time diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/linux/time.h linux/include/linux/time.h --- linux-2.5.41-x862/include/linux/time.h Mon Oct 7 17:39:58 2002 +++ linux/include/linux/time.h Mon Oct 7 17:46:04 2002 @@ -138,6 +138,7 @@ extern void do_gettimeofday(struct timeval *tv); extern void do_settimeofday(struct timeval *tv); extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); +extern void clock_was_set(void); // Function to call when ever the clock is set #endif #define FD_SETSIZE __FD_SETSIZE @@ -163,5 +164,25 @@ struct timeval it_interval; /* timer interval */ struct timeval it_value; /* current value */ }; + + +/* + * The IDs of the various system clocks (for POSIX.1b interval timers). + */ +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_REALTIME_HR 4 +#define CLOCK_MONOTONIC_HR 5 + +#define MAX_CLOCKS 6 + +/* + * The various flags for setting POSIX.1b interval timers. + */ + +#define TIMER_ABSTIME 0x01 + #endif diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/include/linux/types.h linux/include/linux/types.h --- linux-2.5.41-x862/include/linux/types.h Mon Oct 7 15:24:31 2002 +++ linux/include/linux/types.h Mon Oct 7 17:46:04 2002 @@ -23,6 +23,8 @@ typedef __kernel_daddr_t daddr_t; typedef __kernel_key_t key_t; typedef __kernel_suseconds_t suseconds_t; +typedef __kernel_timer_t timer_t; +typedef __kernel_clockid_t clockid_t; #ifdef __KERNEL__ typedef __kernel_uid32_t uid_t; diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/init/Config.help linux/init/Config.help --- linux-2.5.41-x862/init/Config.help Mon Oct 7 17:39:58 2002 +++ linux/init/Config.help Mon Oct 7 17:46:04 2002 @@ -124,4 +124,11 @@ timers and are more concerned about list insertion time than the extra memory usage. (The list size must be a power of 2.) - +Maximum number of POSIX timers +CONFIG_MAX_POSIX_TIMERS + This option allows you to configure the system wide maximum number of + POSIX timers. Timers are allocated as needed so the only memory + overhead this adds is about 4 bytes for every 50 or so timers to keep + track of each block of timers. The system quietly rounds this number + up to fill out a timer allocation block. It is ok to have several + thousand timers as needed by your applications. diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/init/Config.in linux/init/Config.in --- linux-2.5.41-x862/init/Config.in Mon Oct 7 17:39:58 2002 +++ linux/init/Config.in Mon Oct 7 17:46:04 2002 @@ -9,6 +9,7 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +int 'System wide maximum number of POSIX timers' CONFIG_MAX_POSIX_TIMERS 3000 choice 'Size of timer list?' \ "512 CONFIG_TIMERLIST_512 \ 1024 CONFIG_TIMERLIST_1k \ diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/kernel/exit.c linux/kernel/exit.c --- linux-2.5.41-x862/kernel/exit.c Fri Sep 27 17:05:18 2002 +++ linux/kernel/exit.c Mon Oct 7 17:46:04 2002 @@ -408,6 +408,21 @@ mmdrop(active_mm); } +static inline void __exit_itimers(struct task_struct *tsk) +{ + struct k_itimer *tmr; + + while (tsk->posix_timers.next != &tsk->posix_timers){ + tmr = list_entry(tsk->posix_timers.next,struct k_itimer,list); + itimer_delete(tmr); + } +} + +void exit_itimers(struct task_struct *tsk) +{ + __exit_itimers(tsk); +} + /* * Turn us into a lazy TLB process if we * aren't already.. @@ -643,6 +658,7 @@ __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); + __exit_itimers(tsk); exit_thread(); if (current->leader) diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/kernel/fork.c linux/kernel/fork.c --- linux-2.5.41-x862/kernel/fork.c Mon Oct 7 15:24:33 2002 +++ linux/kernel/fork.c Mon Oct 7 17:46:04 2002 @@ -781,6 +781,7 @@ goto bad_fork_cleanup_files; if (copy_sighand(clone_flags, p)) goto bad_fork_cleanup_fs; + INIT_LIST_HEAD(&p->posix_timers); if (copy_mm(clone_flags, p)) goto bad_fork_cleanup_sighand; if (copy_namespace(clone_flags, p)) diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/kernel/itimer.c linux/kernel/itimer.c --- linux-2.5.41-x862/kernel/itimer.c Mon Sep 9 10:35:09 2002 +++ linux/kernel/itimer.c Mon Oct 7 17:46:04 2002 @@ -2,6 +2,8 @@ * linux/kernel/itimer.c * * Copyright (C) 1992 Darren Senn + * 2002-8-13 High res timers by George Anzinger + * Copyright (C) 2002 by MontaVista Software. */ /* These are all the functions necessary to implement itimers */ @@ -9,9 +11,331 @@ #include #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include + +/* + * Management arrays for POSIX timers. Timers are kept in memory that + * is allocated a CHUNCK at a time. Pointers to the CHUNCKS are kept in + * an array of pointers. A bit map is kept of CHUNCKS that have free + * timers. Allocation is always made from the first CHUNCK that has a + * free timer. Timers in CHUNCKS are kept in a free list, which is + * unordered. A count of free timers in a CHUNCK is kept and when all + * timers in a CHUNCK are free, the CHUNCK memory is returned and the + * CHUNCK is marked empty in the bit map. The free slot in the CHUNCK + * array is linked into the free list for CHUNCK pointers. + */ +/* + * First lets abstract the memory interface. + */ +#define get_timer_chunck()(struct posix_timer_chunck *)__get_free_page(GFP_KERNEL) +#define free_timer_chunck(p) free_page((unsigned long)p) +#define POSIX_TIMERS_CHUNCK_SIZE (PAGE_SIZE) + +#undef NULL +#define NULL ((void *)0) +#define CONFIGURE_MIN_INTERVAL 500000 +/* + * Love to make this offsetof((struct posix_timer_chunck).timers) or + * some such but that is recursive... + */ +#define CHUNCK_OVERHEAD (sizeof(struct list_head) + sizeof(int) + sizeof(int)) +#define NUM_POSIX_TIMERS_PER_CHUNCK \ + ((POSIX_TIMERS_CHUNCK_SIZE - CHUNCK_OVERHEAD)/ sizeof(struct k_itimer)) + +struct posix_timer_chunck { + struct list_head free_list; + int used_count; + int index; + struct k_itimer timers[NUM_POSIX_TIMERS_PER_CHUNCK]; +}; + +#define NUM_CHUNCKS_POSIX_TIMERS \ + (1 + (CONFIG_MAX_POSIX_TIMERS / NUM_POSIX_TIMERS_PER_CHUNCK)) +#define MAX_POSIX_TIMERS NUM_CHUNCKS_POSIX_TIMERS * NUM_POSIX_TIMERS_PER_CHUNCK +#define CHUNCK_SHIFT 8 +#define CHUNCK_MASK ((1 << CHUNCK_SHIFT) - 1) + + +/* + * Just because the timer is not in the timer list does NOT mean it is + * inactive. It could be in the "fire" routine getting a new expire time. + */ +#define TIMER_INACTIVE 1 +#define TIMER_RETRY 1 +#ifdef CONFIG_SMP +#define timer_active(tmr) (tmr->it_timer.entry.prev != (void *)TIMER_INACTIVE) +#define set_timer_inactive(tmr) tmr->it_timer.entry.prev = (void *)TIMER_INACTIVE +#else +#define timer_active(tmr) BARFY // error to use outside of SMP +#define set_timer_inactive(tmr) +#endif +/* + * Lets talk. + * + * The following structure is the root of the posix timers data. The + * is taken when ever we are allocating or releasing a timer + * structure. Since we allocate memory for this, we use a semaphore + * (memory allocate can block). + * + * The is an array index into the array. If a + * is populated, the array element will point to a struct + * posix_timer_chunck which will be the allocated memory block. If the + * is not populated it will contain an array index to the next + * free , or if there are no more it will be + * NUM_CHUNCKS_POSIX_TIMERS, which is too high to be an array index + * (this fact is used to verify that a is populated and that we + * have reached the end of free . + * + * NOTE- We are not doing any post "settime" processing for abs timers at + * this time and so, these next two entries are not defined. + */ +#define IF_ABS_TIME_ADJ(a) +#if 0 // We are not doing this at this time (ever?). + /* + * The is a list of all active (some fudging on this, see the + * code) timers that are tagged as absolute. Active absolute timers + * need to have their expire time adjusted when ever the system time of + * day clock is set or adjusted. + * + * The is used to protect entries and exits from the . + * Since timer expiration is an interrupt driven event this spinlock must be + * an irq type. + */ +#endif +/* + * The array is described above. The timer ID is composed of + * the index and the array index of in that chunck. + * Verifying a valid ID consists of: + * + * a) checking that the chunck index is < NUM_CHUNCKS_POSIX_TIMERS and + * b) that that chunck is allocated (i.e. the array entry + * is > NUM_CHUNCKS_POSIX_TIMERS) and + * c) that the index is in bounds and + * d) that the timer owner is in the callers thread group. + */ + +static struct { + struct semaphore list_lock; + int free_list; + IF_ABS_TIME_ADJ( + struct list_head abs_list; + spinlock_t abs_list_lock; + ) + union { + struct posix_timer_chunck * chunck[NUM_CHUNCKS_POSIX_TIMERS]; + int free_ent[NUM_CHUNCKS_POSIX_TIMERS]; + } chunck_free; +} posix_timers = { list_lock: __MUTEX_INITIALIZER( posix_timers.list_lock) + +#define chuncks chunck_free.chunck +#define free chunck_free. \ + free_ent +#ifdef ABS_TIMERS_ADJ + ,abs_list: LIST_HEAD_INIT(posix_timers.abs_list) + ,abs_list_lock: SPIN_LOCK_UNLOCKED +#endif +}; + +/* + * The tmr_bit_ary is a bit array in which a bit is assigned for each + * entry in . A set bit indicates that the + * chunck has one or more free timers. This makes it easy to quickly + * find a free timer. + */ +static struct { + unsigned long tmr_bit_ary[((NUM_CHUNCKS_POSIX_TIMERS)/32) +1]; + unsigned long guard; +}tmr_bits = {guard: -1}; +#define tmr_bit_map tmr_bits.tmr_bit_ary +#define BF 31 /* bit flip constant */ +#define set_tmr_bit(bit) set_bit(((bit)&0x1f),&tmr_bit_map[(bit) >> 5]) +#define clear_tmr_bit(bit) clear_bit(((bit)&0x1f),&tmr_bit_map[(bit) >> 5]) + +DECLARE_MUTEX(posix_timers_mutex); +#define mutex_enter(x) down(x) +#define mutex_enter_interruptable(x) down_interruptible(x) +#define mutex_exit(x) up(x) + +extern rwlock_t xtime_lock; + +/* + * CLOCKs: The POSIX standard calls for a couple of clocks and allows us + * to implement others. This structure defines the various + * clocks and allows the possibility of adding others. We + * provide an interface to add clocks to the table and expect + * the "arch" code to add at least one clock that is high + * resolution. Here we define the standard CLOCK_REALTIME as a + * 1/HZ resolution clock. + + * CPUTIME & THREAD_CPUTIME: We are not, at this time, definding these + * two clocks (and the other process related clocks (Std + * 1003.1d-1999). The way these should be supported, we think, + * is to use large negative numbers for the two clocks that are + * pinned to the executing process and to use -pid for clocks + * pinned to particular pids. Calls which supported these clock + * ids would split early in the function. + + * RESOLUTION: Clock resolution is used to round up timer and interval + * times, NOT to report clock times, which are reported with as + * much resolution as the system can muster. In some cases this + * resolution may depend on the underlaying clock hardware and + * may not be quantifiable until run time, and only then is the + * necessary code is written. The standard says we should say + * something about this issue in the documentation... + + * FUNCTIONS: The CLOCKs structure defines possible functions to handle + * various clock functions. For clocks that use the standard + * system timer code these entries should be NULL. This will + * allow dispatch without the overhead of indirect function + * calls. CLOCKS that depend on other sources (e.g. WWV or GPS) + * must supply functions here, even if the function just returns + * ENOSYS. The standard POSIX timer management code assumes the + * following: 1.) The k_itimer struct (sched.h) is used for the + * timer. 2.) The list, it_lock, it_clock, it_id and it_process + * fields are not modified by timer code. + * + * Permissions: It is assumed that the clock_settime() function defined + * for each clock will take care of permission checks. Some + * clocks may be set able by any user (i.e. local process + * clocks) others not. Currently the only set able clock we + * have is CLOCK_REALTIME and its high res counter part, both of + * which we beg off on and pass to do_sys_settimeofday(). + */ + +struct k_clock posix_clocks[MAX_CLOCKS]; + +#define if_clock_do(clock_fun, alt_fun,parms) (! clock_fun)? alt_fun parms :\ + clock_fun parms + +#define p_timer_get( clock,a,b) if_clock_do((clock)->timer_get, \ + do_timer_gettime, \ + (a,b)) + +#define p_nsleep( clock,a,b,c) if_clock_do((clock)->nsleep, \ + do_nsleep, \ + (a,b,c)) + +#define p_timer_del( clock,a) if_clock_do((clock)->timer_del, \ + do_timer_delete, \ + (a)) + +void register_posix_clock(int clock_id, struct k_clock * new_clock); + +static int do_posix_gettime(struct k_clock *clock, struct timespec *tp); + +int do_posix_clock_monotonic_gettime(struct timespec *tp); + +int do_posix_clock_monotonic_settime(struct timespec *tp); + +#if CONFIGURE_MIN_INTERVAL == 0 +IF_HIGH_RES(static __init void figure_time_rep(void);) +#endif +IF_HIGH_RES(static int high_res_guard = 0;) +/* + * Build the free list + */ + +static __init int init_posix_timers(void) +{ + int i; + struct k_clock clock_realtime = {res: NSEC_PER_SEC/HZ}; + struct k_clock clock_monotonic = + {res: NSEC_PER_SEC/HZ, + clock_get: do_posix_clock_monotonic_gettime, + clock_set: do_posix_clock_monotonic_settime}; + + for ( i = 0; i < NUM_CHUNCKS_POSIX_TIMERS;) { + posix_timers.free[i] = ++i; + } + register_posix_clock(CLOCK_REALTIME,&clock_realtime); + register_posix_clock(CLOCK_MONOTONIC,&clock_monotonic); + IF_HIGH_RES(clock_realtime.res = CONFIG_HIGH_RES_RESOLUTION; + register_posix_clock(CLOCK_REALTIME_HR,&clock_realtime); + clock_monotonic.res = CONFIG_HIGH_RES_RESOLUTION; + register_posix_clock(CLOCK_MONOTONIC_HR,&clock_monotonic); + high_res_guard = nsec_to_arch_cycles(CONFIGURE_MIN_INTERVAL); + ); +#ifdef final_clock_init + final_clock_init(); // defined by arch header file +#endif +#if CONFIGURE_MIN_INTERVAL == 0 + figure_time_rep(); +#endif + return 0; +} + +__initcall(init_posix_timers); + +static inline int tstojiffie(struct timespec *tp, + int res, + unsigned long *jiff) +{ + unsigned long sec = tp->tv_sec; + long nsec = tp->tv_nsec + res - 1; + + /* + * A note on jiffy overflow: It is possible for the system to + * have been up long enough for the jiffies quanity to overflow. + * In order for correct timer evaluations we require that the + * specified time be somewhere between now and now + (max + * unsigned int/2). Times beyond this will be truncated back to + * this value. This is done in the absolute adjustment code, + * below. Here it is enough to just discard the high order + * bits. + */ + *jiff = HZ * sec; + /* + * Do the res thing. (Don't forget the add in the declaration of nsec) + */ + nsec -= nsec % res; + /* + * Split to jiffie and sub jiffie + */ + *jiff += nsec / (NSEC_PER_SEC / HZ); + /* + * We trust that the optimizer will use the remainder from the + * above div in the following operation as long as they are close. + */ + return (nsec_to_arch_cycles(nsec % (NSEC_PER_SEC / HZ))); +} +#ifdef CONFIG_HIGH_RES_TIMERS +static void tstotimer(struct itimerspec * time, struct k_itimer * timer) +{ + int res = posix_clocks[timer->it_clock].res; + + timer->it_timer.sub_expires = tstojiffie(&time->it_value, + res, + &timer->it_timer.expires); + timer->it_sub_incr = tstojiffie(&time->it_interval, + res, + (unsigned long*) &timer->it_incr); + if ((unsigned long)timer->it_incr > MAX_JIFFY_OFFSET) + timer->it_incr = MAX_JIFFY_OFFSET; +} +#else +static void tstotimer(struct itimerspec * time, struct k_itimer * timer) +{ + int res = posix_clocks[timer->it_clock].res; + tstojiffie(&time->it_value, + res, + &timer->it_timer.expires); + tstojiffie(&time->it_interval, + res, + &timer->it_incr); +} + + +#endif int do_getitimer(int which, struct itimerval *value) { register unsigned long val, interval; @@ -21,7 +345,11 @@ interval = current->it_real_incr; val = 0; /* - * FIXME! This needs to be atomic, in case the kernel timer happens! + * FIXME! This needs to be atomic, in case the kernel + * timer happens! + * Well, not really, for the one word values, now for + * high-res-timers, that is another thing. But we don't + * do high-res-timers on this API. */ if (timer_pending(¤t->real_timer)) { val = current->real_timer.expires - jiffies; @@ -118,7 +446,7 @@ } /* SMP: Again, only we play with our itimers, and signals are SMP safe - * now so that is not an issue at all anymore. + * now so that is not an issue at all anymore. */ asmlinkage long sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) @@ -137,6 +465,1228 @@ 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_sigev_notify & SIGEV_NONE)) { + + memset(&info, 0, sizeof(info)); + + /* Send signal to the process that owns this timer. */ + info.si_signo = timr->it_sigev_signo; + info.si_errno = 0; + info.si_code = SI_TIMER; + info.si_tid = timr->it_id; + info.si_value = timr->it_sigev_value; + info.si_overrun = timr->it_overrun_deferred; + ret = send_sig_info(info.si_signo, &info, timr->it_process); + switch (ret) { + case 0: /* all's well new signal queued */ + timr->it_overrun_last = timr->it_overrun; + timr->it_overrun = timr->it_overrun_deferred; + break; + case 1: /* signal from this timer was already in the queue */ + timr->it_overrun += timr->it_overrun_deferred + 1; + break; + default: + printk(KERN_WARNING "sending signal failed: %d\n", ret); + break; + } + } +} + +#ifdef CONFIG_HIGH_RES_TIMERS +/* + * This bit of code is to protect the system from being consumed by + * repeating timer expirations. We detect overrun and adjust the + * next time to be at least high_res_guard out. We clock the overrun + * but only AFTER the next expire as it has not really happened yet. + * + * Careful, only do this if the timer repeat time is less than + * high_res_guard AND we have fallen behind. + */ + +static inline void do_overrun_protect(struct k_itimer *timr) +{ + timr->it_overrun_deferred = 0; + + if (! timr->it_incr && + (high_res_guard > timr->it_sub_incr)){ + int offset = quick_update_jiffies_sub( timr->it_timer.expires); + + offset -= timr->it_timer.sub_expires; + touch_nmi_watchdog(); + offset += high_res_guard; + if (offset <= 0){ + return; + } + // expire time is in the past (or within the guard window) + + timr->it_overrun_deferred = (offset / timr->it_sub_incr) - 1; + timr->it_timer.sub_expires += + offset - (offset % timr->it_sub_incr); + + while ((timr->it_timer.sub_expires - cycles_per_jiffies) >= 0){ + timr->it_timer.sub_expires -= cycles_per_jiffies; + timr->it_timer.expires++; + } + } +} + +#endif +/* + * 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){ + IF_HIGH_RES(if(timr->it_sub_incr == 0) + ){ + set_timer_inactive(timr); + return; + } + } + if (interval > (unsigned long) LONG_MAX) + interval = LONG_MAX; + timr->it_timer.expires += interval; + IF_HIGH_RES(timr->it_timer.sub_expires += timr->it_sub_incr; + if ((timr->it_timer.sub_expires - cycles_per_jiffies) >= 0){ + timr->it_timer.sub_expires -= cycles_per_jiffies; + timr->it_timer.expires++; + } + do_overrun_protect(timr); + ); + 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. + * The run_timer_list code ALWAYS calls with interrutps on. + */ +static void posix_timer_fn(unsigned long __data) +{ + struct k_itimer *timr = (struct k_itimer *)__data; + + spin_lock_irq(&timr->it_lock); + posix_timer_fire(timr); + spin_unlock_irq(&timr->it_lock); +} +/* + * For some reason mips/mips64 define the SIGEV constants plus 128. + * Here we define a mask to get rid of the common bits. The + * optimizer should make this costless to all but mips. + */ +#if (ARCH == mips) || (ARCH == mips64) +#define MIPS_SIGEV ~(SIGEV_NONE & \ + SIGEV_SIGNAL & \ + SIGEV_THREAD & \ + SIGEV_THREAD_ID) +#else +#define MIPS_SIGEV (int)-1 +#endif + +static inline struct task_struct * good_sigevent(sigevent_t *event) +{ + struct task_struct * rtn = current; + + if (event->sigev_notify & SIGEV_THREAD_ID & MIPS_SIGEV ) { + if ( !(rtn = + find_task_by_pid(event->sigev_notify_thread_id)) || + rtn->tgid != current->tgid){ + return NULL; + } + } + if (event->sigev_notify & SIGEV_SIGNAL & MIPS_SIGEV) { + if ((unsigned)(event->sigev_signo > SIGRTMAX)) + return NULL; + } + if (event->sigev_notify & ~(SIGEV_SIGNAL | SIGEV_THREAD_ID )) { + return NULL; + } + return rtn; +} + + +void register_posix_clock(int clock_id,struct k_clock * new_clock) +{ + if ( (unsigned)clock_id >= MAX_CLOCKS){ + printk("POSIX clock register failed for clock_id %d\n",clock_id); + return; + } + posix_clocks[clock_id] = *new_clock; +} + +static struct k_itimer * alloc_posix_timer(void) +{ + struct k_itimer * tmr; + struct posix_timer_chunck *chunck, **chunck_ptr; + int i, open; + unsigned long *ip; + /* + * kmalloc sleeps so we must use a mutex, not a spinlock + */ + mutex_enter(&posix_timers.list_lock); + + for (ip = &tmr_bit_map[0], open = 0; (*ip == 0); open +=32,ip++); + open += ffz(~*ip); + if (open > NUM_CHUNCKS_POSIX_TIMERS){ + /* + * No free timers, try to allocate some memory + */ + if (posix_timers.free_list != NUM_CHUNCKS_POSIX_TIMERS){ + chunck = get_timer_chunck(); + if ( ! chunck ){ + mutex_exit(&posix_timers.list_lock); + return NULL; + } else { + chunck_ptr = &posix_timers. + chuncks[posix_timers.free_list]; + posix_timers.free_list = posix_timers. + free[posix_timers.free_list]; + *chunck_ptr = chunck; + chunck->index = chunck_ptr - + &posix_timers.chuncks[0]; + chunck->used_count = 1; + INIT_LIST_HEAD(&chunck->free_list); + for ( i = 0,tmr = &chunck->timers[0]; + i < NUM_POSIX_TIMERS_PER_CHUNCK; + i++, tmr++){ + list_add(&tmr->list, + &chunck->free_list); + tmr->it_id = + (timer_t)( + (chunck->index << + CHUNCK_SHIFT) + i); + tmr->it_process = NULL; + } + --tmr; + list_del(&tmr->list); + set_tmr_bit( chunck->index); + mutex_exit(&posix_timers.list_lock); + return tmr; + } + } else { + /* + * max number of timers is already allocated + */ + mutex_exit(&posix_timers.list_lock); + return NULL; + } + } else { + /* + * we have a partically allocated chunck + */ + chunck = posix_timers.chuncks[open]; + chunck->used_count++; + if (chunck->used_count == NUM_POSIX_TIMERS_PER_CHUNCK){ + clear_tmr_bit(open); + } + tmr = list_entry(chunck->free_list.next,struct k_itimer,list); + list_del(&tmr->list); + mutex_exit(&posix_timers.list_lock); + return tmr; + } +} + +static void release_posix_timer(struct k_itimer * tmr) +{ + int index = tmr->it_id >> CHUNCK_SHIFT; + struct posix_timer_chunck *chunck = posix_timers.chuncks[index]; + + mutex_enter(&posix_timers.list_lock); + list_add_tail(&tmr->list, &chunck->free_list); + tmr->it_process = NULL; + if ( --chunck->used_count == 0){ + int i; + for ( i = 0; i < NUM_POSIX_TIMERS_PER_CHUNCK; i++) { + list_del(&chunck->timers[i].list); + } + free_timer_chunck(chunck); + posix_timers.free[index] = posix_timers.free_list; + posix_timers.free_list = index; + clear_tmr_bit(index); + } + mutex_exit(&posix_timers.list_lock); +} + +/* 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; + int new_timer_id; + struct task_struct * process = current; + sigevent_t event; + + /* Right now, we only support CLOCK_REALTIME for timers. */ + if ((unsigned)which_clock >= MAX_CLOCKS || + ! posix_clocks[which_clock].res) return -EINVAL; + + new_timer = alloc_posix_timer(); + if (new_timer == NULL) return -EAGAIN; + + spin_lock_init(&new_timer->it_lock); + IF_ABS_TIME_ADJ(INIT_LIST_HEAD(&new_timer->abs_list)); + if (timer_event_spec) { + if (copy_from_user(&event, timer_event_spec, + sizeof(event))) { + error = -EFAULT; + goto out; + } + if ((process = good_sigevent(&event)) == NULL) { + error = -EINVAL; + goto out; + } + new_timer->it_sigev_notify = event.sigev_notify; + new_timer->it_sigev_signo = event.sigev_signo; + new_timer->it_sigev_value = event.sigev_value; + } + else { + new_timer->it_sigev_notify = SIGEV_SIGNAL; + new_timer->it_sigev_signo = SIGALRM; + new_timer->it_sigev_value.sival_int = new_timer->it_id; + } + + new_timer->it_clock = which_clock; + new_timer->it_incr = 0; + new_timer->it_overrun = 0; + init_timer (&new_timer->it_timer); + new_timer->it_timer.expires = 0; + new_timer->it_timer.data = (unsigned long) new_timer; + new_timer->it_timer.function = posix_timer_fn; + set_timer_inactive(new_timer); + + new_timer_id = new_timer->it_id; + + if (copy_to_user(created_timer_id, + &new_timer_id, + sizeof(new_timer_id))) { + error = -EFAULT; + goto out; + } + spin_lock(&process->alloc_lock); + list_add(&new_timer->list, &process->posix_timers); + + spin_unlock(&process->alloc_lock); + /* + * Once we set the process, it can be found so do it last... + */ + new_timer->it_process = process; + + out: + if (error) { + release_posix_timer(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) || + (ts->tv_sec < 0) || + ((unsigned)ts->tv_nsec >= NSEC_PER_SEC)) + return 0; + return 1; +} + +static inline void unlock_timer(struct k_itimer *timr) +{ + spin_unlock_irq(&timr->it_lock); +} + +static struct k_itimer* lock_timer( timer_t timer_id) +{ + struct k_itimer *timr = NULL; + int chunck_index = (int)((unsigned)timer_id >> CHUNCK_SHIFT); + int chunck_offset = timer_id & CHUNCK_MASK; + struct task_struct *owner = NULL; + + mutex_enter(&posix_timers.list_lock); + if ( chunck_index >= NUM_CHUNCKS_POSIX_TIMERS || + chunck_offset >= NUM_POSIX_TIMERS_PER_CHUNCK || + posix_timers.free[chunck_index] <= NUM_CHUNCKS_POSIX_TIMERS){ + timr = NULL; + goto lock_timer_exit; + } + timr = &(posix_timers.chuncks[chunck_index]->timers[chunck_offset]); + /* + * It would be better if we had a thread group structure to keep, + * among other things, the head of the owned timers list + * and which could be pointed to by the owners field in the timer + * structure. Failing that, check to see if owner is one of + * the thread group. Protect against stale timer ids. + */ + if (timr->it_id != timer_id) { + BUG(); + } + if ( ! (owner = timr->it_process) || owner->tgid != current->tgid){ + timr = NULL; + }else{ + + spin_lock_irq(&timr->it_lock); + /* + * Suppose while we were spining, the timer was deleted... + * AND maybe even given to some other process... + * Well, it just can not happen because we hold the mutex! + * AND, now we have the lock. + */ + } + lock_timer_exit: + mutex_exit(&posix_timers.list_lock); + return timr; +} + +/* + * Get the time remaining on a POSIX.1b interval timer. + * This function is ALWAYS called with spin_lock_irq on the timer, thus + * it must not mess with irq. + */ +void inline do_timer_gettime(struct k_itimer *timr, + struct itimerspec *cur_setting) +{ + long sub_expires; + unsigned long expires; + + do { + expires = timr->it_timer.expires; + IF_HIGH_RES(sub_expires = timr->it_timer.sub_expires); + } while ((volatile long)(timr->it_timer.expires) != expires); + + IF_HIGH_RES(write_lock(&xtime_lock); + update_jiffies_sub()); + if (expires && timer_pending(&timr->it_timer)){ + expires -= jiffies; + IF_HIGH_RES(sub_expires -= sub_jiffie()); + }else{ + sub_expires = expires = 0; + } + IF_HIGH_RES( write_unlock(&xtime_lock)); + + jiffies_to_timespec(expires, &cur_setting->it_value); + jiffies_to_timespec(timr->it_incr, &cur_setting->it_interval); + + IF_HIGH_RES(cur_setting->it_value.tv_nsec += + arch_cycles_to_nsec( sub_expires); + if (cur_setting->it_value.tv_nsec < 0){ + cur_setting->it_value.tv_nsec += NSEC_PER_SEC; + cur_setting->it_value.tv_sec--; + } + if ((cur_setting->it_value.tv_nsec - NSEC_PER_SEC) >= 0){ + cur_setting->it_value.tv_nsec -= NSEC_PER_SEC; + cur_setting->it_value.tv_sec++; + } + cur_setting->it_interval.tv_nsec += + arch_cycles_to_nsec(timr->it_sub_incr); + if ((cur_setting->it_interval.tv_nsec - NSEC_PER_SEC) >= 0){ + cur_setting->it_interval.tv_nsec -= NSEC_PER_SEC; + cur_setting->it_interval.tv_sec++; + } + ); + if (cur_setting->it_value.tv_sec < 0){ + cur_setting->it_value.tv_nsec = 1; + cur_setting->it_value.tv_sec = 0; + } +} +/* 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(timer_id); + if (!timr) return -EINVAL; + + p_timer_get(&posix_clocks[timr->it_clock],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 + * This is a bit messy as we don't easily know where he is in the delivery + * of possible multiple signals. We are to give him the overrun on the + * last delivery. If we have another pending, we want to make sure we + * use the last and not the current. If there is not another pending + * then he is current and gets the current overrun. We search both the + * shared and local queue. + */ + +asmlinkage int sys_timer_getoverrun(timer_t timer_id) +{ + struct k_itimer *timr; + int overrun, i; + struct sigqueue *q; + struct sigpending *sig_queue; + struct task_struct * t; + + timr = lock_timer( timer_id); + if (!timr) return -EINVAL; + + t = timr->it_process; + overrun = timr->it_overrun; + spin_lock_irq(&t->sig->siglock); + for (sig_queue = &t->sig->shared_pending, i = 2; i; + sig_queue = &t->pending, i--){ + for (q = sig_queue->head; q; q = q->next) { + if ((q->info.si_code == SI_TIMER) && + (q->info.si_tid == timr->it_id)) { + + overrun = timr->it_overrun_last; + goto out; + } + } + } + out: + spin_unlock_irq(&t->sig->siglock); + + unlock_timer(timr); + + return overrun; +} +/* Adjust for absolute time */ +/* + * If absolute time is given and it is not CLOCK_MONOTONIC, we need to + * adjust for the offset between the timer clock (CLOCK_MONOTONIC) and + * what ever clock he is using. + * + * If it is relative time, we need to add the current (CLOCK_MONOTONIC) + * time to it to get the proper time for the timer. + */ +static int adjust_abs_time(struct k_clock *clock,struct timespec *tp, int abs) +{ + struct timespec now; + struct timespec oc; + do_posix_clock_monotonic_gettime(&now); + + if ( abs && + (posix_clocks[CLOCK_MONOTONIC].clock_get == clock->clock_get)){ + }else{ + + if (abs){ + do_posix_gettime(clock,&oc); + }else{ + oc.tv_nsec = oc.tv_sec =0; + } + tp->tv_sec += now.tv_sec - oc.tv_sec; + tp->tv_nsec += now.tv_nsec - oc.tv_nsec; + + /* + * Normalize... + */ + if (( tp->tv_nsec - NSEC_PER_SEC) >= 0){ + tp->tv_nsec -= NSEC_PER_SEC; + tp->tv_sec++; + } + if (( tp->tv_nsec ) < 0){ + tp->tv_nsec += NSEC_PER_SEC; + tp->tv_sec--; + } + } + /* + * Check if the requested time is prior to now (if so set now) or + * is more than the timer code can handle (if so we error out). + * The (unsigned) catches the case of prior to "now" with the same + * test. Only on failure do we sort out what happened, and then + * we use the (unsigned) to error out negative seconds. + */ + if ((unsigned)(tp->tv_sec - now.tv_sec) > (MAX_JIFFY_OFFSET / HZ)){ + if ( (unsigned)tp->tv_sec < now.tv_sec){ + tp->tv_sec = now.tv_sec; + tp->tv_nsec = now.tv_nsec; + }else{ + // tp->tv_sec = now.tv_sec + (MAX_JIFFY_OFFSET / HZ); + /* + * This is a considered response, not exactly in + * line with the standard (in fact it is silent on + * possible overflows). We assume such a large + * value ALMOST always is a programming error and + * try not to compound it by setting a really dumb + * value. + */ + return -EINVAL; + } + } + return 0; +} + +/* Set a POSIX.1b interval timer. */ +/* timr->it_lock is taken. */ +static inline int do_timer_settime(struct k_itimer *timr, int flags, + struct itimerspec *new_setting, + struct itimerspec *old_setting) +{ + struct k_clock * clock = &posix_clocks[timr->it_clock]; + + if (old_setting) { + do_timer_gettime(timr, old_setting); + } + + /* disable the timer */ + timr->it_incr = 0; + IF_HIGH_RES(timr->it_sub_incr = 0); + /* + * careful here. If smp we could be in the "fire" routine which will + * be spinning as we hold the lock. But this is ONLY an SMP issue. + */ +#ifdef CONFIG_SMP + if ( timer_active(timr) && ! del_timer(&timr->it_timer)){ + /* + * It can only be active if on an other cpu. Since + * we have cleared the interval stuff above, it should + * clear once we release the spin lock. Of course once + * we do that anything could happen, including the + * complete melt down of the timer. So return with + * a "retry" exit status. + */ + return TIMER_RETRY; + } + set_timer_inactive(timr); +#else + del_timer(&timr->it_timer); +#endif + /* 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_timer.expires = 0; + IF_HIGH_RES(timr->it_timer.sub_expires = 0 ); + return 0; + } + + if ((flags & TIMER_ABSTIME) && + (clock->clock_get != do_posix_clock_monotonic_gettime)) { + //timr->it_timer.abs = TIMER_ABSTIME; + }else{ + // timr->it_timer.abs = 0; + } + if( adjust_abs_time(clock, + &new_setting->it_value, + flags & TIMER_ABSTIME)){ + return -EINVAL; + } + tstotimer(new_setting,timr); + + /* + * For some reason the timer does not fire immediately if expires is + * equal to jiffies, so the timer callback function is called directly. + */ +#ifndef CONFIG_HIGH_RES_TIMERS + if (timr->it_timer.expires == jiffies) { + posix_timer_fire(timr); + return 0; + } +#endif + timr->it_overrun_deferred = + timr->it_overrun_last = + timr->it_overrun = 0; + add_timer(&timr->it_timer); + return 0; +} + + +/* 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; + struct itimerspec *rtn = old_setting ? &old_spec : NULL; + + + if (new_setting == NULL) { + return -EINVAL; + } + + if (copy_from_user(&new_spec, new_setting, sizeof(new_spec))) { + return -EFAULT; + } + + if ((!good_timespec(&new_spec.it_interval)) || + (!good_timespec(&new_spec.it_value))) { + return -EINVAL; + } + retry: + timr = lock_timer( timer_id); + if (!timr) return -EINVAL; + + if (! posix_clocks[timr->it_clock].timer_set) { + error = do_timer_settime(timr, flags, &new_spec, rtn ); + }else{ + error = posix_clocks[timr->it_clock].timer_set(timr, + flags, + &new_spec, + rtn ); + } + unlock_timer(timr); + if ( error == TIMER_RETRY){ + rtn = NULL; // We already got the old time... + goto retry; + } + + if (old_setting && ! error) { + if (copy_to_user(old_setting, &old_spec, sizeof(old_spec))) { + error = -EFAULT; + } + } + + return error; +} + +static inline int do_timer_delete(struct k_itimer *timer) +{ + timer->it_incr = 0; + IF_HIGH_RES(timer->it_sub_incr = 0); +#ifdef CONFIG_SMP + if ( timer_active(timer) && ! del_timer(&timer->it_timer)){ + /* + * It can only be active if on an other cpu. Since + * we have cleared the interval stuff above, it should + * clear once we release the spin lock. Of course once + * we do that anything could happen, including the + * complete melt down of the timer. So return with + * a "retry" exit status. + */ + return TIMER_RETRY; + } +#else + del_timer(&timer->it_timer); +#endif + return 0; +} + +/* Delete a POSIX.1b interval timer. */ +asmlinkage int sys_timer_delete(timer_t timer_id) +{ + struct k_itimer *timer; + +#ifdef CONFIG_SMP + int error; + retry_delete: +#endif + + timer = lock_timer( timer_id); + if (!timer) return -EINVAL; + +#ifdef CONFIG_SMP + error = p_timer_del(&posix_clocks[timer->it_clock],timer); + + if (error == TIMER_RETRY) { + unlock_timer(timer); + goto retry_delete; + } +#else + p_timer_del(&posix_clocks[timer->it_clock],timer); +#endif + + spin_lock(&timer->it_process->alloc_lock); + + list_del(&timer->list); + + spin_unlock(&timer->it_process->alloc_lock); + + IF_ABS_TIME_ADJ( + spin_lock(&abs_list_lock); + + if (! list_empty(&timer->abs_list)){ + + list_del(&timer->abs_list); + } + spin_unlock( &abs_list_lock); + ); + /* + * This keeps any tasks waiting on the spin lock from thinking + * they got something (see the lock code above). + */ + timer->it_process = NULL; + unlock_timer(timer); + release_posix_timer(timer); return 0; } +/* + * return timer owned by the process, used by exit and exec + */ +void itimer_delete(struct k_itimer *timer) +{ + if (sys_timer_delete(timer->it_id)){ + BUG(); + } +} +/* + * And now for the "clock" calls + + * These functions are called both from timer functions (with the timer + * spin_lock_irq() held and from clock calls with no locking. They must + * use the save flags versions of locks. + */ +static int do_posix_gettime(struct k_clock *clock, struct timespec *tp) +{ + + if (clock->clock_get){ + return clock->clock_get(tp); + } + +#ifdef CONFIG_HIGH_RES_TIMERS + { + unsigned long flags; + write_lock_irqsave(&xtime_lock, flags); + update_jiffies_sub(); + update_real_wall_time(); + tp->tv_sec = xtime.tv_sec; + tp->tv_nsec = xtime.tv_nsec; + tp->tv_nsec += arch_cycles_to_nsec(sub_jiffie()); + write_unlock_irqrestore(&xtime_lock, flags); + if ( tp->tv_nsec > NSEC_PER_SEC ){ + tp->tv_nsec -= NSEC_PER_SEC ; + tp->tv_sec++; + } + } +#else + do_gettimeofday((struct timeval*)tp); + tp->tv_nsec *= NSEC_PER_USEC; +#endif + return 0; +} + +/* + * We do ticks here to avoid the irq lock ( they take sooo long) + * Note also that the while loop assures that the sub_jiff_offset + * will be less than a jiffie, thus no need to normalize the result. + * Well, not really, if called with ints off :( + */ + +int do_posix_clock_monotonic_gettime(struct timespec *tp) +{ + long sub_sec; + u64 jiffies_64_f; + IF_HIGH_RES(long sub_jiff_offset;) + +#if (BITS_PER_LONG > 32) && !defined(CONFIG_HIGH_RES_TIMERS) + + jiffies_64_f = jiffies_64; + +#elif defined(CONFIG_SMP) + + /* Tricks don't work here, must take the lock. Remember, called + * above from both timer and clock system calls => save flags. + */ + { + unsigned long flags; + read_lock_irqsave(&xtime_lock, flags); + jiffies_64_f = jiffies_64; + + IF_HIGH_RES(sub_jiff_offset = + quick_update_jiffies_sub(jiffies)); + + read_unlock_irqrestore(&xtime_lock, flags); + } +#elif ! defined(CONFIG_SMP) && (BITS_PER_LONG < 64) + unsigned long jiffies_f; + do { + jiffies_f = jiffies; + barrier(); + IF_HIGH_RES( + sub_jiff_offset = + quick_update_jiffies_sub(jiffies_f)); + jiffies_64_f = jiffies_64; + } while (unlikely(jiffies_f != jiffies)); + +#else /* 64 bit long and high-res but no SMP if I did the Venn right */ + do { + jiffies_64_f = jiffies_64; + barrier(); + sub_jiff_offset = quick_update_jiffies_sub(jiffies_64_f); + } while (unlikely(jiffies_64_f != jiffies_64)); + +#endif + /* + * Remember that quick_update_jiffies_sub() can return more + * than a jiffies worth of cycles... + */ + IF_HIGH_RES( + while ( unlikely(sub_jiff_offset > cycles_per_jiffies)){ + sub_jiff_offset -= cycles_per_jiffies; + jiffies_64_f++; + } + ) + tp->tv_sec = div_long_long_rem(jiffies_64_f,HZ,&sub_sec); + + tp->tv_nsec = sub_sec * (NSEC_PER_SEC / HZ); + IF_HIGH_RES(tp->tv_nsec += arch_cycles_to_nsec(sub_jiff_offset)); + return 0; +} + +int do_posix_clock_monotonic_settime(struct timespec *tp) +{ + return -EINVAL; +} + +asmlinkage int sys_clock_settime(clockid_t which_clock,const struct timespec *tp) +{ + struct timespec new_tp; + + if ((unsigned)which_clock >= MAX_CLOCKS || + ! posix_clocks[which_clock].res) return -EINVAL; + if (copy_from_user(&new_tp, tp, sizeof(*tp))) + return -EFAULT; + if ( posix_clocks[which_clock].clock_set){ + return posix_clocks[which_clock].clock_set(&new_tp); + } + new_tp.tv_nsec /= NSEC_PER_USEC; + return do_sys_settimeofday((struct timeval*)&new_tp,NULL); +} +asmlinkage int sys_clock_gettime(clockid_t which_clock, struct timespec *tp) +{ + struct timespec rtn_tp; + int error = 0; + + if ((unsigned)which_clock >= MAX_CLOCKS || + ! posix_clocks[which_clock].res) return -EINVAL; + + error = do_posix_gettime(&posix_clocks[which_clock],&rtn_tp); + + if ( ! error) { + if (copy_to_user(tp, &rtn_tp, sizeof(rtn_tp))) { + error = -EFAULT; + } + } + return error; + +} +asmlinkage int sys_clock_getres(clockid_t which_clock, struct timespec *tp) +{ + struct timespec rtn_tp; + + if ((unsigned)which_clock >= MAX_CLOCKS || + ! posix_clocks[which_clock].res) return -EINVAL; + + rtn_tp.tv_sec = 0; + rtn_tp.tv_nsec = posix_clocks[which_clock].res; + if ( tp){ + if (copy_to_user(tp, &rtn_tp, sizeof(rtn_tp))) { + return -EFAULT; + } + } + return 0; + +} +static void nanosleep_wake_up(unsigned long __data) +{ + struct task_struct * p = (struct task_struct *) __data; + + wake_up_process(p); +} +/* + * The standard says that an absolute nanosleep call MUST wake up at + * the requested time in spite of clock settings. Here is what we do: + * For each nanosleep call that needs it (only absolute and not on + * CLOCK_MONOTONIC* (as it can not be set)) we thread a little structure + * into the "nanosleep_abs_list". All we need is the task_struct pointer. + * When ever the clock is set we just wake up all those tasks. The rest + * is done by the while loop in clock_nanosleep(). + + * On locking, clock_was_set() is called from update_wall_clock which + * holds (or has held for it) a write_lock_irq( xtime_lock) and is + * called from the timer bh code. Thus we need the irq save locks. + */ +spinlock_t nanosleep_abs_list_lock = SPIN_LOCK_UNLOCKED; + +struct list_head nanosleep_abs_list = LIST_HEAD_INIT(nanosleep_abs_list); + +struct abs_struct { + struct list_head list; + struct task_struct *t; +}; + +void clock_was_set(void) +{ + struct list_head *pos; + unsigned long flags; + + spin_lock_irqsave(&nanosleep_abs_list_lock, flags); + list_for_each(pos, &nanosleep_abs_list){ + wake_up_process(list_entry(pos,struct abs_struct,list)->t); + } + spin_unlock_irqrestore(&nanosleep_abs_list_lock, flags); +} + +#if 0 +// This #if 0 is to keep the pretty printer/ formatter happy so the indents will +// correct below. + +// The NANOSLEEP_ENTRY macro is defined in asm/signal.h and +// is structured to allow code as well as entry definitions, so that when +// we get control back here the entry parameters will be available as expected. +// Some systems may find these paramerts in other ways than as entry parms, +// for example, struct pt_regs *regs is defined in i386 as the address of the +// first parameter, where as other archs pass it as one of the paramerters. + +asmlinkage long sys_clock_nanosleep(void) +{ +#endif + CLOCK_NANOSLEEP_ENTRY( struct timespec t; + struct timespec tsave; + struct timer_list new_timer; + struct abs_struct abs_struct = {list: {next :0}}; + int abs; + int rtn = 0; + int active;) + + //asmlinkage int sys_clock_nanosleep(clockid_t which_clock, + // int flags, + // const struct timespec *rqtp, + // struct timespec *rmtp) + //{ + if ((unsigned)which_clock >= MAX_CLOCKS || + ! posix_clocks[which_clock].res) return -EINVAL; + + if(copy_from_user(&tsave, rqtp, sizeof(struct timespec))) + return -EFAULT; + + if ((unsigned)tsave.tv_nsec >= NSEC_PER_SEC || tsave.tv_sec < 0) + return -EINVAL; + + init_timer(&new_timer); + new_timer.expires = 0; + new_timer.data = (unsigned long)current; + new_timer.function = nanosleep_wake_up; + abs = flags & TIMER_ABSTIME; + + if ( abs && (posix_clocks[which_clock].clock_get != + posix_clocks[CLOCK_MONOTONIC].clock_get) ){ + spin_lock_irq(&nanosleep_abs_list_lock); + list_add(&abs_struct.list, &nanosleep_abs_list); + abs_struct.t = current; + spin_unlock_irq(&nanosleep_abs_list_lock); + } + do { + t = tsave; + if ( (abs || !new_timer.expires) && + !(rtn = adjust_abs_time(&posix_clocks[which_clock], + &t, + abs))){ + /* + * On error, we don't set up the timer so + * we don't arm the timer so + * del_timer_sync() will return 0, thus + * active is zero... and so it goes. + */ + IF_HIGH_RES(new_timer.sub_expires = ) + + tstojiffie(&t, + posix_clocks[which_clock].res, + &new_timer.expires); + } + if (new_timer.expires ){ + current->state = TASK_INTERRUPTIBLE; + add_timer(&new_timer); + + schedule(); + } + } + while((active = del_timer_sync(&new_timer)) && !_do_signal()); + + if ( abs_struct.list.next ){ + spin_lock_irq(&nanosleep_abs_list_lock); + list_del(&abs_struct.list); + spin_unlock_irq(&nanosleep_abs_list_lock); + } + if (active && rmtp ) { + unsigned long jiffies_f = jiffies; + IF_HIGH_RES( + long sub_jiff = + quick_update_jiffies_sub(jiffies_f)); + + jiffies_to_timespec(new_timer.expires - jiffies_f, &t); + + IF_HIGH_RES(t.tv_nsec += + arch_cycles_to_nsec(new_timer.sub_expires - + sub_jiff)); + while (t.tv_nsec < 0){ + t.tv_nsec += NSEC_PER_SEC; + t.tv_sec--; + } + if (t.tv_sec < 0){ + t.tv_sec = 0; + t.tv_nsec = 1; + } + }else{ + t.tv_sec = 0; + t.tv_nsec = 0; + } + if (!rtn && !abs && rmtp && + copy_to_user(rmtp, &t, sizeof(struct timespec))){ + return -EFAULT; + } + if (active) return -EINTR; + + return rtn; +} +#ifdef CONFIG_HIGH_RES_TIMERS +/* + * The following code times the timer delivery to see what the system will do. + * Given this time an "unload" value is computed to limit the possible bringing + * of the system to its knees by a repeating timer. We assume the user will + * need at least as much time as we do to handle the signal, so we double the + * "observed" time. +*/ +#define SIG (_NSIG - 1) +#define USEC_TO_RUN 5000 +#define OVERHEAD_MUL 4 // we use this factor to give us room to breath + +#if CONFIGURE_MIN_INTERVAL == 0 + +static __init void fig_time_fn( unsigned long __data) +{ + struct k_itimer *timr = (struct k_itimer *)__data; + struct timeval tv, *endtime; + long jiffies_f,sub_jiffie_f; + + if ( ! timr->it_id) return; + spin_lock(&timr->it_lock); + timer_notify_task(timr); + touch_nmi_watchdog(); + + do_gettimeofday(&tv); + + read_lock(&xtime_lock); + jiffies_f = jiffies; + sub_jiffie_f = sub_jiffie(); + read_unlock(&xtime_lock); + + if ( ++sub_jiffie_f == cycles_per_jiffies){ + sub_jiffie_f = 0; + jiffies_f++; + } + timr->it_timer.expires = jiffies_f; + timr->it_timer.sub_expires = sub_jiffie_f; + add_timer(&timr->it_timer); + + endtime = (struct timeval *)timr->it_clock; + if (endtime->tv_sec == 0 ){ + tv.tv_usec += USEC_TO_RUN; + while ( tv.tv_usec > 1000000){ + tv.tv_sec++; + tv.tv_usec -= 1000000; + } + *endtime = tv; + spin_unlock(&timr->it_lock); + return; + } + if ( tv.tv_sec < endtime->tv_sec || + (tv.tv_sec == endtime->tv_sec && tv.tv_usec < endtime->tv_usec )){ + spin_unlock(&timr->it_lock); + return; + } + spin_unlock(&timr->it_lock); + del_timer(&timr->it_timer); + timr->it_id = 0; // signals end of wait to figure_time_rep + return; +} + +static __init void figure_time_rep(void) +{ + int old_sig = current->blocked.sig[_NSIG_WORDS-1]; + struct timeval tv; + struct k_itimer itimer = {it_overrun: 0, + it_lock: SPIN_LOCK_UNLOCKED, + it_clock: (unsigned long)&tv, + it_id: -1, + it_incr: 0, + it_sub_incr: nsec_to_arch_cycles( + CONFIG_HIGH_RES_RESOLUTION), + it_process: current, + it_sigev_notify: SIGEV_SIGNAL, + it_sigev_signo: SIG, + it_timer: {list: + LIST_HEAD_INIT( + itimer.it_timer.entry), + expires: jiffies + 1, + sub_expires: 0, + data:(unsigned long) &itimer, + function: fig_time_fn + } + }; + + + /* + * We will be sending these singals to our self. We don't really + * want them so we block them here. + */ + sigaddset(¤t->blocked, SIG); + tv.tv_sec = 0; + init_timer(&itimer.it_timer); + itimer.it_overrun_deferred = 0; + high_res_test(); + add_timer(&itimer.it_timer); + while ( ((volatile struct k_itimer *)(&itimer))->it_id){ + struct timeval t; + do_gettimeofday(&t); + if ( ! tv.tv_sec ) continue; + if (t.tv_sec > (tv.tv_sec + 1)) { + printk("High-res-timer calibration problem?\n"); + break; + } + } + + /* + * Ok, the run is over. Clean up, set the results, and + * report. + */ + high_res_end_test(); + flush_signals(current); + current->blocked.sig[_NSIG_WORDS-1] = old_sig; + if (!itimer.it_overrun) { + /* + * Bad, really bad. + */ + printk("High-res-timer calibration failed!!!!!!!!!!!!!!!!\n"); + }else{ + int tmp = ((USEC_TO_RUN * OVERHEAD_MUL) * 1000) / + itimer.it_overrun; + high_res_guard = nsec_to_arch_cycles(tmp); + printk("High-res-timer min supported interval time is " + "%d nsec\n", tmp); + } +} + +#endif //CONFIG_MIN_INTERVAL +#endif diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.41-x862/kernel/signal.c linux/kernel/signal.c --- linux-2.5.41-x862/kernel/signal.c Mon Oct 7 15:24:33 2002 +++ linux/kernel/signal.c Mon Oct 7 17:46:04 2002 @@ -424,8 +424,6 @@ if (!collect_signal(sig, 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(); @@ -692,6 +690,7 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t, int shared) { int ret; + struct sigpending *sig_queue; if (!irqs_disabled()) BUG(); @@ -725,20 +724,43 @@ if (ignored_signal(sig, t)) goto out; + sig_queue = shared ? &t->sig->shared_pending : &t->pending; + #define LEGACY_QUEUE(sigptr, sig) \ (((sig) < SIGRTMIN) && sigismember(&(sigptr)->signal, (sig))) - + /* + * Support queueing exactly one non-rt signal, so that we + * can get more detailed information about the cause of + * the signal. + */ + if (LEGACY_QUEUE(sig_queue, 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 = sig_queue->head; q; q = q->next) { + if ((q->info.si_code == SI_TIMER) && + (q->info.si_tid == info->si_tid)) { + q->info.si_overrun += info->si_overrun + 1; + /* + * this special ret value (1) is recognized + * only by posix_timer_fn() in itimer.c + */ + ret = 1; + goto out; + } + } + } if (!shared) { - /* Support queueing exactly one non-rt signal, so that we - can get more detailed information about the cause of - the signal. */ - if (LEGACY_QUEUE(&t->pending, sig)) - goto out; ret = deliver_signal(sig, info, t); } else { - if (LEGACY_QUEUE(&t->sig->shared_pending, sig)) - goto out; ret = send_signal(sig, info, &t->sig->shared_pending); } out: @@ -1418,8 +1440,9 @@ err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_TIMER: - err |= __put_user(from->si_timer1, &to->si_timer1); - err |= __put_user(from->si_timer2, &to->si_timer2); + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_overrun, &to->si_overrun); + err |= __put_user(from->si_ptr, &to->si_ptr); break; case __SI_POLL: err |= __put_user(from->si_band, &to->si_band);