Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Wed, 23 Oct 2002 14:36:13 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Wed, 23 Oct 2002 14:36:13 -0400 Received: from gateway-1237.mvista.com ([12.44.186.158]:13052 "EHLO av.mvista.com") by vger.kernel.org with ESMTP id ; Wed, 23 Oct 2002 14:35:41 -0400 Message-ID: <3DB6ED10.A81B0429@mvista.com> Date: Wed, 23 Oct 2002 11:40:16 -0700 From: george anzinger Organization: Monta Vista Software X-Mailer: Mozilla 4.77 [en] (X11; U; Linux 2.2.12-20b i686) X-Accept-Language: en MIME-Version: 1.0 To: jim.houston@attbi.com CC: linux-kernel@vger.kernel.org, high-res-timers-discourse@lists.sourceforge.net, jim.houston@ccur.com, ak@suse.de Subject: Re: [PATCH] alternate Posix timer patch References: <200210230838.g9N8cac00490@linux.local> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 82562 Lines: 2221 Jim Houston wrote: > > Hi Everyone, > > This is the second version of my spin on the Posix timers. I started > with George Anzinger's patch but I have made major changes. > > I have been using George's version of the patch and would be glad to > see it included into the 2.5 tree. On the other hand since we don't > know what might appeal to Linus it makes sense to give him a choice. > > I sent out the first version of this last friday and had useful > coments from Andi Kleen. I have addressed some of these but mostly > I have just been getting it to work. It now passes most of the > tests that are included in George's timers support package. > > Of particular interest is a race (that Andi pointed out) between > saving a task_struct pointer, using this pointer to send signals > and the process exiting. George please look at my changes in > sys_timer_create and exit_itimer. Yes, I have looked and agree with your changes. They will be in the next version, hopefully today. I have also looked at the timer index stuff and made a few changes. If it get it working today, I will include it also. My changes mostly revolved around not caring about reusing a timer id. Would you care to comment on why you think reuse is bad? With out this feature the code is much simpler and does not keep around dead trees. -g > > Here is a summary of my changes: > > - A new queue just for Posix timers and code to > handle expiring timers. This supports high resolution > without having to change the existing jiffie based timers. > > I implemented this priority queue as a sort list > with a rbtree to index the list. It is deterministic > and fast. > > - Change to use the slab allocator. This removes > the CONFIG option for the maximum number of timers. > > - A new id allocator/lookup mechanism based on a > radix tree. It includes a bitmap to summarize the portion > of the tree which is in use. Currently the Posix > timers patch reuses the id immediately. > > - I keep the timers in seconds and nano-seconds. > I'm hoping that the system time keeping will sort > itself out and the Posix timers can just be a consumer. > Posix timers need two clocks - the time since boot and > the wall clock time. > > I'm currently working on nanosleep. I'm trying to come up with an > alternative for the call to do_signal. At the moment my patch may > return from nanosleep early if it receives a debug signal. > > This patch should work with linux- 2.5.44. > > Jim Houston - Concurrent Computer Corp. > > diff -X /usr1/jhouston/dontdiff -urN linux.orig/arch/i386/kernel/entry.S linux.mytimers/arch/i386/kernel/entry.S > --- linux.orig/arch/i386/kernel/entry.S Wed Oct 23 00:54:19 2002 > +++ linux.mytimers/arch/i386/kernel/entry.S Wed Oct 23 01:17:51 2002 > @@ -737,6 +737,15 @@ > .long sys_free_hugepages > .long sys_exit_group > .long sys_lookup_dcookie > + .long sys_timer_create > + .long sys_timer_settime /* 255 */ > + .long sys_timer_gettime > + .long sys_timer_getoverrun > + .long sys_timer_delete > + .long sys_clock_settime > + .long sys_clock_gettime /* 260 */ > + .long sys_clock_getres > + .long sys_clock_nanosleep > > .rept NR_syscalls-(.-sys_call_table)/4 > .long sys_ni_syscall > diff -X /usr1/jhouston/dontdiff -urN linux.orig/arch/i386/kernel/time.c linux.mytimers/arch/i386/kernel/time.c > --- linux.orig/arch/i386/kernel/time.c Wed Oct 23 00:54:19 2002 > +++ linux.mytimers/arch/i386/kernel/time.c Wed Oct 23 01:17:51 2002 > @@ -131,6 +131,7 @@ > time_maxerror = NTP_PHASE_LIMIT; > time_esterror = NTP_PHASE_LIMIT; > write_unlock_irq(&xtime_lock); > + clock_was_set(); > } > > /* > diff -X /usr1/jhouston/dontdiff -urN linux.orig/fs/exec.c linux.mytimers/fs/exec.c > --- linux.orig/fs/exec.c Wed Oct 23 00:54:21 2002 > +++ linux.mytimers/fs/exec.c Wed Oct 23 01:37:27 2002 > @@ -756,6 +756,7 @@ > > flush_signal_handlers(current); > flush_old_files(current->files); > + exit_itimers(current, 0); > > return 0; > > diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/asm-generic/siginfo.h linux.mytimers/include/asm-generic/siginfo.h > --- linux.orig/include/asm-generic/siginfo.h Wed Oct 23 00:54:24 2002 > +++ linux.mytimers/include/asm-generic/siginfo.h Wed Oct 23 01:17:51 2002 > @@ -43,8 +43,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 */ > @@ -86,8 +87,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 > @@ -221,6 +222,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 > @@ -235,6 +237,7 @@ > int sigev_notify; > union { > int _pad[SIGEV_PAD_SIZE]; > + int _tid; > > struct { > void (*_function)(sigval_t); > @@ -247,6 +250,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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/asm-i386/posix_types.h linux.mytimers/include/asm-i386/posix_types.h > --- linux.orig/include/asm-i386/posix_types.h Tue Jan 18 01:22:52 2000 > +++ linux.mytimers/include/asm-i386/posix_types.h Wed Oct 23 01:17:51 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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/asm-i386/signal.h linux.mytimers/include/asm-i386/signal.h > --- linux.orig/include/asm-i386/signal.h Wed Oct 23 00:50:41 2002 > +++ linux.mytimers/include/asm-i386/signal.h Wed Oct 23 01:17:51 2002 > @@ -219,6 +219,73 @@ > > struct pt_regs; > extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); > +/* > + * These macros are used by nanosleep() and clock_nanosleep(). > + * The issue is that these functions need the *regs pointer which is > + * passed in different ways by the differing archs. > + > + * Below we do things in two differing ways. In the long run we would > + * like to see nano_sleep() go away (glibc should call clock_nanosleep > + * much as we do). When that happens and the nano_sleep() system > + * call entry is retired, there will no longer be any real need for > + * sys_nanosleep() so the FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP macro > + * could be undefined, resulting in not needing to stack all the > + * parms over again, i.e. better (faster AND smaller) code. > + > + * And while were at it, there needs to be a way to set the return code > + * on the way to do_signal(). It (i.e. do_signal()) saves the regs on > + * the callers stack to call the user handler and then the return is > + * done using those registers. This means that the error code MUST be > + * 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 > + > + > +#ifdef FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP > +extern long do_clock_nanosleep(struct pt_regs *regs, > + clockid_t which_clock, > + int flags, > + const struct timespec *rqtp, > + struct timespec *rmtp); > + > +#define NANOSLEEP_ENTRY(a) \ > + asmlinkage long sys_nanosleep( struct timespec* rqtp, \ > + struct timespec * rmtp) \ > +{ struct pt_regs *regs = (struct pt_regs *)&rqtp; \ > + return do_clock_nanosleep(regs, CLOCK_REALTIME, 0, rqtp, rmtp); \ > +} > + > +#define CLOCK_NANOSLEEP_ENTRY(a) asmlinkage long sys_clock_nanosleep( \ > + clockid_t which_clock, \ > + int flags, \ > + const struct timespec *rqtp, \ > + struct timespec *rmtp) \ > +{ struct pt_regs *regs = (struct pt_regs *)&which_clock; \ > + return do_clock_nanosleep(regs, which_clock, flags, rqtp, rmtp); \ > +} \ > +long do_clock_nanosleep(struct pt_regs *regs, \ > + clockid_t which_clock, \ > + int flags, \ > + const struct timespec *rqtp, \ > + struct timespec *rmtp) \ > +{ a > + > +#else > +#define NANOSLEEP_ENTRY(a) \ > + asmlinkage long sys_nanosleep( struct timespec* rqtp, \ > + struct timespec * rmtp) \ > +{ struct pt_regs *regs = (struct pt_regs *)&rqtp; \ > + a > +#define CLOCK_NANOSLEEP_ENTRY(a) asmlinkage long sys_clock_nanosleep( \ > + clockid_t which_clock, \ > + int flags, \ > + const struct timespec *rqtp, \ > + struct timespec *rmtp) \ > +{ struct pt_regs *regs = (struct pt_regs *)&which_clock; \ > + a > +#endif > +#define _do_signal() (regs->eax = -EINTR, do_signal(regs, NULL)) > > #endif /* __KERNEL__ */ > > diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/asm-i386/unistd.h linux.mytimers/include/asm-i386/unistd.h > --- linux.orig/include/asm-i386/unistd.h Wed Oct 23 00:54:21 2002 > +++ linux.mytimers/include/asm-i386/unistd.h Wed Oct 23 01:17:51 2002 > @@ -258,6 +258,15 @@ > #define __NR_free_hugepages 251 > #define __NR_exit_group 252 > #define __NR_lookup_dcookie 253 > +#define __NR_timer_create 254 > +#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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/id2ptr.h linux.mytimers/include/linux/id2ptr.h > --- linux.orig/include/linux/id2ptr.h Wed Dec 31 19:00:00 1969 > +++ linux.mytimers/include/linux/id2ptr.h Wed Oct 23 01:25:23 2002 > @@ -0,0 +1,47 @@ > +/* > + * include/linux/id2ptr.h > + * > + * 2002-10-18 written by Jim Houston jim.houston@ccur.com > + * Copyright (C) 2002 by Concurrent Computer Corporation > + * Distributed under the GNU GPL license version 2. > + * > + * Small id to pointer translation service avoiding fixed sized > + * tables. > + */ > + > +#define ID_BITS 5 > +#define ID_MASK ((1 << ID_BITS)-1) > +#define ID_FULL ((1 << (1 << ID_BITS))-1) > + > +/* Number of id_layer structs to leave in free list */ > +#define ID_FREE_MAX 6 > + > +struct id_layer { > + unsigned int bitmap; > + struct id_layer *ary[1< +}; > + > +struct id { > + int layers; > + int last; > + int count; > + int min_wrap; > + struct id_layer *top; > +}; > + > +void *id2ptr_lookup(struct id *idp, int id); > +int id2ptr_new(struct id *idp, void *ptr); > +void id2ptr_remove(struct id *idp, int id); > +void id2ptr_init(struct id *idp, int min_wrap); > + > + > +static inline void update_bitmap(struct id_layer *p, int bit) > +{ > + if (p->ary[bit] && p->ary[bit]->bitmap == 0xffffffff) > + p->bitmap |= 1< + else > + p->bitmap &= ~(1< +} > + > +extern kmem_cache_t *id_layer_cache; > + > diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/init_task.h linux.mytimers/include/linux/init_task.h > --- linux.orig/include/linux/init_task.h Wed Oct 23 00:54:03 2002 > +++ linux.mytimers/include/linux/init_task.h Wed Oct 23 01:17:51 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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/posix-timers.h linux.mytimers/include/linux/posix-timers.h > --- linux.orig/include/linux/posix-timers.h Wed Dec 31 19:00:00 1969 > +++ linux.mytimers/include/linux/posix-timers.h Wed Oct 23 01:25:02 2002 > @@ -0,0 +1,81 @@ > +/* > + * include/linux/posix-timers.h > + * > + * 2002-10-22 written by Jim Houston jim.houston@ccur.com > + * Copyright (C) 2002 by Concurrent Computer Corporation > + * Distributed under the GNU GPL license version 2. > + * > + */ > + > +#ifndef _linux_POSIX_TIMERS_H > +#define _linux_POSIX_TIMERS_H > + > +/* This should be in posix-timers.h - but this is easier now. */ > + > +enum timer_type { > + TIMER, > + NANOSLEEP > +}; > + > +struct k_itimer { > + struct list_head it_pq_list; /* fields for timer priority queue. */ > + struct rb_node it_pq_node; > + struct timer_pq *it_pq; /* pointer to the queue. */ > + > + struct list_head it_task_list; /* list for exit_itimers */ > + 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 */ > + struct task_struct *it_process; /* process to send signal to */ > + struct itimerspec it_v; /* expiry time & interval */ > + enum timer_type it_type; > +}; > + > +/* > + * The priority queue is a sorted doubly linked list ordered by > + * expiry time. A rbtree is used as an index in to this list > + * so that inserts are O(log2(n)). > + */ > + > +struct timer_pq { > + struct list_head head; > + struct rb_root rb_root; > +}; > + > +#define TIMER_PQ_INIT(name) { \ > + .rb_root = RB_ROOT, \ > + .head = LIST_HEAD_INIT(name.head), \ > +} > + > + > +#if 0 > +#include > +#endif > + > +struct k_clock { > + struct timer_pq pq; > + 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); > +}; > + > +int do_posix_clock_monotonic_gettime(struct timespec *tp); > +int do_posix_clock_monotonic_settime(struct timespec *tp); > +asmlinkage int sys_timer_delete(timer_t timer_id); > + > +#endif > diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/sched.h linux.mytimers/include/linux/sched.h > --- linux.orig/include/linux/sched.h Wed Oct 23 00:54:28 2002 > +++ linux.mytimers/include/linux/sched.h Wed Oct 23 01:31:41 2002 > @@ -29,6 +29,7 @@ > #include > #include > #include > +#include > > struct exec_domain; > > @@ -333,6 +334,8 @@ > 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 */ > + struct k_itimer nanosleep_tmr; > unsigned long utime, stime, cutime, cstime; > unsigned long start_time; > long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; > @@ -637,6 +640,7 @@ > > extern void exit_mm(struct task_struct *); > extern void exit_files(struct task_struct *); > +extern void exit_itimers(struct task_struct *, int); > extern void exit_sighand(struct task_struct *); > extern void __exit_sighand(struct task_struct *); > > diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/signal.h linux.mytimers/include/linux/signal.h > --- linux.orig/include/linux/signal.h Wed Oct 23 00:53:01 2002 > +++ linux.mytimers/include/linux/signal.h Wed Oct 23 01:17:51 2002 > @@ -224,6 +224,36 @@ > struct pt_regs; > extern int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs); > #endif > +/* > + * We would like the asm/signal.h code to define these so that the using > + * function can call do_signal(). In loo of that, we define a genaric > + * version that pretends that do_signal() was called and delivered a signal. > + * To see how this is used, see nano_sleep() in timer.c and the i386 version > + * in asm_i386/signal.h. > + */ > +#ifndef PT_REGS_ENTRY > +#define PT_REGS_ENTRY(type,name,p1_type,p1, p2_type,p2) \ > +type name(p1_type p1,p2_type p2)\ > +{ > +#endif > +#ifndef _do_signal > +#define _do_signal() 1 > +#endif > +#ifndef NANOSLEEP_ENTRY > +#define NANOSLEEP_ENTRY(a) asmlinkage long sys_nanosleep( struct timespec* rqtp, \ > + struct timespec * rmtp) \ > +{ a > +#endif > +#ifndef CLOCK_NANOSLEEP_ENTRY > +#define CLOCK_NANOSLEEP_ENTRY(a) asmlinkage long sys_clock_nanosleep( \ > + clockid_t which_clock, \ > + int flags, \ > + const struct timespec *rqtp, \ > + struct timespec *rmtp) \ > +{ a > + > +#endif > + > > #endif /* __KERNEL__ */ > > diff -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/sys.h linux.mytimers/include/linux/sys.h > --- linux.orig/include/linux/sys.h Sun Dec 10 23:56:37 1995 > +++ linux.mytimers/include/linux/sys.h Wed Oct 23 01:17:51 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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/time.h linux.mytimers/include/linux/time.h > --- linux.orig/include/linux/time.h Wed Oct 23 00:53:34 2002 > +++ linux.mytimers/include/linux/time.h Wed Oct 23 01:17:51 2002 > @@ -38,6 +38,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) > { > @@ -124,6 +137,8 @@ > #ifdef __KERNEL__ > 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); // call when ever the clock is set > #endif > > #define FD_SETSIZE __FD_SETSIZE > @@ -149,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 -X /usr1/jhouston/dontdiff -urN linux.orig/include/linux/types.h linux.mytimers/include/linux/types.h > --- linux.orig/include/linux/types.h Wed Oct 23 00:54:17 2002 > +++ linux.mytimers/include/linux/types.h Wed Oct 23 01:17:51 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 -X /usr1/jhouston/dontdiff -urN linux.orig/init/Config.help linux.mytimers/init/Config.help > --- linux.orig/init/Config.help Wed Oct 23 00:50:42 2002 > +++ linux.mytimers/init/Config.help Wed Oct 23 01:17:51 2002 > @@ -115,3 +115,11 @@ > replacement for kerneld.) Say Y here and read about configuring it > in . > > +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 -X /usr1/jhouston/dontdiff -urN linux.orig/init/Config.in linux.mytimers/init/Config.in > --- linux.orig/init/Config.in Wed Oct 23 00:50:45 2002 > +++ linux.mytimers/init/Config.in Wed Oct 23 01:17:51 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 > endmenu > > mainmenu_option next_comment > diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/Makefile linux.mytimers/kernel/Makefile > --- linux.orig/kernel/Makefile Wed Oct 23 00:54:21 2002 > +++ linux.mytimers/kernel/Makefile Wed Oct 23 01:24:01 2002 > @@ -10,7 +10,7 @@ > module.o exit.o itimer.o time.o softirq.o resource.o \ > sysctl.o capability.o ptrace.o timer.o user.o \ > signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \ > - rcupdate.o > + rcupdate.o posix-timers.o id2ptr.o > > obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o > obj-$(CONFIG_SMP) += cpu.o > diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/exit.c linux.mytimers/kernel/exit.c > --- linux.orig/kernel/exit.c Wed Oct 23 00:54:21 2002 > +++ linux.mytimers/kernel/exit.c Wed Oct 23 01:22:00 2002 > @@ -647,6 +647,7 @@ > __exit_files(tsk); > __exit_fs(tsk); > exit_namespace(tsk); > + exit_itimers(tsk, 1); > exit_thread(); > > if (current->leader) > diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/fork.c linux.mytimers/kernel/fork.c > --- linux.orig/kernel/fork.c Wed Oct 23 00:54:17 2002 > +++ linux.mytimers/kernel/fork.c Wed Oct 23 01:17:51 2002 > @@ -783,6 +783,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 -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/id2ptr.c linux.mytimers/kernel/id2ptr.c > --- linux.orig/kernel/id2ptr.c Wed Dec 31 19:00:00 1969 > +++ linux.mytimers/kernel/id2ptr.c Wed Oct 23 01:23:24 2002 > @@ -0,0 +1,223 @@ > +/* > + * linux/kernel/id2ptr.c > + * > + * 2002-10-18 written by Jim Houston jim.houston@ccur.com > + * Copyright (C) 2002 by Concurrent Computer Corporation > + * Distributed under the GNU GPL license version 2. > + * > + * Small id to pointer translation service. > + * > + * It uses a radix tree like structure as a sparse array indexed > + * by the id to obtain the pointer. A bit map is included in each > + * level of the tree which identifies portions of the tree which > + * are completely full. This makes the process of allocating a > + * new id quick. > + */ > + > + > +#include > +#include > +#include > +#include > + > +static kmem_cache_t *id_layer_cache; > +spinlock_t id_lock = SPIN_LOCK_UNLOCKED; > + > +/* > + * Since we can't allocate memory with spinlock held and dropping the > + * lock to allocate gets ugly keep a free list which will satisfy the > + * worst case allocation. > + */ > + > +struct id_layer *id_free; > +int id_free_cnt; > + > +static inline struct id_layer *alloc_layer(void) > +{ > + struct id_layer *p; > + > + if (!(p = id_free)) > + BUG(); > + id_free = p->ary[0]; > + id_free_cnt--; > + p->ary[0] = 0; > + return(p); > +} > + > +static inline void free_layer(struct id_layer *p) > +{ > + p->ary[0] = id_free; > + id_free = p; > + id_free_cnt++; > +} > + > +/* > + * Lookup the kernel pointer associated with a user supplied > + * id value. > + */ > +void *id2ptr_lookup(struct id *idp, int id) > +{ > + int n; > + struct id_layer *p; > + > + if (id <= 0) > + return(NULL); > + id--; > + spin_lock_irq(&id_lock); > + n = idp->layers * ID_BITS; > + p = idp->top; > + if (id >= (1 << n)) { > + spin_unlock_irq(&id_lock); > + return(NULL); > + } > + > + while (n > 0 && p) { > + n -= ID_BITS; > + p = p->ary[(id >> n) & ID_MASK]; > + } > + spin_unlock_irq(&id_lock); > + return((void *)p); > +} > + > +static int sub_alloc(struct id_layer *p, int shift, int id, void *ptr) > +{ > + int n = (id >> shift) & ID_MASK; > + int bitmap = p->bitmap; > + int id_base = id & ~((1 << (shift+ID_BITS))-1); > + int v; > + > + for ( ; n <= ID_MASK; n++, id = id_base + (n << shift)) { > + if (bitmap & (1 << n)) > + continue; > + if (shift == 0) { > + p->ary[n] = (struct id_layer *)ptr; > + p->bitmap |= 1< + return(id); > + } > + if (!p->ary[n]) > + p->ary[n] = alloc_layer(); > + if ((v = sub_alloc(p->ary[n], shift-ID_BITS, id, ptr))) { > + update_bitmap(p, n); > + return(v); > + } > + } > + return(0); > +} > + > +/* > + * Allocate a new id associate the value ptr with this new id. > + */ > +int id2ptr_new(struct id *idp, void *ptr) > +{ > + int n, last, id, v; > + struct id_layer *new; > + > + spin_lock_irq(&id_lock); > + n = idp->layers * ID_BITS; > + last = idp->last; > + while (id_free_cnt < n+1) { > + spin_unlock_irq(&id_lock); > + new = kmem_cache_alloc(id_layer_cache, GFP_KERNEL); > + memset(new, 0, sizeof(struct id_layer)); > + spin_lock_irq(&id_lock); > + free_layer(new); > + } > + /* > + * Add a new layer if the array is full or the last id > + * was at the limit and we don't want to wrap. > + */ > + if ((last == ((1 << n)-1) && last < idp->min_wrap) || > + idp->count == (1 << n)) { > + ++idp->layers; > + n += ID_BITS; > + new = alloc_layer(); > + new->ary[0] = idp->top; > + idp->top = new; > + update_bitmap(new, 0); > + } > + if (last >= ((1 << n)-1)) > + last = 0; > + > + /* > + * Search for a free id starting after last id allocated. > + * If that fails wrap back to start. > + */ > + id = last+1; > + if (!(v = sub_alloc(idp->top, n-ID_BITS, id, ptr))) > + v = sub_alloc(idp->top, n-ID_BITS, 1, ptr); > + idp->last = v; > + idp->count++; > + spin_unlock_irq(&id_lock); > + return(v+1); > +} > + > + > +static int sub_remove(struct id_layer *p, int shift, int id) > +{ > + int n = (id >> shift) & ID_MASK; > + int i, bitmap, rv; > + > + rv = 0; > + bitmap = p->bitmap & ~(1< + p->bitmap = bitmap; > + if (shift == 0) { > + p->ary[n] = NULL; > + rv = !bitmap; > + } else { > + if (sub_remove(p->ary[n], shift-ID_BITS, id)) { > + free_layer(p->ary[n]); > + p->ary[n] = 0; > + for (i = 0; i < (1 << ID_BITS); i++) > + if (p->ary[i]) > + break; > + if (i == (1 << ID_BITS)) > + rv = 1; > + } > + } > + return(rv); > +} > + > +/* > + * Remove (free) an id value and break the association with > + * the kernel pointer. > + */ > +void id2ptr_remove(struct id *idp, int id) > +{ > + struct id_layer *p; > + > + if (id <= 0) > + return; > + id--; > + spin_lock_irq(&id_lock); > + sub_remove(idp->top, (idp->layers-1)*ID_BITS, id); > + idp->count--; > + if (id_free_cnt >= ID_FREE_MAX) { > + > + p = alloc_layer(); > + spin_unlock_irq(&id_lock); > + kmem_cache_free(id_layer_cache, p); > + return; > + } > + spin_unlock_irq(&id_lock); > +} > + > +void init_id_cache(void) > +{ > + if (!id_layer_cache) > + id_layer_cache = kmem_cache_create("id_layer_cache", > + sizeof(struct id_layer), 0, 0, 0, 0); > +} > + > +void id2ptr_init(struct id *idp, int min_wrap) > +{ > + init_id_cache(); > + idp->count = 1; > + idp->last = 0; > + idp->layers = 1; > + idp->top = kmem_cache_alloc(id_layer_cache, GFP_KERNEL); > + memset(idp->top, 0, sizeof(struct id_layer)); > + idp->top->bitmap = 0; > + idp->min_wrap = min_wrap; > +} > + > +__initcall(init_id_cache); > diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/posix-timers.c linux.mytimers/kernel/posix-timers.c > --- linux.orig/kernel/posix-timers.c Wed Dec 31 19:00:00 1969 > +++ linux.mytimers/kernel/posix-timers.c Wed Oct 23 01:56:45 2002 > @@ -0,0 +1,1109 @@ > +/* > + * linux/kernel/posix_timers.c > + * > + * > + * 2002-10-15 Posix Clocks & timers by George Anzinger > + * Copyright (C) 2002 by MontaVista Software. > + * > + * 2002-10-18 changes by Jim Houston jim.houston@attbi.com > + * Copyright (C) 2002 by Concurrent Computer Corp. > + * > + * - Add a separate queue for posix timers. Its a > + * priority queue implemented as a sorted doubly > + * linked list & a rbtree as an index into the list. > + * - Use a slab cache to allocate the timer structures. > + * - Allocate timer ids using my new id allocator. > + * This avoids the immediate reuse of timer ids. > + * - Uses seconds and nano-seconds rather than > + * jiffies and sub_jiffies. > + * > + * This is an experimental change. I'm sending it out to > + * the mailing list in the hope that it will stimulate > + * discussion. > + */ > + > +/* These are all the functions necessary to implement > + * POSIX clocks & timers > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > + > +#ifndef div_long_long_rem > +#include > + > +#define div_long_long_rem(dividend,divisor,remainder) ({ \ > + u64 result = dividend; \ > + *remainder = do_div(result,divisor); \ > + result; }) > + > +#endif /* ifndef div_long_long_rem */ > + > + > +/* > + * Lets keep our timers in a slab cache :-) > + */ > +static kmem_cache_t *posix_timers_cache; > +struct id posix_timers_id; > + > +/* > + * This lock portects the timer queues it is held for the > + * duration of the timer expiry process. > + */ > +spinlock_t posix_timers_lock = SPIN_LOCK_UNLOCKED; > + > +/* > + * Kluge until I can wire into the timer interrupt. > + */ > +int poll_timer_running; > +void run_posix_timers(unsigned long dummy); > +static struct timer_list poll_posix_timers = { > + .function = &run_posix_timers, > +}; > + > +struct k_clock clock_realtime = { > + .pq = TIMER_PQ_INIT(clock_realtime.pq), > + .res = NSEC_PER_SEC/HZ, > +}; > + > +struct k_clock clock_monotonic = { > + .pq = TIMER_PQ_INIT(clock_monotonic.pq), > + .res= NSEC_PER_SEC/HZ, > + .clock_get = do_posix_clock_monotonic_gettime, > + .clock_set = do_posix_clock_monotonic_settime > +}; > + > +/* > + * Insert a timer into a priority queue. This is a sorted > + * list of timers. A rbtree is used to index the list. > + */ > + > +static int timer_insert_nolock(struct timer_pq *pq, struct k_itimer *t) > +{ > + struct rb_node ** p = &pq->rb_root.rb_node; > + struct rb_node * parent = NULL; > + struct k_itimer *cur; > + struct list_head *prev; > + prev = &pq->head; > + > + if (t->it_pq) > + BUG(); > + t->it_pq = pq; > + while (*p) { > + parent = *p; > + cur = rb_entry(parent, struct k_itimer , it_pq_node); > + > + /* > + * We allow non unique entries. This works > + * but there might be opportunity to do something > + * clever. > + */ > + if (t->it_v.it_value.tv_sec < cur->it_v.it_value.tv_sec || > + (t->it_v.it_value.tv_sec == cur->it_v.it_value.tv_sec && > + t->it_v.it_value.tv_nsec < cur->it_v.it_value.tv_nsec)) > + p = &(*p)->rb_left; > + else { > + prev = &cur->it_pq_list; > + p = &(*p)->rb_right; > + } > + } > + /* link into rbtree. */ > + rb_link_node(&t->it_pq_node, parent, p); > + rb_insert_color(&t->it_pq_node, &pq->rb_root); > + /* link it into the list */ > + list_add(&t->it_pq_list, prev); > + /* > + * We need to setup a timer interrupt if the new timer is > + * at the head of the queue. > + */ > + return(pq->head.next == &t->it_pq_list); > +} > + > +static inline void timer_remove_nolock(struct k_itimer *t) > +{ > + struct timer_pq *pq; > + > + if (!(pq = t->it_pq)) > + return; > + rb_erase(&t->it_pq_node, &pq->rb_root); > + list_del(&t->it_pq_list); > + t->it_pq = 0; > +} > + > +static void timer_remove(struct k_itimer *t) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&posix_timers_lock, flags); > + timer_remove_nolock(t); > + spin_unlock_irqrestore(&posix_timers_lock, flags); > +} > + > + > +static int timer_insert(struct timer_pq *pq, struct k_itimer *t) > +{ > + unsigned long flags; > + int rv; > + > + spin_lock_irqsave(&posix_timers_lock, flags); > + rv = timer_insert_nolock(pq, t); > + spin_unlock_irqrestore(&posix_timers_lock, flags); > + if (!poll_timer_running) { > + poll_timer_running = 1; > + poll_posix_timers.expires = jiffies + 1; > + add_timer(&poll_posix_timers); > + } > + return(rv); > +} > + > +/* > + * If we are late delivering a periodic timer we may > + * have missed several expiries. We want to calculate the > + * number we have missed both as the overrun count but also > + * so that we can pick next expiry. > + * > + * You really need this if you schedule a high frequency timer > + * and then make a big change to the current time. > + */ > + > +int handle_overrun(struct k_itimer *t, struct timespec dt) > +{ > + int ovr; > +#if 0 > + long long ldt, in; > + long sec, nsec; > + > + in = (long long)t->it_v.it_interval.tv_sec*1000000000 + > + t->it_v.it_interval.tv_nsec; > + ldt = (long long)dt.tv_sec * 1000000000 + dt.tv_nsec; > + ovr = ldt/in + 1; > + ldt = (long long)t->it_v.it_interval.tv_nsec * ovr; > + nsec = ldt % 1000000000; > + sec = ldt / 1000000000; > + sec += ovr * t->it_v.it_interval.tv_sec; > + nsec += t->it_v.it_value.tv_nsec; > + sec += t->it_v.it_value.tv_sec; > + if (nsec > 1000000000) { > + sec++; > + nsec -= 1000000000; > + } > + t->it_v.it_value.tv_sec = sec; > + t->it_v.it_value.tv_nsec = nsec; > +#else > + /* Temporary hack */ > + ovr = 0; > + while (dt.tv_sec > t->it_v.it_interval.tv_sec || > + (dt.tv_sec == t->it_v.it_interval.tv_sec && > + dt.tv_nsec > t->it_v.it_interval.tv_nsec)) { > + dt.tv_sec -= t->it_v.it_interval.tv_sec; > + dt.tv_nsec -= t->it_v.it_interval.tv_nsec; > + if (dt.tv_nsec < 0) { > + dt.tv_sec--; > + dt.tv_nsec += 1000000000; > + } > + t->it_v.it_value.tv_sec += t->it_v.it_interval.tv_sec; > + t->it_v.it_value.tv_nsec += t->it_v.it_interval.tv_nsec; > + if (t->it_v.it_value.tv_nsec >= 1000000000) { > + t->it_v.it_value.tv_sec++; > + t->it_v.it_value.tv_nsec -= 1000000000; > + } > + ovr++; > + } > +#endif > + return(ovr); > +} > + > +int sending_signal_failed; > + > +/* > + * Yes I calculate an overrun but don't deliver it. I need to > + * play with this code. > + */ > +static void timer_notify_task(struct k_itimer *timr, int ovr) > +{ > + 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: > + sending_signal_failed++; > + break; > + } > + } > +} > + > +void do_expiry(struct k_itimer *t, int ovr) > +{ > + switch (t->it_type) { > + case TIMER: > + timer_notify_task(t, ovr); > + return; > + case NANOSLEEP: > + wake_up_process(t->it_process); > + return; > + } > +} > + > +/* > + * Check if the timer at the head of the priority queue has > + * expired and handle the expiry. Return time in nsec till > + * the next expiry. We only really care about expiries > + * before the next clock tick so we use a 32 bit int here. > + */ > + > +static int check_expiry(struct timer_pq *pq, struct timespec *tv) > +{ > + struct k_itimer *t; > + struct timespec dt; > + int ovr; > + long sec, nsec; > + unsigned long flags; > + > + ovr = 1; > + spin_lock_irqsave(&posix_timers_lock, flags); > + while (!list_empty(&pq->head)) { > + t = list_entry(pq->head.next, struct k_itimer, it_pq_list); > + dt.tv_sec = tv->tv_sec - t->it_v.it_value.tv_sec; > + dt.tv_nsec = tv->tv_nsec - t->it_v.it_value.tv_nsec; > + if (dt.tv_sec < 0 || (dt.tv_sec == 0 && dt.tv_nsec < 0)) { > + /* > + * It has not expired yet. Return nano-seconds > + * remaining if its less than a second. > + */ > + if (dt.tv_sec < -1) > + nsec = -1; > + else > + nsec = dt.tv_sec ? 1000000000-dt.tv_nsec : > + -dt.tv_nsec; > + spin_unlock_irqrestore(&posix_timers_lock, flags); > + return(nsec); > + } > + /* > + * Its expired. If this is a periodic timer we need to > + * setup for the next expiry. We also check for overrun > + * here. If the timer has already missed an expiry we want > + * deliver the overrun information and get back on schedule. > + */ > + if (dt.tv_nsec < 0) { > + dt.tv_sec--; > + dt.tv_nsec += 1000000000; > + } > + timer_remove_nolock(t); > + if (t->it_v.it_interval.tv_sec || t->it_v.it_interval.tv_nsec) { > + if (dt.tv_sec > t->it_v.it_interval.tv_sec || > + (dt.tv_sec == t->it_v.it_interval.tv_sec && > + dt.tv_nsec > t->it_v.it_interval.tv_nsec)) { > + ovr = handle_overrun(t, dt); > + } else { > + nsec = t->it_v.it_value.tv_nsec + > + t->it_v.it_interval.tv_nsec; > + sec = t->it_v.it_value.tv_sec + > + t->it_v.it_interval.tv_sec; > + if (nsec > 1000000000) { > + nsec -= 1000000000; > + sec++; > + } > + t->it_v.it_value.tv_sec = sec; > + t->it_v.it_value.tv_nsec = nsec; > + } > + /* > + * It might make sense to leave the timer queue and > + * avoid the remove/insert for timers which stay > + * at the front of the queue. > + */ > + timer_insert_nolock(pq, t); > + } > + do_expiry(t, ovr); > + } > + spin_unlock_irqrestore(&posix_timers_lock, flags); > + return(-1); > +} > + > +/* > + * kluge? We should know the offset between clock_realtime and > + * clock_monotonic so we don't need to get the time twice. > + */ > + > +void run_posix_timers(unsigned long dummy) > +{ > + struct timespec now; > + int ns, ret; > + > + ns = 0x7fffffff; > + do_posix_clock_monotonic_gettime(&now); > + ret = check_expiry(&clock_monotonic.pq, &now); > + if (ret > 0 && ret < ns) > + ns = ret; > + > + do_gettimeofday((struct timeval*)&now); > + now.tv_nsec *= NSEC_PER_USEC; > + ret = check_expiry(&clock_realtime.pq, &now); > + if (ret > 0 && ret < ns) > + ns = ret; > + poll_posix_timers.expires = jiffies + 1; > + add_timer(&poll_posix_timers); > +} > + > + > +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); > + > + > +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 __init int init_posix_timers(void) > +{ > + posix_timers_cache = kmem_cache_create("posix_timers_cache", > + sizeof(struct k_itimer), 0, 0, 0, 0); > + id2ptr_init(&posix_timers_id, 1000); > + > + register_posix_clock(CLOCK_REALTIME,&clock_realtime); > + register_posix_clock(CLOCK_MONOTONIC,&clock_monotonic); > + return 0; > +} > + > +__initcall(init_posix_timers); > + > +/* > + * 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 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; > +} > + > + > + > +static struct k_itimer * alloc_posix_timer(void) > +{ > + struct k_itimer *tmr; > + tmr = kmem_cache_alloc(posix_timers_cache, GFP_KERNEL); > + memset(tmr, 0, sizeof(struct k_itimer)); > + return(tmr); > +} > + > +static void release_posix_timer(struct k_itimer *tmr) > +{ > + if (tmr->it_id > 0) > + id2ptr_remove(&posix_timers_id, tmr->it_id); > + kmem_cache_free(posix_timers_cache, tmr); > +} > + > +/* 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 = 0; > + sigevent_t event; > + > + if ((unsigned)which_clock >= MAX_CLOCKS || !posix_clocks[which_clock]) > + return -EINVAL; > + > + new_timer = alloc_posix_timer(); > + if (new_timer == NULL) return -EAGAIN; > + > + new_timer_id = (timer_t)id2ptr_new(&posix_timers_id, > + (void *)new_timer); > + if (!new_timer_id) { > + error = -EAGAIN; > + goto out; > + } > + new_timer->it_id = new_timer_id; > + > + if (copy_to_user(created_timer_id, &new_timer_id, > + sizeof(new_timer_id))) { > + error = -EFAULT; > + goto out; > + } > + spin_lock_init(&new_timer->it_lock); > + if (timer_event_spec) { > + if (copy_from_user(&event, timer_event_spec, sizeof(event))) { > + error = -EFAULT; > + goto out; > + } > + read_lock(&tasklist_lock); > + if ((process = good_sigevent(&event))) { > + /* > + * We may be setting up this timer for another > + * thread. It may be exitiing. To catch this > + * case the we clear posix_timers.next in > + * exit_itimers. > + */ > + spin_lock(&process->alloc_lock); > + if (process->posix_timers.next) { > + list_add(&new_timer->it_task_list, > + &process->posix_timers); > + spin_unlock(&process->alloc_lock); > + } else { > + spin_unlock(&process->alloc_lock); > + process = 0; > + } > + } > + read_unlock(&tasklist_lock); > + if (!process) { > + 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; > + process = current; > + spin_lock(¤t->alloc_lock); > + list_add(&new_timer->it_task_list, ¤t->posix_timers); > + spin_unlock(¤t->alloc_lock); > + } > + new_timer->it_clock = which_clock; > + new_timer->it_overrun = 0; > + new_timer->it_process = process; > + > + out: > + if (error) > + release_posix_timer(new_timer); > + return error; > +} > + > + > +/* > + * 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(); > + } > +} > + > +/* > + * This is call from both exec and exit to shutdown the > + * timers. > + */ > + > +inline void exit_itimers(struct task_struct *tsk, int exit) > +{ > + struct k_itimer *tmr; > + > + if (!tsk->posix_timers.next) > + BUG(); > + if (tsk->nanosleep_tmr.it_pq) > + timer_remove(&tsk->nanosleep_tmr); > + spin_lock(&tsk->alloc_lock); > + while (tsk->posix_timers.next != &tsk->posix_timers){ > + spin_unlock(&tsk->alloc_lock); > + tmr = list_entry(tsk->posix_timers.next,struct k_itimer, > + it_task_list); > + itimer_delete(tmr); > + spin_lock(&tsk->alloc_lock); > + } > + /* > + * sys_timer_create has the option to create a timer > + * for another thread. There is the risk that as the timer > + * is being created that the thread that was supposed to handle > + * the signal is exiting. We use the posix_timers.next field > + * as a flag so we can close this race. > +` */ > + if (exit) > + tsk->posix_timers.next = 0; > + spin_unlock(&tsk->alloc_lock); > +} > + > +/* 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; > + > + timr = (struct k_itimer *)id2ptr_lookup(&posix_timers_id, > + (int)timer_id); > + if (timr) > + spin_lock_irq(&timr->it_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) > +{ > + struct timespec ts; > + > + do_posix_gettime(posix_clocks[timr->it_clock], &ts); > + ts.tv_sec = timr->it_v.it_value.tv_sec - ts.tv_sec; > + ts.tv_nsec = timr->it_v.it_value.tv_nsec - ts.tv_nsec; > + if (ts.tv_nsec < 0) { > + ts.tv_nsec += 1000000000; > + ts.tv_sec--; > + } > + if (ts.tv_sec < 0) > + ts.tv_sec = ts.tv_nsec = 0; > + cur_setting->it_value = ts; > + cur_setting->it_interval = timr->it_v.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(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; > +} > + > +/* > + * If it is relative time, we need to add the current time to it to > + * get the proper expiry time. > + */ > +static int adjust_rel_time(struct k_clock *clock,struct timespec *tp) > +{ > + struct timespec now; > + > + > + do_posix_gettime(clock,&now); > + tp->tv_sec += now.tv_sec; > + tp->tv_nsec += now.tv_nsec; > + > + /* > + * Normalize... > + */ > + if (( tp->tv_nsec - NSEC_PER_SEC) >= 0){ > + tp->tv_nsec -= NSEC_PER_SEC; > + tp->tv_sec++; > + } > + 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]; > + > + timer_remove(timr); > + 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_v = *new_setting; > + return 0; > + } > + > + if (!(flags & TIMER_ABSTIME)) > + adjust_rel_time(clock, &new_setting->it_value); > + > + timr->it_v = *new_setting; > + timr->it_overrun_deferred = > + timr->it_overrun_last = > + timr->it_overrun = 0; > + timer_insert(&clock->pq, timr); > + 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; > + } > + > + 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 (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_remove(timer); > + return 0; > +} > + > +/* Delete a POSIX.1b interval timer. */ > +asmlinkage int sys_timer_delete(timer_t timer_id) > +{ > + struct k_itimer *timer; > + > + timer = lock_timer( timer_id); > + if (!timer) > + return -EINVAL; > + > + p_timer_del(posix_clocks[timer->it_clock],timer); > + > + spin_lock(&timer->it_process->alloc_lock); > + list_del(&timer->it_task_list); > + spin_unlock(&timer->it_process->alloc_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; > +} > +/* > + * 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); > + } > + > + do_gettimeofday((struct timeval*)tp); > + tp->tv_nsec *= NSEC_PER_USEC; > + 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 (BITS_PER_LONG > 32) > + > + 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; > + > + > + read_unlock_irqrestore(&xtime_lock, flags); > + } > +#elif ! defined(CONFIG_SMP) && (BITS_PER_LONG < 64) > + unsigned long jiffies_f; > + do { > + jiffies_f = jiffies; > + barrier(); > + jiffies_64_f = jiffies_64; > + } while (unlikely(jiffies_f != jiffies)); > + > + > +#endif > + tp->tv_sec = div_long_long_rem(jiffies_64_f,HZ,&sub_sec); > + > + tp->tv_nsec = sub_sec * (NSEC_PER_SEC / HZ); > + 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]) > + 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]) > + 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]) > + 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; > + > +} > + > +#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 ts; > + struct k_itimer *t; > + struct k_clock * clock; > + 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]) > + return -EINVAL; > + /* > + * See discussion below about waking up early. > + */ > + clock = posix_clocks[which_clock]; > + t = ¤t->nanosleep_tmr; > + if (t->it_pq) > + timer_remove(t); > + > + if(copy_from_user(&t->it_v.it_value, rqtp, sizeof(struct timespec))) > + return -EFAULT; > + > + if ((t->it_v.it_value.tv_nsec < 0) || > + (t->it_v.it_value.tv_nsec >= NSEC_PER_SEC) || > + (t->it_v.it_value.tv_sec < 0)) > + return -EINVAL; > + > + if (!(flags & TIMER_ABSTIME)) > + adjust_rel_time(clock, &t->it_v.it_value); > + /* > + * These fields don't need to be setup each time. This > + * should be in the INIT_TASK() and forgoten. > + */ > + t->it_v.it_interval.tv_sec = 0; > + t->it_v.it_interval.tv_nsec = 0; > + t->it_type = NANOSLEEP; > + t->it_process = current; > + > + current->state = TASK_INTERRUPTIBLE; > + timer_insert(&clock->pq, t); > + schedule(); > + /* > + * Were not supposed to leave early. The problem is > + * being woken by signals that are not delivered to > + * the user. Typically this means debug related > + * signals. > + * > + * My plan is to leave the timer running and have a > + * small hook in do_signal which will complete the > + * nanosleep. For now we just return early in clear > + * violation of the Posix spec. > + */ > + active = (t->it_pq != 0); > + if (!(flags & TIMER_ABSTIME) && active && rmtp ) { > + do_posix_gettime(clock, &ts); > + ts.tv_sec = t->it_v.it_value.tv_sec - ts.tv_sec; > + ts.tv_nsec = t->it_v.it_value.tv_nsec - ts.tv_nsec; > + if (ts.tv_nsec < 0) { > + ts.tv_nsec += 1000000000; > + ts.tv_sec--; > + } > + if (ts.tv_sec < 0) > + ts.tv_sec = ts.tv_nsec = 0; > + if (copy_to_user(rmtp, &ts, sizeof(struct timespec))) > + return -EFAULT; > + } > + if (active) > + return -EINTR; > + return 0; > +} > + > +void clock_was_set(void) > +{ > +} > diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/signal.c linux.mytimers/kernel/signal.c > --- linux.orig/kernel/signal.c Wed Oct 23 00:54:30 2002 > +++ linux.mytimers/kernel/signal.c Wed Oct 23 01:17:51 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); > diff -X /usr1/jhouston/dontdiff -urN linux.orig/kernel/timer.c linux.mytimers/kernel/timer.c > --- linux.orig/kernel/timer.c Wed Oct 23 00:54:21 2002 > +++ linux.mytimers/kernel/timer.c Wed Oct 23 01:17:51 2002 > @@ -47,12 +47,11 @@ > struct list_head vec[TVR_SIZE]; > } tvec_root_t; > > -typedef struct timer_list timer_t; > > struct tvec_t_base_s { > spinlock_t lock; > unsigned long timer_jiffies; > - timer_t *running_timer; > + struct timer_list *running_timer; > tvec_root_t tv1; > tvec_t tv2; > tvec_t tv3; > @@ -67,7 +66,7 @@ > /* Fake initialization needed to avoid compiler breakage */ > static DEFINE_PER_CPU(struct tasklet_struct, timer_tasklet) = { NULL }; > > -static inline void internal_add_timer(tvec_base_t *base, timer_t *timer) > +static inline void internal_add_timer(tvec_base_t *base, struct timer_list *timer) > { > unsigned long expires = timer->expires; > unsigned long idx = expires - base->timer_jiffies; > @@ -119,7 +118,7 @@ > * Timers with an ->expired field in the past will be executed in the next > * timer tick. It's illegal to add an already pending timer. > */ > -void add_timer(timer_t *timer) > +void add_timer(struct timer_list *timer) > { > int cpu = get_cpu(); > tvec_base_t *base = tvec_bases + cpu; > @@ -153,7 +152,7 @@ > * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an > * active timer returns 1.) > */ > -int mod_timer(timer_t *timer, unsigned long expires) > +int mod_timer(struct timer_list *timer, unsigned long expires) > { > tvec_base_t *old_base, *new_base; > unsigned long flags; > @@ -226,7 +225,7 @@ > * (ie. del_timer() of an inactive timer returns 0, del_timer() of an > * active timer returns 1.) > */ > -int del_timer(timer_t *timer) > +int del_timer(struct timer_list *timer) > { > unsigned long flags; > tvec_base_t *base; > @@ -263,7 +262,7 @@ > * > * The function returns whether it has deactivated a pending timer or not. > */ > -int del_timer_sync(timer_t *timer) > +int del_timer_sync(struct timer_list *timer) > { > tvec_base_t *base = tvec_bases; > int i, ret = 0; > @@ -302,9 +301,9 @@ > * detach them individually, just clear the list afterwards. > */ > while (curr != head) { > - timer_t *tmp; > + struct timer_list *tmp; > > - tmp = list_entry(curr, timer_t, entry); > + tmp = list_entry(curr, struct timer_list, entry); > if (tmp->base != base) > BUG(); > next = curr->next; > @@ -343,9 +342,9 @@ > if (curr != head) { > void (*fn)(unsigned long); > unsigned long data; > - timer_t *timer; > + struct timer_list *timer; > > - timer = list_entry(curr, timer_t, entry); > + timer = list_entry(curr, struct timer_list, entry); > fn = timer->function; > data = timer->data; > > @@ -448,6 +447,7 @@ > if (xtime.tv_sec % 86400 == 0) { > xtime.tv_sec--; > time_state = TIME_OOP; > + clock_was_set(); > printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n"); > } > break; > @@ -456,6 +456,7 @@ > if ((xtime.tv_sec + 1) % 86400 == 0) { > xtime.tv_sec++; > time_state = TIME_WAIT; > + clock_was_set(); > printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n"); > } > break; > @@ -912,7 +913,7 @@ > */ > signed long schedule_timeout(signed long timeout) > { > - timer_t timer; > + struct timer_list timer; > unsigned long expire; > > switch (timeout) > @@ -968,10 +969,32 @@ > return current->pid; > } > > -asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) > +#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_nanosleep(void) > { > - struct timespec t; > - unsigned long expire; > +#endif > + NANOSLEEP_ENTRY( struct timespec t; > + unsigned long expire;) > + > +#ifndef FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP > + // The following code expects rqtp, rmtp to be available > + // as a result of the above macro. Also any regs needed > + // for the _do_signal() macro shoule be set up here. > + > + //asmlinkage long sys_nanosleep(struct timespec *rqtp, > + // struct timespec *rmtp) > + // { > + // struct timespec t; > + // unsigned long expire; > + > > if(copy_from_user(&t, rqtp, sizeof(struct timespec))) > return -EFAULT; > @@ -994,6 +1017,7 @@ > } > return 0; > } > +#endif // ! FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP > > /* > * sys_sysinfo - fill in sysinfo struct > - > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ -- George Anzinger george@mvista.com High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/