Merge branch 'block' of git://brick.kernel.dk/data/git/linux-2.6-block
[pandora-kernel.git] / kernel / posix-cpu-timers.c
index cae4f57..479b16b 100644 (file)
@@ -7,7 +7,7 @@
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 
-static int check_clock(clockid_t which_clock)
+static int check_clock(const clockid_t which_clock)
 {
        int error = 0;
        struct task_struct *p;
@@ -31,7 +31,7 @@ static int check_clock(clockid_t which_clock)
 }
 
 static inline union cpu_time_count
-timespec_to_sample(clockid_t which_clock, const struct timespec *tp)
+timespec_to_sample(const clockid_t which_clock, const struct timespec *tp)
 {
        union cpu_time_count ret;
        ret.sched = 0;          /* high half always zero when .cpu used */
@@ -43,7 +43,7 @@ timespec_to_sample(clockid_t which_clock, const struct timespec *tp)
        return ret;
 }
 
-static void sample_to_timespec(clockid_t which_clock,
+static void sample_to_timespec(const clockid_t which_clock,
                               union cpu_time_count cpu,
                               struct timespec *tp)
 {
@@ -55,7 +55,7 @@ static void sample_to_timespec(clockid_t which_clock,
        }
 }
 
-static inline int cpu_time_before(clockid_t which_clock,
+static inline int cpu_time_before(const clockid_t which_clock,
                                  union cpu_time_count now,
                                  union cpu_time_count then)
 {
@@ -65,7 +65,7 @@ static inline int cpu_time_before(clockid_t which_clock,
                return cputime_lt(now.cpu, then.cpu);
        }
 }
-static inline void cpu_time_add(clockid_t which_clock,
+static inline void cpu_time_add(const clockid_t which_clock,
                                union cpu_time_count *acc,
                                union cpu_time_count val)
 {
@@ -75,7 +75,7 @@ static inline void cpu_time_add(clockid_t which_clock,
                acc->cpu = cputime_add(acc->cpu, val.cpu);
        }
 }
-static inline union cpu_time_count cpu_time_sub(clockid_t which_clock,
+static inline union cpu_time_count cpu_time_sub(const clockid_t which_clock,
                                                union cpu_time_count a,
                                                union cpu_time_count b)
 {
@@ -151,7 +151,7 @@ static inline unsigned long long sched_ns(struct task_struct *p)
        return (p == current) ? current_sched_time(p) : p->sched_time;
 }
 
-int posix_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
+int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp)
 {
        int error = check_clock(which_clock);
        if (!error) {
@@ -169,7 +169,7 @@ int posix_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
        return error;
 }
 
-int posix_cpu_clock_set(clockid_t which_clock, const struct timespec *tp)
+int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *tp)
 {
        /*
         * You can never reset a CPU clock, but we check for other errors
@@ -186,7 +186,7 @@ int posix_cpu_clock_set(clockid_t which_clock, const struct timespec *tp)
 /*
  * Sample a per-thread clock for the given task.
  */
-static int cpu_clock_sample(clockid_t which_clock, struct task_struct *p,
+static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,
                            union cpu_time_count *cpu)
 {
        switch (CPUCLOCK_WHICH(which_clock)) {
@@ -238,18 +238,7 @@ static int cpu_clock_sample_group_locked(unsigned int clock_idx,
                while ((t = next_thread(t)) != p) {
                        cpu->sched += t->sched_time;
                }
-               if (p->tgid == current->tgid) {
-                       /*
-                        * We're sampling ourselves, so include the
-                        * cycles not yet banked.  We still omit
-                        * other threads running on other CPUs,
-                        * so the total can always be behind as
-                        * much as max(nthreads-1,ncpus) * (NSEC_PER_SEC/HZ).
-                        */
-                       cpu->sched += current_sched_time(current);
-               } else {
-                       cpu->sched += p->sched_time;
-               }
+               cpu->sched += sched_ns(p);
                break;
        }
        return 0;
@@ -259,7 +248,7 @@ static int cpu_clock_sample_group_locked(unsigned int clock_idx,
  * Sample a process (thread group) clock for the given group_leader task.
  * Must be called with tasklist_lock held for reading.
  */
-static int cpu_clock_sample_group(clockid_t which_clock,
+static int cpu_clock_sample_group(const clockid_t which_clock,
                                  struct task_struct *p,
                                  union cpu_time_count *cpu)
 {
@@ -273,7 +262,7 @@ static int cpu_clock_sample_group(clockid_t which_clock,
 }
 
 
-int posix_cpu_clock_get(clockid_t which_clock, struct timespec *tp)
+int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
 {
        const pid_t pid = CPUCLOCK_PID(which_clock);
        int error = -EINVAL;
@@ -566,9 +555,6 @@ static void arm_timer(struct k_itimer *timer, union cpu_time_count now)
        struct cpu_timer_list *next;
        unsigned long i;
 
-       if (CPUCLOCK_PERTHREAD(timer->it_clock) && (p->flags & PF_EXITING))
-               return;
-
        head = (CPUCLOCK_PERTHREAD(timer->it_clock) ?
                p->cpu_timers : p->signal->cpu_timers);
        head += CPUCLOCK_WHICH(timer->it_clock);
@@ -1184,6 +1170,9 @@ static void check_process_timers(struct task_struct *tsk,
                }
                t = tsk;
                do {
+                       if (unlikely(t->flags & PF_EXITING))
+                               continue;
+
                        ticks = cputime_add(cputime_add(t->utime, t->stime),
                                            prof_left);
                        if (!cputime_eq(prof_expires, cputime_zero) &&
@@ -1204,11 +1193,7 @@ static void check_process_timers(struct task_struct *tsk,
                                              t->it_sched_expires > sched)) {
                                t->it_sched_expires = sched;
                        }
-
-                       do {
-                               t = next_thread(t);
-                       } while (unlikely(t->flags & PF_EXITING));
-               } while (t != tsk);
+               } while ((t = next_thread(t)) != tsk);
        }
 }
 
@@ -1300,30 +1285,30 @@ void run_posix_cpu_timers(struct task_struct *tsk)
 
 #undef UNEXPIRED
 
-       BUG_ON(tsk->exit_state);
-
        /*
         * Double-check with locks held.
         */
        read_lock(&tasklist_lock);
-       spin_lock(&tsk->sighand->siglock);
+       if (likely(tsk->signal != NULL)) {
+               spin_lock(&tsk->sighand->siglock);
 
-       /*
-        * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N]
-        * all the timers that are firing, and put them on the firing list.
-        */
-       check_thread_timers(tsk, &firing);
-       check_process_timers(tsk, &firing);
+               /*
+                * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N]
+                * all the timers that are firing, and put them on the firing list.
+                */
+               check_thread_timers(tsk, &firing);
+               check_process_timers(tsk, &firing);
 
-       /*
-        * We must release these locks before taking any timer's lock.
-        * There is a potential race with timer deletion here, as the
-        * siglock now protects our private firing list.  We have set
-        * the firing flag in each timer, so that a deletion attempt
-        * that gets the timer lock before we do will give it up and
-        * spin until we've taken care of that timer below.
-        */
-       spin_unlock(&tsk->sighand->siglock);
+               /*
+                * We must release these locks before taking any timer's lock.
+                * There is a potential race with timer deletion here, as the
+                * siglock now protects our private firing list.  We have set
+                * the firing flag in each timer, so that a deletion attempt
+                * that gets the timer lock before we do will give it up and
+                * spin until we've taken care of that timer below.
+                */
+               spin_unlock(&tsk->sighand->siglock);
+       }
        read_unlock(&tasklist_lock);
 
        /*
@@ -1408,24 +1393,12 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
        }
 }
 
-static long posix_cpu_clock_nanosleep_restart(struct restart_block *);
-
-int posix_cpu_nsleep(clockid_t which_clock, int flags,
-                    struct timespec *rqtp)
+static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
+                           struct timespec *rqtp, struct itimerspec *it)
 {
-       struct restart_block *restart_block =
-           &current_thread_info()->restart_block;
        struct k_itimer timer;
        int error;
 
-       /*
-        * Diagnose required errors first.
-        */
-       if (CPUCLOCK_PERTHREAD(which_clock) &&
-           (CPUCLOCK_PID(which_clock) == 0 ||
-            CPUCLOCK_PID(which_clock) == current->pid))
-               return -EINVAL;
-
        /*
         * Set up a temporary timer and then wait for it to go off.
         */
@@ -1436,13 +1409,13 @@ int posix_cpu_nsleep(clockid_t which_clock, int flags,
        error = posix_cpu_timer_create(&timer);
        timer.it_process = current;
        if (!error) {
-               struct timespec __user *rmtp;
                static struct itimerspec zero_it;
-               struct itimerspec it = { .it_value = *rqtp,
-                                        .it_interval = {} };
+
+               memset(it, 0, sizeof *it);
+               it->it_value = *rqtp;
 
                spin_lock_irq(&timer.it_lock);
-               error = posix_cpu_timer_set(&timer, flags, &it, NULL);
+               error = posix_cpu_timer_set(&timer, flags, it, NULL);
                if (error) {
                        spin_unlock_irq(&timer.it_lock);
                        return error;
@@ -1470,55 +1443,102 @@ int posix_cpu_nsleep(clockid_t which_clock, int flags,
                 * We were interrupted by a signal.
                 */
                sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
-               posix_cpu_timer_set(&timer, 0, &zero_it, &it);
+               posix_cpu_timer_set(&timer, 0, &zero_it, it);
                spin_unlock_irq(&timer.it_lock);
 
-               if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
+               if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) {
                        /*
                         * It actually did fire already.
                         */
                        return 0;
                }
 
+               error = -ERESTART_RESTARTBLOCK;
+       }
+
+       return error;
+}
+
+int posix_cpu_nsleep(const clockid_t which_clock, int flags,
+                    struct timespec *rqtp, struct timespec __user *rmtp)
+{
+       struct restart_block *restart_block =
+           &current_thread_info()->restart_block;
+       struct itimerspec it;
+       int error;
+
+       /*
+        * Diagnose required errors first.
+        */
+       if (CPUCLOCK_PERTHREAD(which_clock) &&
+           (CPUCLOCK_PID(which_clock) == 0 ||
+            CPUCLOCK_PID(which_clock) == current->pid))
+               return -EINVAL;
+
+       error = do_cpu_nanosleep(which_clock, flags, rqtp, &it);
+
+       if (error == -ERESTART_RESTARTBLOCK) {
+
+               if (flags & TIMER_ABSTIME)
+                       return -ERESTARTNOHAND;
                /*
-                * Report back to the user the time still remaining.
-                */
-               rmtp = (struct timespec __user *) restart_block->arg1;
-               if (rmtp != NULL && !(flags & TIMER_ABSTIME) &&
-                   copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+                * Report back to the user the time still remaining.
+                */
+               if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
                        return -EFAULT;
 
-               restart_block->fn = posix_cpu_clock_nanosleep_restart;
-               /* Caller already set restart_block->arg1 */
+               restart_block->fn = posix_cpu_nsleep_restart;
                restart_block->arg0 = which_clock;
+               restart_block->arg1 = (unsigned long) rmtp;
                restart_block->arg2 = rqtp->tv_sec;
                restart_block->arg3 = rqtp->tv_nsec;
-
-               error = -ERESTART_RESTARTBLOCK;
        }
-
        return error;
 }
 
-static long
-posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
+long posix_cpu_nsleep_restart(struct restart_block *restart_block)
 {
        clockid_t which_clock = restart_block->arg0;
-       struct timespec t = { .tv_sec = restart_block->arg2,
-                             .tv_nsec = restart_block->arg3 };
+       struct timespec __user *rmtp;
+       struct timespec t;
+       struct itimerspec it;
+       int error;
+
+       rmtp = (struct timespec __user *) restart_block->arg1;
+       t.tv_sec = restart_block->arg2;
+       t.tv_nsec = restart_block->arg3;
+
        restart_block->fn = do_no_restart_syscall;
-       return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t);
+       error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it);
+
+       if (error == -ERESTART_RESTARTBLOCK) {
+               /*
+                * Report back to the user the time still remaining.
+                */
+               if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+                       return -EFAULT;
+
+               restart_block->fn = posix_cpu_nsleep_restart;
+               restart_block->arg0 = which_clock;
+               restart_block->arg1 = (unsigned long) rmtp;
+               restart_block->arg2 = t.tv_sec;
+               restart_block->arg3 = t.tv_nsec;
+       }
+       return error;
+
 }
 
 
 #define PROCESS_CLOCK  MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED)
 #define THREAD_CLOCK   MAKE_THREAD_CPUCLOCK(0, CPUCLOCK_SCHED)
 
-static int process_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
+static int process_cpu_clock_getres(const clockid_t which_clock,
+                                   struct timespec *tp)
 {
        return posix_cpu_clock_getres(PROCESS_CLOCK, tp);
 }
-static int process_cpu_clock_get(clockid_t which_clock, struct timespec *tp)
+static int process_cpu_clock_get(const clockid_t which_clock,
+                                struct timespec *tp)
 {
        return posix_cpu_clock_get(PROCESS_CLOCK, tp);
 }
@@ -1527,16 +1547,23 @@ static int process_cpu_timer_create(struct k_itimer *timer)
        timer->it_clock = PROCESS_CLOCK;
        return posix_cpu_timer_create(timer);
 }
-static int process_cpu_nsleep(clockid_t which_clock, int flags,
-                             struct timespec *rqtp)
+static int process_cpu_nsleep(const clockid_t which_clock, int flags,
+                             struct timespec *rqtp,
+                             struct timespec __user *rmtp)
 {
-       return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp);
+       return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp);
 }
-static int thread_cpu_clock_getres(clockid_t which_clock, struct timespec *tp)
+static long process_cpu_nsleep_restart(struct restart_block *restart_block)
+{
+       return -EINVAL;
+}
+static int thread_cpu_clock_getres(const clockid_t which_clock,
+                                  struct timespec *tp)
 {
        return posix_cpu_clock_getres(THREAD_CLOCK, tp);
 }
-static int thread_cpu_clock_get(clockid_t which_clock, struct timespec *tp)
+static int thread_cpu_clock_get(const clockid_t which_clock,
+                               struct timespec *tp)
 {
        return posix_cpu_clock_get(THREAD_CLOCK, tp);
 }
@@ -1545,8 +1572,12 @@ static int thread_cpu_timer_create(struct k_itimer *timer)
        timer->it_clock = THREAD_CLOCK;
        return posix_cpu_timer_create(timer);
 }
-static int thread_cpu_nsleep(clockid_t which_clock, int flags,
-                             struct timespec *rqtp)
+static int thread_cpu_nsleep(const clockid_t which_clock, int flags,
+                             struct timespec *rqtp, struct timespec __user *rmtp)
+{
+       return -EINVAL;
+}
+static long thread_cpu_nsleep_restart(struct restart_block *restart_block)
 {
        return -EINVAL;
 }
@@ -1559,6 +1590,7 @@ static __init int init_posix_cpu_timers(void)
                .clock_set = do_posix_clock_nosettime,
                .timer_create = process_cpu_timer_create,
                .nsleep = process_cpu_nsleep,
+               .nsleep_restart = process_cpu_nsleep_restart,
        };
        struct k_clock thread = {
                .clock_getres = thread_cpu_clock_getres,
@@ -1566,6 +1598,7 @@ static __init int init_posix_cpu_timers(void)
                .clock_set = do_posix_clock_nosettime,
                .timer_create = thread_cpu_timer_create,
                .nsleep = thread_cpu_nsleep,
+               .nsleep_restart = thread_cpu_nsleep_restart,
        };
 
        register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);