kernels/linux-2.6.24/kernel/sys.c
/*
 * It would make sense to put struct rusage in the task_struct,
 * except that would make the task_struct be *really big*.  After
 * task_struct gets moved into malloc'ed memory, it would
 * make sense to do this.  It will make moving the rest of the information
 * a lot simpler!  (Which we're not doing right now because we're not
 * measuring them yet).
 *
 * When sampling multiple threads for RUSAGE_SELF, under SMP we might have
 * races with threads incrementing their own counters.  But since word
 * reads are atomic, we either get new values or old values and we don't
 * care which for the sums.  We always take the siglock to protect reading
 * the c* fields from p->signal from races with exit.c updating those
 * fields when reaping, so a sample either gets all the additions of a
 * given child after it's reaped, or none so this sample is before reaping.
 *
 * Locking:
 * We need to take the siglock for CHILDEREN, SELF and BOTH
 * for  the cases current multithreaded, non-current single threaded
 * non-current multithreaded.  Thread traversal is now safe with
 * the siglock held.
 * Strictly speaking, we donot need to take the siglock if we are current and
 * single threaded,  as no one else can take our signal_struct away, no one
 * else can  reap the  children to update signal->c* counters, and no one else
 * can race with the signal-> fields. If we do not take any lock, the
 * signal-> fields could be read out of order while another thread was just
 * exiting. So we should  place a read memory barrier when we avoid the lock.
 * On the writer side,  write memory barrier is implied in  __exit_signal
 * as __exit_signal releases  the siglock spinlock after updating the signal->
 * fields. But we don't do this yet to keep things simple.
 *
 */
It would make sense to put struct rusage in the task_struct,
except that would make the task_struct be *really big*.  After
task_struct gets moved into malloc'ed memory, it would
make sense to do this.  It will make moving the rest of the information
a lot simpler.  (Which we're not doing right now because we're not
measuring them yet).

When sampling multiple threads for RUSAGE_SELF, under SMP we might have
races with threads incrementing their own counters.  But since word
reads are atomic, we either get new values or old values and we don't
care which for the sums.  We always take the siglock to protect reading
the c* fields from p->signal from races with exit.c updating those
fields when reaping, so a sample either gets all the additions of a
given child after it's reaped, or none so this sample is before reaping.

