diff options
| author | George Anzinger <george@mvista.com> | 2003-02-17 22:41:13 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-02-17 22:41:13 -0800 |
| commit | db8b50ba75f208be80e63366f124f064283f971c (patch) | |
| tree | d41564415753de17870d2a3d5423d3492989f3cd /kernel | |
| parent | 307d18496fb5b3182c06f90faede52458ddd7f4f (diff) | |
[PATCH] POSIX clocks & timers
This is version 23 or so of the POSIX timer code.
Internal changelog:
- Changed the signals code to match the new order of things. Also the
new xtime_lock code needed to be picked up. It made some things a lot
simpler.
- Fixed a spin lock hand off problem in locking timers (thanks
to Randy).
- Fixed nanosleep to test for out of bound nanoseconds
(thanks to Julie).
- Fixed a couple of id deallocation bugs that left old ids
laying around (hey I get this one).
- This version has a new timer id manager. Andrew Morton
suggested elimination of recursion (done) and I added code
to allow it to release unused nodes. The prior version only
released the leaf nodes. (The id manager uses radix tree
type nodes.) Also added is a reuse count so ids will not
repeat for at least 256 alloc/ free cycles.
- The changes for the new sys_call restart now allow one
restart function to handle both nanosleep and clock_nanosleep.
Saves a bit of code, nice.
- All the requested changes and Lindent too :).
- I also broke clock_nanosleep() apart much the same way
nanosleep() was with the 2.5.50-bk5 changes.
TIMER STORMS
The POSIX clocks and timers code prevents "timer storms" by
not putting repeating timers back in the timer list until
the signal is delivered for the prior expiry. Timer events
missed by this delay are accounted for in the timer overrun
count. The net result is MUCH lower system overhead while
presenting the same info to the user as would be the case if
an interrupt and timer processing were required for each
increment in the overrun count.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Makefile | 2 | ||||
| -rw-r--r-- | kernel/exit.c | 2 | ||||
| -rw-r--r-- | kernel/fork.c | 1 | ||||
| -rw-r--r-- | kernel/posix-timers.c | 1318 | ||||
| -rw-r--r-- | kernel/signal.c | 52 | ||||
| -rw-r--r-- | kernel/timer.c | 31 |
6 files changed, 1378 insertions, 28 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index 142a78613066..2929aae0c2fe 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -6,7 +6,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.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 pid.o \ - rcupdate.o intermodule.o extable.o params.o + rcupdate.o intermodule.o extable.o params.o posix-timers.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o diff --git a/kernel/exit.c b/kernel/exit.c index d2d7c72f1e81..6b2f1113b926 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -460,6 +460,7 @@ void end_lazy_tlb(struct mm_struct *mm) mmdrop(active_mm); } + /* * Turn us into a lazy TLB process if we * aren't already.. @@ -741,6 +742,7 @@ NORET_TYPE void do_exit(long code) __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); + exit_itimers(tsk); exit_thread(); if (tsk->leader) diff --git a/kernel/fork.c b/kernel/fork.c index 5ecc19a9aab4..6f137beea865 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -813,6 +813,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); + INIT_LIST_HEAD(&p->posix_timers); init_waitqueue_head(&p->wait_chldexit); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c new file mode 100644 index 000000000000..6552ffa2db39 --- /dev/null +++ b/kernel/posix-timers.c @@ -0,0 +1,1318 @@ +/* + * linux/kernel/posix_timers.c + * + * + * 2002-10-15 Posix Clocks & timers by George Anzinger + * Copyright (C) 2002 by MontaVista Software. + */ + +/* These are all the functions necessary to implement + * POSIX clocks & timers + */ + +#include <linux/mm.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/time.h> + +#include <asm/uaccess.h> +#include <asm/semaphore.h> +#include <linux/list.h> +#include <linux/init.h> +#include <linux/compiler.h> +#include <linux/idr.h> +#include <linux/posix-timers.h> + +#ifndef div_long_long_rem +#include <asm/div64.h> + +#define div_long_long_rem(dividend,divisor,remainder) ({ \ + u64 result = dividend; \ + *remainder = do_div(result,divisor); \ + result; }) + +#endif /* ifndef div_long_long_rem */ + +/* + * Management arrays for POSIX timers. Timers are kept in slab memory + * Timer ids are allocated by an external routine that keeps track of the + * id and the timer. The external interface is: + * + *void *idr_find(struct idr *idp, int id); to find timer_id <id> + *int idr_get_new(struct idr *idp, void *ptr); to get a new id and + * related it to <ptr> + *void idr_remove(struct idr *idp, int id); to release <id> + *void idr_init(struct idr *idp); to initialize <idp> + * which we supply. + * The idr_get_new *may* call slab for more memory so it must not be + * called under a spin lock. Likewise idr_remore may release memory + * (but it may be ok to do this under a lock...). + * idr_find is just a memory look up and is quite fast. A zero return + * indicates that the requested id does not exist. + + */ +/* + * Lets keep our timers in a slab cache :-) + */ +static kmem_cache_t *posix_timers_cache; +struct idr posix_timers_id; +spinlock_t idr_lock = SPIN_LOCK_UNLOCKED; + +/* + * 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 +/* + * The timer ID is turned into a timer address by idr_find(). + * Verifying a valid ID consists of: + * + * a) checking that idr_find() returns other than zero. + * b) checking that the timer id matches the one in the timer itself. + * c) that the timer owner is in the callers thread group. + */ + + +/* + * 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. + * + * At this time all functions EXCEPT clock_nanosleep can be + * redirected by the CLOCKS structure. Clock_nanosleep is in + * there, but the code ignors it. + * + * 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); +static struct k_itimer *lock_timer(timer_t timer_id, long *flags); +static inline void unlock_timer(struct k_itimer *timr, long flags); + +/* + * Initialize everything, well, just everything in Posix clocks/timers ;) + */ + +static __init int +init_posix_timers(void) +{ + 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 + }; + + register_posix_clock(CLOCK_REALTIME, &clock_realtime); + register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic); + + posix_timers_cache = kmem_cache_create("posix_timers_cache", + sizeof (struct k_itimer), 0, 0, + 0, 0); + idr_init(&posix_timers_id); + 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; + + if (nsec > NSEC_PER_SEC) { + sec++; + nsec -= NSEC_PER_SEC; + } + + /* + * 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 0; +} +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); +} + +static void +schedule_next_timer(struct k_itimer *timr) +{ + struct now_struct now; + + /* Set up the timer for the next interval (if there is one) */ + if (timr->it_incr == 0) { + { + set_timer_inactive(timr); + return; + } + } + posix_get_now(&now); + while (posix_time_before(&timr->it_timer, &now)) { + posix_bump_timer(timr); + }; + timr->it_overrun_last = timr->it_overrun; + timr->it_overrun = -1; + timr->it_requeue_pending = 0; + add_timer(&timr->it_timer); +} + +/* + + * This function is exported for use by the signal deliver code. It is + * called just prior to the info block being released and passes that + * block to us. It's function is to update the overrun entry AND to + * restart the timer. It should only be called if the timer is to be + * restarted (i.e. we have flagged this in the sys_private entry of the + * info block). + * + * To protect aginst the timer going away while the interrupt is queued, + * we require that the it_requeue_pending flag be set. + + */ +void +do_schedule_next_timer(struct siginfo *info) +{ + + struct k_itimer *timr; + long flags; + + timr = lock_timer(info->si_tid, &flags); + + if (!timr || !timr->it_requeue_pending) + goto exit; + + schedule_next_timer(timr); + info->si_overrun = timr->it_overrun_last; + exit: + if (timr) + unlock_timer(timr, flags); +} + +/* + + * 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. This code will requeue the timer only if we get + * either an error return or a flag (ret > 0) from send_seg_info + * indicating that the signal was either not queued or was queued + * without an info block. In this case, we will not get a call back to + * do_schedule_next_timer() so we do it here. This should be rare... + + */ + +static void +timer_notify_task(struct k_itimer *timr) +{ + struct siginfo info; + int ret; + + 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; + if (timr->it_incr == 0) { + set_timer_inactive(timr); + } else { + timr->it_requeue_pending = info.si_sys_private = 1; + } + ret = send_sig_info(info.si_signo, &info, timr->it_process); + switch (ret) { + + default: + /* + * Signal was not sent. May or may not need to + * restart the timer. + */ + printk(KERN_WARNING "sending signal failed: %d\n", ret); + case 1: + /* + * signal was not sent because of sig_ignor or, + * possibly no queue memory OR will be sent but, + * we will not get a call back to restart it AND + * it should be restarted. + */ + schedule_next_timer(timr); + case 0: + /* + * all's well new signal queued + */ + break; + } +} + +/* + + * 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; + long flags; + + spin_lock_irqsave(&timr->it_lock, flags); + timer_notify_task(timr); + unlock_timer(timr, flags); +} + +/* + * 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; + 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 != -1){ + spin_lock_irq(&idr_lock); + idr_remove(&posix_timers_id, tmr->it_id); + spin_unlock_irq(&idr_lock); + } + 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; + timer_t new_timer_id; + struct task_struct *process = 0; + sigevent_t event; + + if ((unsigned) which_clock >= MAX_CLOCKS || + !posix_clocks[which_clock].res) return -EINVAL; + + new_timer = alloc_posix_timer(); + if (unlikely (new_timer == NULL)) + return -EAGAIN; + + spin_lock_init(&new_timer->it_lock); + do { + if ( unlikely ( !idr_pre_get(&posix_timers_id))){ + error = -EAGAIN; + new_timer_id = (timer_t)-1; + goto out; + } + spin_lock_irq(&idr_lock); + new_timer_id = (timer_t) idr_get_new( + &posix_timers_id, (void *) new_timer); + spin_unlock_irq(&idr_lock); + }while( unlikely (new_timer_id == -1)); + + new_timer->it_id = new_timer_id; + /* + * return the timer_id now. The next step is hard to + * back out if there is an error. + */ + if (copy_to_user(created_timer_id, + &new_timer_id, sizeof (new_timer_id))) { + error = -EFAULT; + goto out; + } + 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 process for another + * thread. It may be exitiing. To catch this + * case the we check the PF_EXITING flag. If + * the flag is not set, the task_lock will catch + * him before it is too late (in exit_itimers). + + * The exec case is a bit more invloved but easy + * to code. If the process is in our thread + * group (and it must be or we would not allow + * it here) and is doing an exec, it will cause + * us to be killed. In this case it will wait + * for us to die which means we can finish this + * linkage with our last gasp. I.e. no code :) + + */ + task_lock(process); + if (!(process->flags & PF_EXITING)) { + list_add(&new_timer->list, + &process->posix_timers); + task_unlock(process); + } else { + task_unlock(process); + 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; + task_lock(process); + list_add(&new_timer->list, &process->posix_timers); + task_unlock(process); + } + + new_timer->it_clock = which_clock; + new_timer->it_incr = 0; + new_timer->it_overrun = -1; + 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); + + /* + * 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, long flags) +{ + spin_unlock_irqrestore(&timr->it_lock, flags); +} + +/* + + * Locking issues: We need to protect the result of the id look up until + * we get the timer locked down so it is not deleted under us. The + * removal is done under the idr spinlock so we use that here to bridge + * the find to the timer lock. To avoid a dead lock, the timer id MUST + * be release with out holding the timer lock. + + */ +static struct k_itimer * +lock_timer(timer_t timer_id, long *flags) +{ + struct k_itimer *timr; + /* + * Watch out here. We do a irqsave on the idr_lock and pass the + * flags part over to the timer lock. Must not let interrupts in + * while we are moving the lock. + */ + + spin_lock_irqsave(&idr_lock, *flags); + timr = (struct k_itimer *) idr_find(&posix_timers_id, (int) timer_id); + if (timr) { + spin_lock(&timr->it_lock); + spin_unlock(&idr_lock); + + if ( (timr->it_id != timer_id) || !(timr->it_process) || + timr->it_process->tgid != current->tgid) { + unlock_timer(timr, *flags); + timr = NULL; + } + } else { + spin_unlock_irqrestore(&idr_lock, *flags); + } + + 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. + + * We have a couple of messes to clean up here. First there is the case + * of a timer that has a requeue pending. These timers should appear to + * be in the timer list with an expiry as if we were to requeue them + * now. + + * The second issue is the SIGEV_NONE timer which may be active but is + * not really ever put in the timer list (to save system resources). + * This timer may be expired, and if so, we will do it here. Otherwise + * it is the same as a requeue pending timer WRT to what we should + * report. + + */ +void inline +do_timer_gettime(struct k_itimer *timr, struct itimerspec *cur_setting) +{ + long sub_expires; + unsigned long expires; + struct now_struct now; + + do { + expires = timr->it_timer.expires; + } while ((volatile long) (timr->it_timer.expires) != expires); + + posix_get_now(&now); + + if (expires && (timr->it_sigev_notify & SIGEV_NONE) && !timr->it_incr) { + if (posix_time_before(&timr->it_timer, &now)) { + timr->it_timer.expires = expires = 0; + } + } + if (expires) { + if (timr->it_requeue_pending || + (timr->it_sigev_notify & SIGEV_NONE)) { + while (posix_time_before(&timr->it_timer, &now)) { + posix_bump_timer(timr); + }; + } else { + if (!timer_pending(&timr->it_timer)) { + sub_expires = expires = 0; + } + } + if (expires) { + expires -= now.jiffies; + } + } + jiffies_to_timespec(expires, &cur_setting->it_value); + jiffies_to_timespec(timr->it_incr, &cur_setting->it_interval); + + 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; + long flags; + + timr = lock_timer(timer_id, &flags); + if (!timr) + return -EINVAL; + + p_timer_get(&posix_clocks[timr->it_clock], timr, &cur_setting); + + unlock_timer(timr, flags); + + 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 to + * be the overrun of the timer last delivered. At the same time we are + * accumulating overruns on the next timer. The overrun is frozen when + * the signal is delivered, either at the notify time (if the info block + * is not queued) or at the actual delivery time (as we are informed by + * the call back to do_schedule_next_timer(). So all we need to do is + * to pick up the frozen overrun. + + */ + +asmlinkage int +sys_timer_getoverrun(timer_t timer_id) +{ + struct k_itimer *timr; + int overrun; + long flags; + + timr = lock_timer(timer_id, &flags); + if (!timr) + return -EINVAL; + + overrun = timr->it_overrun_last; + unlock_timer(timr, flags); + + 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 is ALMOST always 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; + /* + * 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 + timr->it_requeue_pending = 0; + timr->it_overrun_last = 0; + timr->it_overrun = -1; + /* + *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; + return 0; + } + + if ((flags & TIMER_ABSTIME) && + (clock->clock_get != do_posix_clock_monotonic_gettime)) { + } + 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 notify function is called directly. + * We do not even queue SIGEV_NONE timers! + */ + if (!(timr->it_sigev_notify & SIGEV_NONE)) { + if (timr->it_timer.expires == jiffies) { + timer_notify_task(timr); + } else + 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; + long flag; + 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, &flag); + 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, flag); + 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; +#ifdef CONFIG_SMP + if (timer_active(timer) && + !del_timer(&timer->it_timer) && !timer->it_requeue_pending) { + /* + * 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; + long flags; + +#ifdef CONFIG_SMP + int error; + retry_delete: +#endif + + timer = lock_timer(timer_id, &flags); + if (!timer) + return -EINVAL; + +#ifdef CONFIG_SMP + error = p_timer_del(&posix_clocks[timer->it_clock], timer); + + if (error == TIMER_RETRY) { + unlock_timer(timer, flags); + goto retry_delete; + } +#else + p_timer_del(&posix_clocks[timer->it_clock], timer); +#endif + + task_lock(timer->it_process); + + list_del(&timer->list); + + task_unlock(timer->it_process); + + /* + * 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, flags); + release_posix_timer(timer); + return 0; +} +/* + * return timer owned by the process, used by exit_itimers + */ +static inline void +itimer_delete(struct k_itimer *timer) +{ + if (sys_timer_delete(timer->it_id)) { + BUG(); + } +} +/* + * This is exported to exit and exec + */ +void +exit_itimers(struct task_struct *tsk) +{ + struct k_itimer *tmr; + + task_lock(tsk); + while (!list_empty(&tsk->posix_timers)) { + tmr = list_entry(tsk->posix_timers.next, struct k_itimer, list); + task_unlock(tsk); + itimer_delete(tmr); + task_lock(tsk); + } + task_unlock(tsk); +} + +/* + * 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). + * The seqlock is great here. Since we a reader, we don't really care + * if we are interrupted since we don't take lock that will stall us or + * any other cpu. Voila, no irq lock is needed. + + * 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; + +#else + unsigned int seq; + + do { + seq = read_seqbegin(&xtime_lock); + jiffies_64_f = jiffies_64; + + }while( read_seqretry(&xtime_lock, seq)); + +#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].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); +} + +long clock_nanosleep_restart(struct restart_block *restart_block); + +extern long do_clock_nanosleep(clockid_t which_clock, int flags, + struct timespec *t); + +#ifdef FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP + +asmlinkage long +sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) +{ + struct timespec t; + long ret; + + if (copy_from_user(&t, rqtp, sizeof (t))) + return -EFAULT; + + if ((unsigned) t.tv_nsec >= NSEC_PER_SEC || t.tv_sec < 0) + return -EINVAL; + + ret = do_clock_nanosleep(CLOCK_REALTIME, 0, &t); + + if (ret == -ERESTART_RESTARTBLOCK && rmtp && + copy_to_user(rmtp, &t, sizeof (t))) + return -EFAULT; + return ret; +} +#endif // ! FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP + +asmlinkage long +sys_clock_nanosleep(clockid_t which_clock, int flags, + const struct timespec *rqtp, struct timespec *rmtp) +{ + struct timespec t; + int ret; + + if ((unsigned) which_clock >= MAX_CLOCKS || + !posix_clocks[which_clock].res) return -EINVAL; + + if (copy_from_user(&t, rqtp, sizeof (struct timespec))) + return -EFAULT; + + if ((unsigned) t.tv_nsec >= NSEC_PER_SEC || t.tv_sec < 0) + return -EINVAL; + + ret = do_clock_nanosleep(which_clock, flags, &t); + + if ((ret == -ERESTART_RESTARTBLOCK) && rmtp && + copy_to_user(rmtp, &t, sizeof (t))) + return -EFAULT; + return ret; + +} + +long +do_clock_nanosleep(clockid_t which_clock, int flags, struct timespec *tsave) +{ + struct timespec t; + struct timer_list new_timer; + struct abs_struct abs_struct = { list:{next:0} }; + int abs; + int rtn = 0; + int active; + struct restart_block *restart_block = + ¤t_thread_info()->restart_block; + + 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 (restart_block->fn == clock_nanosleep_restart) { + /* + * Interrupted by a non-delivered signal, pick up remaining + * time and continue. + */ + restart_block->fn = do_no_restart_syscall; + if (!restart_block->arg2) + return -EINTR; + + new_timer.expires = restart_block->arg2; + if (time_before(new_timer.expires, jiffies)) + return 0; + } + + 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. + */ + + 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)) && + !test_thread_flag(TIF_SIGPENDING)); + + 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) { + unsigned long jiffies_f = jiffies; + + /* + * Always restart abs calls from scratch to pick up any + * clock shifting that happened while we are away. + */ + if (abs) + return -ERESTARTNOHAND; + + jiffies_to_timespec(new_timer.expires - jiffies_f, tsave); + + while (tsave->tv_nsec < 0) { + tsave->tv_nsec += NSEC_PER_SEC; + tsave->tv_sec--; + } + if (tsave->tv_sec < 0) { + tsave->tv_sec = 0; + tsave->tv_nsec = 1; + } + restart_block->fn = clock_nanosleep_restart; + restart_block->arg0 = which_clock; + restart_block->arg1 = (int)tsave; + restart_block->arg2 = new_timer.expires; + return -ERESTART_RESTARTBLOCK; + } + + return rtn; +} +/* + * This will restart either clock_nanosleep or clock_nanosleep + */ +long +clock_nanosleep_restart(struct restart_block *restart_block) +{ + struct timespec t; + int ret = do_clock_nanosleep(restart_block->arg0, 0, &t); + + if ((ret == -ERESTART_RESTARTBLOCK) && restart_block->arg1 && + copy_to_user((struct timespec *)(restart_block->arg1), &t, + sizeof (t))) + return -EFAULT; + return ret; +} diff --git a/kernel/signal.c b/kernel/signal.c index b7ac6a557ddb..f232baae6fd8 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -472,8 +472,6 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, 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(); @@ -492,6 +490,11 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) if (!signr) signr = __dequeue_signal(&tsk->signal->shared_pending, mask, info); + if ( signr && + ((info->si_code & __SI_MASK) == __SI_TIMER) && + info->si_sys_private){ + do_schedule_next_timer(info); + } return signr; } @@ -677,6 +680,7 @@ static void handle_stop_signal(int sig, struct task_struct *p) static int send_signal(int sig, struct siginfo *info, struct sigpending *signals) { struct sigqueue * q = NULL; + int ret = 0; /* * fast-pathed signals for kernel-internal things like SIGSTOP @@ -720,17 +724,25 @@ static int send_signal(int sig, struct siginfo *info, struct sigpending *signals copy_siginfo(&q->info, info); break; } - } else if (sig >= SIGRTMIN && info && (unsigned long)info != 1 + } else { + if (sig >= SIGRTMIN && info && (unsigned long)info != 1 && info->si_code != SI_USER) /* * Queue overflow, abort. We may abort if the signal was rt * and sent by user using something other than kill(). */ - return -EAGAIN; + return -EAGAIN; + if (((unsigned long)info > 1) && (info->si_code == SI_TIMER)) + /* + * Set up a return to indicate that we dropped + * the signal. + */ + ret = info->si_sys_private; + } out_set: sigaddset(&signals->signal, sig); - return 0; + return ret; } #define LEGACY_QUEUE(sigptr, sig) \ @@ -749,20 +761,26 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t) BUG(); #endif + if (((unsigned long)info > 2) && (info->si_code == SI_TIMER)) + /* + * Set up a return to indicate that we dropped the signal. + */ + ret = info->si_sys_private; + /* Short-circuit ignored signals. */ if (sig_ignored(t, sig)) - return 0; + goto out; /* 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)) - return 0; + goto out; ret = send_signal(sig, info, &t->pending); if (!ret && !sigismember(&t->blocked, sig)) signal_wake_up(t, sig == SIGKILL); - +out: return ret; } @@ -821,7 +839,7 @@ __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) { struct task_struct *t; unsigned int mask; - int ret; + int ret = 0; #if CONFIG_SMP if (!spin_is_locked(&p->sighand->siglock)) @@ -829,13 +847,19 @@ __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) #endif handle_stop_signal(sig, p); + if (((unsigned long)info > 2) && (info->si_code == SI_TIMER)) + /* + * Set up a return to indicate that we dropped the signal. + */ + ret = info->si_sys_private; + /* Short-circuit ignored signals. */ if (sig_ignored(p, sig)) - return 0; + return ret; if (LEGACY_QUEUE(&p->signal->shared_pending, sig)) /* This is a non-RT signal and we already have one queued. */ - return 0; + return ret; /* * Don't bother zombies and stopped tasks (but @@ -1322,6 +1346,7 @@ do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent) static void finish_stop(int stop_count) { + int ret; /* * If there are no other threads in the group, or if there is * a group stop in progress and we are the last to stop, @@ -1753,8 +1778,9 @@ int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) 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 --git a/kernel/timer.c b/kernel/timer.c index 2c297124b6d9..b94c6fd8485c 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -52,12 +52,11 @@ typedef struct tvec_root_s { 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; @@ -70,7 +69,7 @@ typedef struct tvec_t_base_s tvec_base_t; /* Fake initialization */ static DEFINE_PER_CPU(tvec_base_t, tvec_bases) = { SPIN_LOCK_UNLOCKED }; -static void check_timer_failed(timer_t *timer) +static void check_timer_failed(struct timer_list *timer) { static int whine_count; if (whine_count < 16) { @@ -88,13 +87,13 @@ static void check_timer_failed(timer_t *timer) timer->magic = TIMER_MAGIC; } -static inline void check_timer(timer_t *timer) +static inline void check_timer(struct timer_list *timer) { if (timer->magic != TIMER_MAGIC) check_timer_failed(timer); } -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; @@ -146,7 +145,7 @@ static inline void internal_add_timer(tvec_base_t *base, timer_t *timer) * 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 = &per_cpu(tvec_bases, cpu); @@ -204,7 +203,7 @@ void add_timer_on(struct timer_list *timer, int cpu) * (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; @@ -281,7 +280,7 @@ repeat: * (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; @@ -320,7 +319,7 @@ repeat: * * 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; int i, ret = 0; @@ -363,9 +362,9 @@ static int cascade(tvec_base_t *base, tvec_t *tv) * 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; @@ -404,9 +403,9 @@ repeat: 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; @@ -508,6 +507,7 @@ static void second_overflow(void) 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; @@ -516,6 +516,7 @@ static void second_overflow(void) 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; @@ -968,7 +969,7 @@ static void process_timeout(unsigned long __data) */ signed long schedule_timeout(signed long timeout) { - timer_t timer; + struct timer_list timer; unsigned long expire; switch (timeout) @@ -1023,6 +1024,7 @@ asmlinkage long sys_gettid(void) { return current->pid; } +#ifndef FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP static long nanosleep_restart(struct restart_block *restart) { @@ -1081,6 +1083,7 @@ asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) } return ret; } +#endif // ! FOLD_NANO_SLEEP_INTO_CLOCK_NANO_SLEEP /* * sys_sysinfo - fill in sysinfo struct |
