diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-02-25 16:40:10 +0100 | 
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-02-25 16:40:10 +0100 | 
| commit | 2e31add2a7e2a15d07f592c21ba35870fa9a1d1f (patch) | |
| tree | 814e2c70fb5528f108114c0da6e5a1e219e6a0e1 /kernel/posix-cpu-timers.c | |
| parent | d639bab8da86d330493487e8c0fea8ca31f53427 (diff) | |
| parent | 17581ad812a9abb0182260374ef2e52d4a808a64 (diff) | |
Merge branch 'x86/urgent' into x86/pat
Diffstat (limited to 'kernel/posix-cpu-timers.c')
| -rw-r--r-- | kernel/posix-cpu-timers.c | 193 | 
1 files changed, 115 insertions, 78 deletions
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 157de3a47832..e976e505648d 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -10,76 +10,6 @@  #include <linux/kernel_stat.h>  /* - * Allocate the thread_group_cputime structure appropriately and fill in the - * current values of the fields.  Called from copy_signal() via - * thread_group_cputime_clone_thread() when adding a second or subsequent - * thread to a thread group.  Assumes interrupts are enabled when called. - */ -int thread_group_cputime_alloc(struct task_struct *tsk) -{ -	struct signal_struct *sig = tsk->signal; -	struct task_cputime *cputime; - -	/* -	 * If we have multiple threads and we don't already have a -	 * per-CPU task_cputime struct (checked in the caller), allocate -	 * one and fill it in with the times accumulated so far.  We may -	 * race with another thread so recheck after we pick up the sighand -	 * lock. -	 */ -	cputime = alloc_percpu(struct task_cputime); -	if (cputime == NULL) -		return -ENOMEM; -	spin_lock_irq(&tsk->sighand->siglock); -	if (sig->cputime.totals) { -		spin_unlock_irq(&tsk->sighand->siglock); -		free_percpu(cputime); -		return 0; -	} -	sig->cputime.totals = cputime; -	cputime = per_cpu_ptr(sig->cputime.totals, smp_processor_id()); -	cputime->utime = tsk->utime; -	cputime->stime = tsk->stime; -	cputime->sum_exec_runtime = tsk->se.sum_exec_runtime; -	spin_unlock_irq(&tsk->sighand->siglock); -	return 0; -} - -/** - * thread_group_cputime - Sum the thread group time fields across all CPUs. - * - * @tsk:	The task we use to identify the thread group. - * @times:	task_cputime structure in which we return the summed fields. - * - * Walk the list of CPUs to sum the per-CPU time fields in the thread group - * time structure. - */ -void thread_group_cputime( -	struct task_struct *tsk, -	struct task_cputime *times) -{ -	struct task_cputime *totals, *tot; -	int i; - -	totals = tsk->signal->cputime.totals; -	if (!totals) { -		times->utime = tsk->utime; -		times->stime = tsk->stime; -		times->sum_exec_runtime = tsk->se.sum_exec_runtime; -		return; -	} - -	times->stime = times->utime = cputime_zero; -	times->sum_exec_runtime = 0; -	for_each_possible_cpu(i) { -		tot = per_cpu_ptr(totals, i); -		times->utime = cputime_add(times->utime, tot->utime); -		times->stime = cputime_add(times->stime, tot->stime); -		times->sum_exec_runtime += tot->sum_exec_runtime; -	} -} - -/*   * Called after updating RLIMIT_CPU to set timer expiration if necessary.   */  void update_rlimit_cpu(unsigned long rlim_new) @@ -300,6 +230,71 @@ static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,  	return 0;  } +void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) +{ +	struct sighand_struct *sighand; +	struct signal_struct *sig; +	struct task_struct *t; + +	*times = INIT_CPUTIME; + +	rcu_read_lock(); +	sighand = rcu_dereference(tsk->sighand); +	if (!sighand) +		goto out; + +	sig = tsk->signal; + +	t = tsk; +	do { +		times->utime = cputime_add(times->utime, t->utime); +		times->stime = cputime_add(times->stime, t->stime); +		times->sum_exec_runtime += t->se.sum_exec_runtime; + +		t = next_thread(t); +	} while (t != tsk); + +	times->utime = cputime_add(times->utime, sig->utime); +	times->stime = cputime_add(times->stime, sig->stime); +	times->sum_exec_runtime += sig->sum_sched_runtime; +out: +	rcu_read_unlock(); +} + +static void update_gt_cputime(struct task_cputime *a, struct task_cputime *b) +{ +	if (cputime_gt(b->utime, a->utime)) +		a->utime = b->utime; + +	if (cputime_gt(b->stime, a->stime)) +		a->stime = b->stime; + +	if (b->sum_exec_runtime > a->sum_exec_runtime) +		a->sum_exec_runtime = b->sum_exec_runtime; +} + +void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times) +{ +	struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; +	struct task_cputime sum; +	unsigned long flags; + +	spin_lock_irqsave(&cputimer->lock, flags); +	if (!cputimer->running) { +		cputimer->running = 1; +		/* +		 * The POSIX timer interface allows for absolute time expiry +		 * values through the TIMER_ABSTIME flag, therefore we have +		 * to synchronize the timer to the clock every time we start +		 * it. +		 */ +		thread_group_cputime(tsk, &sum); +		update_gt_cputime(&cputimer->cputime, &sum); +	} +	*times = cputimer->cputime; +	spin_unlock_irqrestore(&cputimer->lock, flags); +} +  /*   * Sample a process (thread group) clock for the given group_leader task.   * Must be called with tasklist_lock held for reading. @@ -527,7 +522,7 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)  {  	struct task_cputime cputime; -	thread_group_cputime(tsk, &cputime); +	thread_group_cputimer(tsk, &cputime);  	cleanup_timers(tsk->signal->cpu_timers,  		       cputime.utime, cputime.stime, cputime.sum_exec_runtime);  } @@ -686,6 +681,33 @@ static void cpu_timer_fire(struct k_itimer *timer)  }  /* + * Sample a process (thread group) timer for the given group_leader task. + * Must be called with tasklist_lock held for reading. + */ +static int cpu_timer_sample_group(const clockid_t which_clock, +				  struct task_struct *p, +				  union cpu_time_count *cpu) +{ +	struct task_cputime cputime; + +	thread_group_cputimer(p, &cputime); +	switch (CPUCLOCK_WHICH(which_clock)) { +	default: +		return -EINVAL; +	case CPUCLOCK_PROF: +		cpu->cpu = cputime_add(cputime.utime, cputime.stime); +		break; +	case CPUCLOCK_VIRT: +		cpu->cpu = cputime.utime; +		break; +	case CPUCLOCK_SCHED: +		cpu->sched = cputime.sum_exec_runtime + task_delta_exec(p); +		break; +	} +	return 0; +} + +/*   * Guts of sys_timer_settime for CPU timers.   * This is called with the timer locked and interrupts disabled.   * If we return TIMER_RETRY, it's necessary to release the timer's lock @@ -746,7 +768,7 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags,  	if (CPUCLOCK_PERTHREAD(timer->it_clock)) {  		cpu_clock_sample(timer->it_clock, p, &val);  	} else { -		cpu_clock_sample_group(timer->it_clock, p, &val); +		cpu_timer_sample_group(timer->it_clock, p, &val);  	}  	if (old) { @@ -894,7 +916,7 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)  			read_unlock(&tasklist_lock);  			goto dead;  		} else { -			cpu_clock_sample_group(timer->it_clock, p, &now); +			cpu_timer_sample_group(timer->it_clock, p, &now);  			clear_dead = (unlikely(p->exit_state) &&  				      thread_group_empty(p));  		} @@ -1034,6 +1056,19 @@ static void check_thread_timers(struct task_struct *tsk,  	}  } +static void stop_process_timers(struct task_struct *tsk) +{ +	struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; +	unsigned long flags; + +	if (!cputimer->running) +		return; + +	spin_lock_irqsave(&cputimer->lock, flags); +	cputimer->running = 0; +	spin_unlock_irqrestore(&cputimer->lock, flags); +} +  /*   * Check for any per-thread CPU timers that have fired and move them   * off the tsk->*_timers list onto the firing list.  Per-thread timers @@ -1057,13 +1092,15 @@ static void check_process_timers(struct task_struct *tsk,  	    sig->rlim[RLIMIT_CPU].rlim_cur == RLIM_INFINITY &&  	    list_empty(&timers[CPUCLOCK_VIRT]) &&  	    cputime_eq(sig->it_virt_expires, cputime_zero) && -	    list_empty(&timers[CPUCLOCK_SCHED])) +	    list_empty(&timers[CPUCLOCK_SCHED])) { +		stop_process_timers(tsk);  		return; +	}  	/*  	 * Collect the current process totals.  	 */ -	thread_group_cputime(tsk, &cputime); +	thread_group_cputimer(tsk, &cputime);  	utime = cputime.utime;  	ptime = cputime_add(utime, cputime.stime);  	sum_sched_runtime = cputime.sum_exec_runtime; @@ -1234,7 +1271,7 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)  			clear_dead_task(timer, now);  			goto out_unlock;  		} -		cpu_clock_sample_group(timer->it_clock, p, &now); +		cpu_timer_sample_group(timer->it_clock, p, &now);  		bump_cpu_timer(timer, now);  		/* Leave the tasklist_lock locked for the call below.  */  	} @@ -1329,7 +1366,7 @@ static inline int fastpath_timer_check(struct task_struct *tsk)  	if (!task_cputime_zero(&sig->cputime_expires)) {  		struct task_cputime group_sample; -		thread_group_cputime(tsk, &group_sample); +		thread_group_cputimer(tsk, &group_sample);  		if (task_cputime_expired(&group_sample, &sig->cputime_expires))  			return 1;  	} @@ -1411,7 +1448,7 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,  	struct list_head *head;  	BUG_ON(clock_idx == CPUCLOCK_SCHED); -	cpu_clock_sample_group(clock_idx, tsk, &now); +	cpu_timer_sample_group(clock_idx, tsk, &now);  	if (oldval) {  		if (!cputime_eq(*oldval, cputime_zero)) {  | 
