From: Roland McGrath POSIX requires that setitimer, getitimer, and alarm work on a per-process basis. Currently, Linux implements these for individual threads. This patch fixes these semantics for the ITIMER_PROF timer (which generates SIGPROF) and the ITIMER_VIRTUAL timer (which generates SIGVTALRM), making them shared by all threads in a process (thread group). This patch should be applied after the one that fixes ITIMER_REAL. The essential machinery for these timers is tied into the new posix-timers code for process CPU clocks and timers. This patch requires the cputimers patch and its dependencies. Signed-off-by: Roland McGrath Signed-off-by: Andrew Morton --- 25-akpm/include/linux/posix-timers.h | 2 25-akpm/include/linux/sched.h | 6 - 25-akpm/include/linux/signal.h | 1 25-akpm/kernel/exit.c | 3 25-akpm/kernel/fork.c | 16 +-- 25-akpm/kernel/itimer.c | 176 +++++++++++++++++++++++------------ 25-akpm/kernel/posix-cpu-timers.c | 157 +++++++++++++++++++++++++++---- 25-akpm/kernel/sched.c | 47 --------- 25-akpm/kernel/signal.c | 2 9 files changed, 277 insertions(+), 133 deletions(-) diff -puN include/linux/posix-timers.h~make-itimer_prof-itimer_virtual-per-process include/linux/posix-timers.h --- 25/include/linux/posix-timers.h~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.057412824 -0800 +++ 25-akpm/include/linux/posix-timers.h 2005-01-26 18:24:13.073410392 -0800 @@ -133,5 +133,7 @@ void run_posix_cpu_timers(struct task_st void posix_cpu_timers_exit(struct task_struct *); void posix_cpu_timers_exit_group(struct task_struct *); +void set_process_cpu_timer(struct task_struct *, unsigned int, + cputime_t *, cputime_t *); #endif diff -puN include/linux/sched.h~make-itimer_prof-itimer_virtual-per-process include/linux/sched.h --- 25/include/linux/sched.h~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.058412672 -0800 +++ 25-akpm/include/linux/sched.h 2005-01-26 18:24:13.074410240 -0800 @@ -304,6 +304,10 @@ struct signal_struct { struct timer_list real_timer; unsigned long it_real_value, it_real_incr; + /* ITIMER_PROF and ITIMER_VIRTUAL timers for the process */ + cputime_t it_prof_expires, it_virt_expires; + cputime_t it_prof_incr, it_virt_incr; + /* job control IDs */ pid_t pgrp; pid_t tty_old_pgrp; @@ -610,8 +614,6 @@ struct task_struct { int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ unsigned long rt_priority; - cputime_t it_virt_value, it_virt_incr; - cputime_t it_prof_value, it_prof_incr; cputime_t utime, stime; unsigned long nvcsw, nivcsw; /* context switch counts */ struct timespec start_time; diff -puN include/linux/signal.h~make-itimer_prof-itimer_virtual-per-process include/linux/signal.h --- 25/include/linux/signal.h~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.059412520 -0800 +++ 25-akpm/include/linux/signal.h 2005-01-26 18:24:13.075410088 -0800 @@ -212,6 +212,7 @@ static inline void init_sigpending(struc } extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); +extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); extern long do_sigpending(void __user *, unsigned long); extern int sigprocmask(int, sigset_t *, sigset_t *); diff -puN kernel/exit.c~make-itimer_prof-itimer_virtual-per-process kernel/exit.c --- 25/kernel/exit.c~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.061412216 -0800 +++ 25-akpm/kernel/exit.c 2005-01-26 18:24:52.595402136 -0800 @@ -753,9 +753,6 @@ static void exit_notify(struct task_stru state = EXIT_DEAD; tsk->exit_state = state; - tsk->it_virt_value = cputime_zero; - tsk->it_prof_value = cputime_zero; - write_unlock_irq(&tasklist_lock); list_for_each_safe(_p, _n, &ptrace_dead) { diff -puN kernel/fork.c~make-itimer_prof-itimer_virtual-per-process kernel/fork.c --- 25/kernel/fork.c~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.063411912 -0800 +++ 25-akpm/kernel/fork.c 2005-01-26 18:24:14.509192120 -0800 @@ -745,6 +745,11 @@ static inline int copy_signal(unsigned l sig->real_timer.data = (unsigned long) tsk; init_timer(&sig->real_timer); + sig->it_virt_expires = cputime_zero; + sig->it_virt_incr = cputime_zero; + sig->it_prof_expires = cputime_zero; + sig->it_prof_incr = cputime_zero; + sig->tty = current->signal->tty; sig->pgrp = process_group(current); sig->session = current->signal->session; @@ -875,11 +880,6 @@ static task_t *copy_process(unsigned lon clear_tsk_thread_flag(p, TIF_SIGPENDING); init_sigpending(&p->pending); - p->it_virt_value = cputime_zero; - p->it_virt_incr = cputime_zero; - p->it_prof_value = cputime_zero; - p->it_prof_incr = cputime_zero; - p->utime = cputime_zero; p->stime = cputime_zero; p->sched_time = 0; @@ -1028,7 +1028,11 @@ static task_t *copy_process(unsigned lon set_tsk_thread_flag(p, TIF_SIGPENDING); } - if (!list_empty(¤t->signal->cpu_timers[0]) || + if (!cputime_eq(current->signal->it_virt_expires, + cputime_zero) || + !cputime_eq(current->signal->it_prof_expires, + cputime_zero) || + !list_empty(¤t->signal->cpu_timers[0]) || !list_empty(¤t->signal->cpu_timers[1]) || !list_empty(¤t->signal->cpu_timers[2])) { /* diff -puN kernel/itimer.c~make-itimer_prof-itimer_virtual-per-process kernel/itimer.c --- 25/kernel/itimer.c~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.064411760 -0800 +++ 25-akpm/kernel/itimer.c 2005-01-26 18:24:14.510191968 -0800 @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -29,24 +30,67 @@ static unsigned long it_real_value(struc int do_getitimer(int which, struct itimerval *value) { + struct task_struct *tsk = current; unsigned long interval, val; + cputime_t cinterval, cval; switch (which) { case ITIMER_REAL: - spin_lock_irq(¤t->sighand->siglock); - interval = current->signal->it_real_incr; - val = it_real_value(current->signal); - spin_unlock_irq(¤t->sighand->siglock); + spin_lock_irq(&tsk->sighand->siglock); + interval = tsk->signal->it_real_incr; + val = it_real_value(tsk->signal); + spin_unlock_irq(&tsk->sighand->siglock); jiffies_to_timeval(val, &value->it_value); jiffies_to_timeval(interval, &value->it_interval); break; case ITIMER_VIRTUAL: - cputime_to_timeval(current->it_virt_value, &value->it_value); - cputime_to_timeval(current->it_virt_incr, &value->it_interval); + read_lock(&tasklist_lock); + spin_lock_irq(&tsk->sighand->siglock); + cval = tsk->signal->it_virt_expires; + cinterval = tsk->signal->it_virt_incr; + if (!cputime_eq(cval, cputime_zero)) { + struct task_struct *t = tsk; + cputime_t utime = tsk->signal->utime; + do { + utime = cputime_add(utime, t->utime); + t = next_thread(t); + } while (t != tsk); + if (cputime_le(cval, utime)) { /* about to fire */ + val = jiffies_to_cputime(1); + } else { + val = cputime_sub(val, utime); + } + } + spin_unlock_irq(&tsk->sighand->siglock); + read_unlock(&tasklist_lock); + cputime_to_timeval(cval, &value->it_value); + cputime_to_timeval(cinterval, &value->it_interval); break; case ITIMER_PROF: - cputime_to_timeval(current->it_prof_value, &value->it_value); - cputime_to_timeval(current->it_prof_incr, &value->it_interval); + read_lock(&tasklist_lock); + spin_lock_irq(&tsk->sighand->siglock); + cval = tsk->signal->it_prof_expires; + cinterval = tsk->signal->it_prof_incr; + if (!cputime_eq(cval, cputime_zero)) { + struct task_struct *t = tsk; + cputime_t ptime = cputime_add(tsk->signal->utime, + tsk->signal->stime); + do { + ptime = cputime_add(ptime, + cputime_add(t->utime, + t->stime)); + t = next_thread(t); + } while (t != tsk); + if (cputime_le(cval, ptime)) { /* about to fire */ + val = jiffies_to_cputime(1); + } else { + val = cputime_sub(val, ptime); + } + } + spin_unlock_irq(&tsk->sighand->siglock); + read_unlock(&tasklist_lock); + cputime_to_timeval(cval, &value->it_value); + cputime_to_timeval(cinterval, &value->it_interval); break; default: return(-EINVAL); @@ -101,57 +145,75 @@ int do_setitimer(int which, struct itime { struct task_struct *tsk = current; unsigned long val, interval; - cputime_t cputime; + cputime_t cval, cinterval, nval, ninterval; switch (which) { - case ITIMER_REAL: - spin_lock_irq(&tsk->sighand->siglock); - interval = tsk->signal->it_real_incr; - val = it_real_value(tsk->signal); - if (val) - del_timer_sync(&tsk->signal->real_timer); - tsk->signal->it_real_incr = - timeval_to_jiffies(&value->it_interval); - it_real_arm(tsk, timeval_to_jiffies(&value->it_value)); - spin_unlock_irq(&tsk->sighand->siglock); - if (ovalue) { - jiffies_to_timeval(val, &ovalue->it_value); - jiffies_to_timeval(interval, - &ovalue->it_interval); - } - break; - case ITIMER_VIRTUAL: - if (ovalue) { - cputime_to_timeval(tsk->it_virt_value, - &ovalue->it_value); - cputime_to_timeval(tsk->it_virt_incr, - &ovalue->it_interval); - } - cputime = timeval_to_cputime(&value->it_value); - if (cputime_gt(cputime, cputime_zero)) - cputime = cputime_add(cputime, - jiffies_to_cputime(1)); - tsk->it_virt_value = cputime; - cputime = timeval_to_cputime(&value->it_interval); - tsk->it_virt_incr = cputime; - break; - case ITIMER_PROF: - if (ovalue) { - cputime_to_timeval(tsk->it_prof_value, - &ovalue->it_value); - cputime_to_timeval(tsk->it_prof_incr, - &ovalue->it_interval); - } - cputime = timeval_to_cputime(&value->it_value); - if (cputime_gt(cputime, cputime_zero)) - cputime = cputime_add(cputime, - jiffies_to_cputime(1)); - tsk->it_prof_value = cputime; - cputime = timeval_to_cputime(&value->it_interval); - tsk->it_prof_incr = cputime; - break; - default: - return -EINVAL; + case ITIMER_REAL: + spin_lock_irq(&tsk->sighand->siglock); + interval = tsk->signal->it_real_incr; + val = it_real_value(tsk->signal); + if (val) + del_timer_sync(&tsk->signal->real_timer); + tsk->signal->it_real_incr = + timeval_to_jiffies(&value->it_interval); + it_real_arm(tsk, timeval_to_jiffies(&value->it_value)); + spin_unlock_irq(&tsk->sighand->siglock); + if (ovalue) { + jiffies_to_timeval(val, &ovalue->it_value); + jiffies_to_timeval(interval, + &ovalue->it_interval); + } + break; + case ITIMER_VIRTUAL: + nval = timeval_to_cputime(&value->it_value); + ninterval = timeval_to_cputime(&value->it_interval); + read_lock(&tasklist_lock); + spin_lock_irq(&tsk->sighand->siglock); + cval = tsk->signal->it_virt_expires; + cinterval = tsk->signal->it_virt_incr; + if (!cputime_eq(cval, cputime_zero) || + !cputime_eq(nval, cputime_zero)) { + if (cputime_gt(nval, cputime_zero)) + nval = cputime_add(nval, + jiffies_to_cputime(1)); + set_process_cpu_timer(tsk, CPUCLOCK_VIRT, + &nval, &cval); + } + tsk->signal->it_virt_expires = nval; + tsk->signal->it_virt_incr = ninterval; + spin_unlock_irq(&tsk->sighand->siglock); + read_unlock(&tasklist_lock); + if (ovalue) { + cputime_to_timeval(cval, &ovalue->it_value); + cputime_to_timeval(cinterval, &ovalue->it_interval); + } + break; + case ITIMER_PROF: + nval = timeval_to_cputime(&value->it_value); + ninterval = timeval_to_cputime(&value->it_interval); + read_lock(&tasklist_lock); + spin_lock_irq(&tsk->sighand->siglock); + cval = tsk->signal->it_prof_expires; + cinterval = tsk->signal->it_prof_incr; + if (!cputime_eq(cval, cputime_zero) || + !cputime_eq(nval, cputime_zero)) { + if (cputime_gt(nval, cputime_zero)) + nval = cputime_add(nval, + jiffies_to_cputime(1)); + set_process_cpu_timer(tsk, CPUCLOCK_PROF, + &nval, &cval); + } + tsk->signal->it_prof_expires = nval; + tsk->signal->it_prof_incr = ninterval; + spin_unlock_irq(&tsk->sighand->siglock); + read_unlock(&tasklist_lock); + if (ovalue) { + cputime_to_timeval(cval, &ovalue->it_value); + cputime_to_timeval(cinterval, &ovalue->it_interval); + } + break; + default: + return -EINVAL; } return 0; } diff -puN kernel/posix-cpu-timers.c~make-itimer_prof-itimer_virtual-per-process kernel/posix-cpu-timers.c --- 25/kernel/posix-cpu-timers.c~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.066411456 -0800 +++ 25-akpm/kernel/posix-cpu-timers.c 2005-01-26 18:24:14.513191512 -0800 @@ -190,36 +190,31 @@ static int cpu_clock_sample(clockid_t wh /* * Sample a process (thread group) clock for the given group_leader task. * Must be called with tasklist_lock held for reading. + * Must be called with tasklist_lock held for reading, and p->sighand->siglock. */ -static int cpu_clock_sample_group(clockid_t which_clock, - struct task_struct *p, - union cpu_time_count *cpu) +static int cpu_clock_sample_group_locked(unsigned int clock_idx, + struct task_struct *p, + union cpu_time_count *cpu) { struct task_struct *t = p; - unsigned long flags; - switch (CPUCLOCK_WHICH(which_clock)) { + switch (clock_idx) { default: return -EINVAL; case CPUCLOCK_PROF: - spin_lock_irqsave(&p->sighand->siglock, flags); cpu->cpu = cputime_add(p->signal->utime, p->signal->stime); do { cpu->cpu = cputime_add(cpu->cpu, prof_ticks(t)); t = next_thread(t); } while (t != p); - spin_unlock_irqrestore(&p->sighand->siglock, flags); break; case CPUCLOCK_VIRT: - spin_lock_irqsave(&p->sighand->siglock, flags); cpu->cpu = p->signal->utime; do { cpu->cpu = cputime_add(cpu->cpu, virt_ticks(t)); t = next_thread(t); } while (t != p); - spin_unlock_irqrestore(&p->sighand->siglock, flags); break; case CPUCLOCK_SCHED: - spin_lock_irqsave(&p->sighand->siglock, flags); cpu->sched = p->signal->sched_time; /* Add in each other live thread. */ while ((t = next_thread(t)) != p) { @@ -237,12 +232,28 @@ static int cpu_clock_sample_group(clocki } else { cpu->sched += p->sched_time; } - spin_unlock_irqrestore(&p->sighand->siglock, flags); break; } return 0; } +/* + * 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, + struct task_struct *p, + union cpu_time_count *cpu) +{ + int ret; + unsigned long flags; + spin_lock_irqsave(&p->sighand->siglock, flags); + ret = cpu_clock_sample_group_locked(CPUCLOCK_WHICH(which_clock), p, + cpu); + spin_unlock_irqrestore(&p->sighand->siglock, flags); + return ret; +} + int posix_cpu_clock_get(clockid_t which_clock, struct timespec *tp) { @@ -453,20 +464,22 @@ void posix_cpu_timers_exit_group(struct * Set the expiry times of all the threads in the process so one of them * will go off before the process cumulative expiry total is reached. */ -static void -process_timer_rebalance(struct k_itimer *timer, union cpu_time_count val) +static void process_timer_rebalance(struct task_struct *p, + unsigned int clock_idx, + union cpu_time_count expires, + union cpu_time_count val) { cputime_t ticks, left; unsigned long long ns, nsleft; - struct task_struct *const p = timer->it.cpu.task, *t = p; + struct task_struct *t = p; unsigned int nthreads = atomic_read(&p->signal->live); - switch (CPUCLOCK_WHICH(timer->it_clock)) { + switch (clock_idx) { default: BUG(); break; case CPUCLOCK_PROF: - left = cputime_sub(timer->it.cpu.expires.cpu, val.cpu) + left = cputime_sub(expires.cpu, val.cpu) / nthreads; do { if (!unlikely(t->exit_state)) { @@ -481,7 +494,7 @@ process_timer_rebalance(struct k_itimer } while (t != p); break; case CPUCLOCK_VIRT: - left = cputime_sub(timer->it.cpu.expires.cpu, val.cpu) + left = cputime_sub(expires.cpu, val.cpu) / nthreads; do { if (!unlikely(t->exit_state)) { @@ -496,7 +509,7 @@ process_timer_rebalance(struct k_itimer } while (t != p); break; case CPUCLOCK_SCHED: - nsleft = timer->it.cpu.expires.sched - val.sched; + nsleft = expires.sched - val.sched; do_div(nsleft, nthreads); do { if (!unlikely(t->exit_state)) { @@ -590,7 +603,31 @@ static void arm_timer(struct k_itimer *t * For a process timer, we must balance * all the live threads' expirations. */ - process_timer_rebalance(timer, now); + switch (CPUCLOCK_WHICH(timer->it_clock)) { + default: + BUG(); + case CPUCLOCK_VIRT: + if (!cputime_eq(p->signal->it_virt_expires, + cputime_zero) && + cputime_lt(p->signal->it_virt_expires, + timer->it.cpu.expires.cpu)) + break; + goto rebalance; + case CPUCLOCK_PROF: + if (!cputime_eq(p->signal->it_prof_expires, + cputime_zero) && + cputime_lt(p->signal->it_prof_expires, + timer->it.cpu.expires.cpu)) + break; + goto rebalance; + case CPUCLOCK_SCHED: + rebalance: + process_timer_rebalance( + timer->it.cpu.task, + CPUCLOCK_WHICH(timer->it_clock), + timer->it.cpu.expires, now); + break; + } } } @@ -952,7 +989,9 @@ static void check_process_timers(struct * Don't sample the current process CPU clocks if there are no timers. */ if (list_empty(&timers[CPUCLOCK_PROF]) && + cputime_eq(sig->it_prof_expires, cputime_zero) && list_empty(&timers[CPUCLOCK_VIRT]) && + cputime_eq(sig->it_virt_expires, cputime_zero) && list_empty(&timers[CPUCLOCK_SCHED])) return; @@ -1012,6 +1051,42 @@ static void check_process_timers(struct list_move_tail(&t->entry, firing); } + /* + * Check for the special case process timers. + */ + if (!cputime_eq(sig->it_prof_expires, cputime_zero)) { + if (cputime_ge(ptime, sig->it_prof_expires)) { + /* ITIMER_PROF fires and reloads. */ + sig->it_prof_expires = sig->it_prof_incr; + if (!cputime_eq(sig->it_prof_expires, cputime_zero)) { + sig->it_prof_expires = cputime_add( + sig->it_prof_expires, ptime); + } + __group_send_sig_info(SIGPROF, SEND_SIG_PRIV, tsk); + } + if (!cputime_eq(sig->it_prof_expires, cputime_zero) && + (cputime_eq(prof_expires, cputime_zero) || + cputime_lt(sig->it_prof_expires, prof_expires))) { + prof_expires = sig->it_prof_expires; + } + } + if (!cputime_eq(sig->it_virt_expires, cputime_zero)) { + if (cputime_ge(utime, sig->it_virt_expires)) { + /* ITIMER_VIRTUAL fires and reloads. */ + sig->it_virt_expires = sig->it_virt_incr; + if (!cputime_eq(sig->it_virt_expires, cputime_zero)) { + sig->it_virt_expires = cputime_add( + sig->it_virt_expires, utime); + } + __group_send_sig_info(SIGVTALRM, SEND_SIG_PRIV, tsk); + } + if (!cputime_eq(sig->it_virt_expires, cputime_zero) && + (cputime_eq(virt_expires, cputime_zero) || + cputime_lt(sig->it_virt_expires, virt_expires))) { + virt_expires = sig->it_virt_expires; + } + } + if (!cputime_eq(prof_expires, cputime_zero) || !cputime_eq(virt_expires, cputime_zero) || sched_expires != 0) { @@ -1197,6 +1272,50 @@ void run_posix_cpu_timers(struct task_st } } +/* + * Set one of the process-wide special case CPU timers. + * The tasklist_lock and tsk->sighand->siglock must be held by the caller. + */ +void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, + cputime_t *newval, cputime_t *oldval) +{ + union cpu_time_count now; + struct list_head *head; + + BUG_ON(clock_idx == CPUCLOCK_SCHED); + cpu_clock_sample_group_locked(clock_idx, tsk, &now); + + if (oldval && !cputime_eq(*oldval, cputime_zero)) { + if (cputime_le(*oldval, now.cpu)) { /* Just about to fire. */ + *oldval = jiffies_to_cputime(1); + } else { + *oldval = cputime_sub(*oldval, now.cpu); + } + } + + if (cputime_eq(*newval, cputime_zero)) + return; + *newval = cputime_add(*newval, now.cpu); + + /* + * Check whether there are any process timers already set to fire + * before this one. If so, we don't have anything more to do. + */ + head = &tsk->signal->cpu_timers[clock_idx]; + if (list_empty(head) || + cputime_ge(list_entry(head->next, + struct cpu_timer_list, entry)->expires.cpu, + *newval)) { + /* + * Rejigger each thread's expiry time so that one will + * notice before we hit the process-cumulative expiry time. + */ + union cpu_time_count expires = { .sched = 0 }; + expires.cpu = *newval; + process_timer_rebalance(tsk, clock_idx, expires, now); + } +} + static long posix_cpu_clock_nanosleep_restart(struct restart_block *); int posix_cpu_nsleep(clockid_t which_clock, int flags, diff -puN kernel/sched.c~make-itimer_prof-itimer_virtual-per-process kernel/sched.c --- 25/kernel/sched.c~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.068411152 -0800 +++ 25-akpm/kernel/sched.c 2005-01-26 18:24:14.516191056 -0800 @@ -2277,46 +2277,6 @@ unsigned long long current_sched_time(co ((rq)->curr->static_prio > (rq)->best_expired_prio)) /* - * Do the virtual cpu time signal calculations. - * @p: the process that the cpu time gets accounted to - * @cputime: the cpu time spent in user space since the last update - */ -static inline void account_it_virt(struct task_struct * p, cputime_t cputime) -{ - cputime_t it_virt = p->it_virt_value; - - if (cputime_gt(it_virt, cputime_zero) && - cputime_gt(cputime, cputime_zero)) { - if (cputime_ge(cputime, it_virt)) { - it_virt = cputime_add(it_virt, p->it_virt_incr); - send_sig(SIGVTALRM, p, 1); - } - it_virt = cputime_sub(it_virt, cputime); - p->it_virt_value = it_virt; - } -} - -/* - * Do the virtual profiling signal calculations. - * @p: the process that the cpu time gets accounted to - * @cputime: the cpu time spent in user and kernel space since the last update - */ -static void account_it_prof(struct task_struct *p, cputime_t cputime) -{ - cputime_t it_prof = p->it_prof_value; - - if (cputime_gt(it_prof, cputime_zero) && - cputime_gt(cputime, cputime_zero)) { - if (cputime_ge(cputime, it_prof)) { - it_prof = cputime_add(it_prof, p->it_prof_incr); - send_sig(SIGPROF, p, 1); - } - it_prof = cputime_sub(it_prof, cputime); - p->it_prof_value = it_prof; - } -} - -/* * Check if the process went over its cputime resource limit after * some cpu time got added to utime/stime. * @p: the process that the cpu time gets accounted to @@ -2353,10 +2313,8 @@ void account_user_time(struct task_struc p->utime = cputime_add(p->utime, cputime); - /* Check for signals (SIGVTALRM, SIGPROF, SIGXCPU & SIGKILL). */ + /* Check for signals (SIGXCPU & SIGKILL). */ check_rlimit(p, cputime); - account_it_virt(p, cputime); - account_it_prof(p, cputime); /* Add user time to cpustat. */ tmp = cputime_to_cputime64(cputime); @@ -2381,10 +2339,9 @@ void account_system_time(struct task_str p->stime = cputime_add(p->stime, cputime); - /* Check for signals (SIGPROF, SIGXCPU & SIGKILL). */ + /* Check for signals (SIGXCPU & SIGKILL). */ if (likely(p->signal && p->exit_state < EXIT_ZOMBIE)) { check_rlimit(p, cputime); - account_it_prof(p, cputime); } /* Add system time to cpustat. */ diff -puN kernel/signal.c~make-itimer_prof-itimer_virtual-per-process kernel/signal.c --- 25/kernel/signal.c~make-itimer_prof-itimer_virtual-per-process 2005-01-26 18:24:13.069411000 -0800 +++ 25-akpm/kernel/signal.c 2005-01-26 18:24:14.518190752 -0800 @@ -1051,7 +1051,7 @@ __group_complete_signal(int sig, struct return; } -static int +int __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) { int ret = 0; _