]> Pileus Git - ~andy/linux/blobdiff - kernel/posix-cpu-timers.c
jbd2: Fix oops in jbd2_journal_file_inode()
[~andy/linux] / kernel / posix-cpu-timers.c
index c3c4ea1225a4964688687e49b4f3fd4df086c902..c7f31aa272f74276d9d4c37d669303ba43ec1dce 100644 (file)
@@ -399,6 +399,15 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
        return ret;
 }
 
+static void cleanup_timers_list(struct list_head *head,
+                               unsigned long long curr)
+{
+       struct cpu_timer_list *timer, *next;
+
+       list_for_each_entry_safe(timer, next, head, entry)
+               list_del_init(&timer->entry);
+}
+
 /*
  * Clean out CPU timers still ticking when a thread exited.  The task
  * pointer is cleared, and the expiry time is replaced with the residual
@@ -409,37 +418,12 @@ static void cleanup_timers(struct list_head *head,
                           cputime_t utime, cputime_t stime,
                           unsigned long long sum_exec_runtime)
 {
-       struct cpu_timer_list *timer, *next;
-       cputime_t ptime = utime + stime;
-
-       list_for_each_entry_safe(timer, next, head, entry) {
-               list_del_init(&timer->entry);
-               if (timer->expires < cputime_to_expires(ptime)) {
-                       timer->expires = 0;
-               } else {
-                       timer->expires -= cputime_to_expires(ptime);
-               }
-       }
 
-       ++head;
-       list_for_each_entry_safe(timer, next, head, entry) {
-               list_del_init(&timer->entry);
-               if (timer->expires < cputime_to_expires(utime)) {
-                       timer->expires = 0;
-               } else {
-                       timer->expires -= cputime_to_expires(utime);
-               }
-       }
+       cputime_t ptime = utime + stime;
 
-       ++head;
-       list_for_each_entry_safe(timer, next, head, entry) {
-               list_del_init(&timer->entry);
-               if (timer->expires < sum_exec_runtime) {
-                       timer->expires = 0;
-               } else {
-                       timer->expires -= sum_exec_runtime;
-               }
-       }
+       cleanup_timers_list(head, cputime_to_expires(ptime));
+       cleanup_timers_list(++head, cputime_to_expires(utime));
+       cleanup_timers_list(++head, sum_exec_runtime);
 }
 
 /*
@@ -469,15 +453,21 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)
                       tsk->se.sum_exec_runtime + sig->sum_sched_runtime);
 }
 
-static void clear_dead_task(struct k_itimer *timer, unsigned long long now)
+static void clear_dead_task(struct k_itimer *itimer, unsigned long long now)
 {
+       struct cpu_timer_list *timer = &itimer->it.cpu;
+
        /*
         * That's all for this thread or process.
         * We leave our residual in expires to be reported.
         */
-       put_task_struct(timer->it.cpu.task);
-       timer->it.cpu.task = NULL;
-       timer->it.cpu.expires -= now;
+       put_task_struct(timer->task);
+       timer->task = NULL;
+       if (timer->expires < now) {
+               timer->expires = 0;
+       } else {
+               timer->expires -= now;
+       }
 }
 
 static inline int expires_gt(cputime_t expires, cputime_t new_exp)
@@ -872,6 +862,28 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
        }
 }
 