We need to take the siglock for CHILDEREN, SELF and BOTH
for  the cases current multithreaded, non-current single threaded
non-current multithreaded.  Thread traversal is now safe with
the siglock held.
Strictly speaking, we donot need to take the siglock if we are current and
single threaded,  as no one else can take our signal_struct away, no one
else can  reap the  children to update signal->c* counters, and no one else
can race with the signal-> fields. If we do not take any lock, the
signal-> fields could be read out of order while another thread was just
exiting. So we should  place a read memory barrier when we avoid the lock.
On the writer side,  write memory barrier is implied in  __exit_signal
as __exit_signal releases  the siglock spinlock after updating the signal->
fields. But we don't do this yet to keep things simple.
It would make sense to put struct rusage in the task_struct except that would make the task_struct be * really big * . After task_struct gets moved into malloc ' ed memory it would make sense to do this . It will make moving the rest of the information a lot simpler . ( Which we ' re not doing right now because we ' re not measuring them yet ) . When sampling multiple threads for RUSAGE_SELF under SMP we might have races with threads incrementing their own counters . But since word reads are atomic we either get new values or old values and we don ' t care which for the sums . We always take the siglock to protect reading the c * fields from p - > signal from races with exit . c updating those fields when reaping so a sample either gets all the additions of a given child after it ' s reaped or none so this sample is before reaping . We need to take the siglock for CHILDEREN SELF and BOTH for the cases current multithreaded non - current single threaded non - current multithreaded . Thread traversal is now safe with the siglock held . Strictly speaking we donot need to take the siglock if we are current and single threaded as no one else can take our signal_struct away no one else can reap the children to update signal - > c * counters and no one else can race with the signal - > fields . If we do not take any lock the signal - > fields could be read out of order while another thread was just exiting . So we should place a read memory barrier when we avoid the lock . On the writer side write memory barrier is implied in __exit_signal as __exit_signal releases the siglock spinlock after updating the signal - > fields . But we don ' t do this yet to keep things simple .
static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
{
	struct task_struct *t;
	unsigned long flags;
	cputime_t utime, stime;
	memset((char *) r, 0, sizeof *r);
	utime = stime = cputime_zero;
	rcu_read_lock();
	if (!lock_task_sighand(p, &flags)) {
		rcu_read_unlock();
		return;
	}
	switch (who) {
		case RUSAGE_BOTH:
		case RUSAGE_CHILDREN:
			utime = p->signal->cutime;
			stime = p->signal->cstime;
			r->ru_nvcsw = p->signal->cnvcsw;
			r->ru_nivcsw = p->signal->cnivcsw;
			r->ru_minflt = p->signal->cmin_flt;
			r->ru_majflt = p->signal->cmaj_flt;
			r->ru_inblock = p->signal->cinblock;
			r->ru_oublock = p->signal->coublock;
			if (who == RUSAGE_CHILDREN)
				break;
		case RUSAGE_SELF:
			utime = cputime_add(utime, p->signal->utime);
			stime = cputime_add(stime, p->signal->stime);
			r->ru_nvcsw += p->signal->nvcsw;
			r->ru_nivcsw += p->signal->nivcsw;
			r->ru_minflt += p->signal->min_flt;
			r->ru_majflt += p->signal->maj_flt;
			r->ru_inblock += p->signal->inblock;
			r->ru_oublock += p->signal->oublock;
			t = p;
			do {
				utime = cputime_add(utime, t->utime);
				stime = cputime_add(stime, t->stime);
				r->ru_nvcsw += t->nvcsw;
				r->ru_nivcsw += t->nivcsw;
				r->ru_minflt += t->min_flt;
				r->ru_majflt += t->maj_flt;
				r->ru_inblock += task_io_get_inblock(t);
				r->ru_oublock += task_io_get_oublock(t);
				t = next_thread(t);
			} while (t != p);
			break;
		default:
			BUG();
	}
	unlock_task_sighand(p, &flags);
	rcu_read_unlock();
	cputime_to_timeval(utime, &r->ru_utime);
	cputime_to_timeval(stime, &r->ru_stime);
}
static void k_getrusage ( struct task_struct * p , int who , struct rusage * r ) { struct task_struct * t ; unsigned long flags ; cputime_t utime , stime ; memset ( ( char * ) r , 0 , sizeof * r ) ; utime = stime = cputime_zero ; rcu_read_lock ( ) ; if ( ! lock_task_sighand ( p , & flags ) ) { rcu_read_unlock ( ) ; return ; } switch ( who ) { case RUSAGE_BOTH : case RUSAGE_CHILDREN : utime = p -> signal -> cutime ; stime = p -> signal -> cstime ; r -> ru_nvcsw = p -> signal -> cnvcsw ; r -> ru_nivcsw = p -> signal -> cnivcsw ; r -> ru_minflt = p -> signal -> cmin_flt ; r -> ru_majflt = p -> signal -> cmaj_flt ; r -> ru_inblock = p -> signal -> cinblock ; r -> ru_oublock = p -> signal -> coublock ; if ( who == RUSAGE_CHILDREN ) break ; case RUSAGE_SELF : utime = cputime_add ( utime , p -> signal -> utime ) ; stime = cputime_add ( stime , p -> signal -> stime ) ; r -> ru_nvcsw += p -> signal -> nvcsw ; r -> ru_nivcsw += p -> signal -> nivcsw ; r -> ru_minflt += p -> signal -> min_flt ; r -> ru_majflt += p -> signal -> maj_flt ; r -> ru_inblock += p -> signal -> inblock ; r -> ru_oublock += p -> signal -> oublock ; t = p ; do { utime = cputime_add ( utime , t -> utime ) ; stime = cputime_add ( stime , t -> stime ) ; r -> ru_nvcsw += t -> nvcsw ; r -> ru_nivcsw += t -> nivcsw ; r -> ru_minflt += t -> min_flt ; r -> ru_majflt += t -> maj_flt ; r -> ru_inblock += task_io_get_inblock ( t ) ; r -> ru_oublock += task_io_get_oublock ( t ) ; t = next_thread ( t ) ; } while ( t != p ) ; break ; default : BUG ( ) ; } unlock_task_sighand ( p , & flags ) ; rcu_read_unlock ( ) ; cputime_to_timeval ( utime , & r -> ru_utime ) ; cputime_to_timeval ( stime , & r -> ru_stime ) ; }
It would make sense to put struct rusage in the task_struct,
 except that would make the task_struct be *really big*.
It would make sense to put struct rusage in the task_struct except that would make the task_struct be * really big * .