+static unsigned long long
+check_timers_list(struct list_head *timers,
+                 struct list_head *firing,
+                 unsigned long long curr)
+{
+       int maxfire = 20;
+
+       while (!list_empty(timers)) {
+               struct cpu_timer_list *t;
+
+               t = list_first_entry(timers, struct cpu_timer_list, entry);
+
+               if (!--maxfire || curr < t->expires)
+                       return t->expires;
+
+               t->firing = 1;
+               list_move_tail(&t->entry, firing);
+       }
+
+       return 0;
+}
+
 /*
  * Check for any per-thread CPU timers that have fired and move them off
  * the tsk->cpu_timers[N] list onto the firing list.  Here we update the
@@ -880,54 +892,20 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
 static void check_thread_timers(struct task_struct *tsk,
                                struct list_head *firing)
 {
-       int maxfire;
        struct list_head *timers = tsk->cpu_timers;
        struct signal_struct *const sig = tsk->signal;
+       struct task_cputime *tsk_expires = &tsk->cputime_expires;
+       unsigned long long expires;
        unsigned long soft;
 
-       maxfire = 20;
-       tsk->cputime_expires.prof_exp = 0;
-       while (!list_empty(timers)) {
-               struct cpu_timer_list *t = list_first_entry(timers,
-                                                     struct cpu_timer_list,
-                                                     entry);
-               if (!--maxfire || prof_ticks(tsk) < t->expires) {
-                       tsk->cputime_expires.prof_exp = expires_to_cputime(t->expires);
-                       break;
-               }
-               t->firing = 1;
-               list_move_tail(&t->entry, firing);
-       }
+       expires = check_timers_list(timers, firing, prof_ticks(tsk));
+       tsk_expires->prof_exp = expires_to_cputime(expires);
 
-       ++timers;
-       maxfire = 20;
-       tsk->cputime_expires.virt_exp = 0;
-       while (!list_empty(timers)) {
-               struct cpu_timer_list *t = list_first_entry(timers,
-                                                     struct cpu_timer_list,
-                                                     entry);
-               if (!--maxfire || virt_ticks(tsk) < t->expires) {
-                       tsk->cputime_expires.virt_exp = expires_to_cputime(t->expires);
-                       break;
-               }
-               t->firing = 1;
-               list_move_tail(&t->entry, firing);
-       }
+       expires = check_timers_list(++timers, firing, virt_ticks(tsk));
+       tsk_expires->virt_exp = expires_to_cputime(expires);
 
-       ++timers;
-       maxfire = 20;
-       tsk->cputime_expires.sched_exp = 0;
-       while (!list_empty(timers)) {
-               struct cpu_timer_list *t = list_first_entry(timers,
-                                                     struct cpu_timer_list,
-                                                     entry);
-               if (!--maxfire || tsk->se.sum_exec_runtime < t->expires) {
-                       tsk->cputime_expires.sched_exp = t->expires;
-                       break;
-               }
-               t->firing = 1;
-               list_move_tail(&t->entry, firing);
-       }
+       tsk_expires->sched_exp = check_timers_list(++timers, firing,
+                                                  tsk->se.sum_exec_runtime);
 
        /*
         * Check for the special case thread timers.
@@ -1012,7 +990,6 @@ static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
 static void check_process_timers(struct task_struct *tsk,
                                 struct list_head *firing)
 {
-       int maxfire;
        struct signal_struct *const sig = tsk->signal;
        unsigned long long utime, ptime, virt_expires, prof_expires;
        unsigned long long sum_sched_runtime, sched_expires;
@@ -1027,49 +1004,10 @@ static void check_process_timers(struct task_struct *tsk,
        utime = cputime_to_expires(cputime.utime);
        ptime = utime + cputime_to_expires(cputime.stime);
        sum_sched_runtime = cputime.sum_exec_runtime;
-       maxfire = 20;
-       prof_expires = 0;
-       while (!list_empty(timers)) {
-               struct cpu_timer_list *tl = list_first_entry(timers,
-                                                     struct cpu_timer_list,
-                                                     entry);
-               if (!--maxfire || ptime < tl->expires) {
-                       prof_expires = tl->expires;
-                       break;
-               }
-               tl->firing = 1;
-               list_move_tail(&tl->entry, firing);
-       }
 
-       ++timers;
-       maxfire = 20;
-       virt_expires = 0;
-       while (!list_empty(timers)) {
-               struct cpu_timer_list *tl = list_first_entry(timers,
-                                                     struct cpu_timer_list,
-                                                     entry);
-               if (!--maxfire || utime < tl->expires) {
-                       virt_expires = tl->expires;
-                       break;
-               }
-               tl->firing = 1;
-               list_move_tail(&tl->entry, firing);
-       }
-
-       ++timers;
-       maxfire = 20;
-       sched_expires = 0;
-       while (!list_empty(timers)) {
-               struct cpu_timer_list *tl = list_first_entry(timers,
-                                                     struct cpu_timer_list,
-                                                     entry);
-               if (!--maxfire || sum_sched_runtime < tl->expires) {
-                       sched_expires = tl->expires;
-                       break;
-               }
-               tl->firing = 1;
-               list_move_tail(&tl->entry, firing);
-       }
+       prof_expires = check_timers_list(timers, firing, ptime);
+       virt_expires = check_timers_list(++timers, firing, utime);
+       sched_expires = check_timers_list(++timers, firing, sum_sched_runtime);
 
        /*
         * Check for the special case process timers.
@@ -1159,6 +1097,7 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
                         * not yet reaped.  Take this opportunity to
                         * drop our task ref.
                         */
+                       cpu_timer_sample_group(timer->it_clock, p, &now);
                        clear_dead_task(timer, now);
                        goto out_unlock;
                }