mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
[PATCH] avoid tasklist_lock at getrusage for multithreaded case too
Avoid taking tasklist_lock for at getrusage for the multithreaded case too. We don't need to take the tasklist lock for thread traversal of a process since Oleg's do-__unhash_process-under-siglock.patch and related work. Signed-off-by: Ravikiran Thirumalai <kiran@scalex86.org> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
c89681ed7d
commit
de047c1bcd
1 changed files with 22 additions and 34 deletions
56
kernel/sys.c
56
kernel/sys.c
|
@ -1860,23 +1860,20 @@ out:
|
||||||
* fields when reaping, so a sample either gets all the additions of a
|
* 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.
|
* given child after it's reaped, or none so this sample is before reaping.
|
||||||
*
|
*
|
||||||
* tasklist_lock locking optimisation:
|
* Locking:
|
||||||
* If we are current and single threaded, we do not need to take the tasklist
|
* We need to take the siglock for CHILDEREN, SELF and BOTH
|
||||||
* lock or the siglock. No one else can take our signal_struct away,
|
* for the cases current multithreaded, non-current single threaded
|
||||||
* no one else can reap the children to update signal->c* counters, and
|
* non-current multithreaded. Thread traversal is now safe with
|
||||||
* no one else can race with the signal-> fields.
|
* the siglock held.
|
||||||
* If we do not take the tasklist_lock, the signal-> fields could be read
|
* Strictly speaking, we donot need to take the siglock if we are current and
|
||||||
* out of order while another thread was just exiting. So we place a
|
* single threaded, as no one else can take our signal_struct away, no one
|
||||||
* read memory barrier when we avoid the lock. On the writer side,
|
* else can reap the children to update signal->c* counters, and no one else
|
||||||
* write memory barrier is implied in __exit_signal as __exit_signal releases
|
* can race with the signal-> fields. If we do not take any lock, the
|
||||||
* the siglock spinlock after updating the signal-> fields.
|
* 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.
|
||||||
* We don't really need the siglock when we access the non c* fields
|
* On the writer side, write memory barrier is implied in __exit_signal
|
||||||
* of the signal_struct (for RUSAGE_SELF) even in multithreaded
|
* as __exit_signal releases the siglock spinlock after updating the signal->
|
||||||
* case, since we take the tasklist lock for read and the non c* signal->
|
* fields. But we don't do this yet to keep things simple.
|
||||||
* fields are updated only in __exit_signal, which is called with
|
|
||||||
* tasklist_lock taken for write, hence these two threads cannot execute
|
|
||||||
* concurrently.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1885,35 +1882,25 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
|
||||||
struct task_struct *t;
|
struct task_struct *t;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
cputime_t utime, stime;
|
cputime_t utime, stime;
|
||||||
int need_lock = 0;
|
|
||||||
|
|
||||||
memset((char *) r, 0, sizeof *r);
|
memset((char *) r, 0, sizeof *r);
|
||||||
utime = stime = cputime_zero;
|
utime = stime = cputime_zero;
|
||||||
|
|
||||||
if (p != current || !thread_group_empty(p))
|
rcu_read_lock();
|
||||||
need_lock = 1;
|
if (!lock_task_sighand(p, &flags)) {
|
||||||
|
rcu_read_unlock();
|
||||||
if (need_lock) {
|
return;
|
||||||
read_lock(&tasklist_lock);
|
}
|
||||||
if (unlikely(!p->signal)) {
|
|
||||||
read_unlock(&tasklist_lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
/* See locking comments above */
|
|
||||||
smp_rmb();
|
|
||||||
|
|
||||||
switch (who) {
|
switch (who) {
|
||||||
case RUSAGE_BOTH:
|
case RUSAGE_BOTH:
|
||||||
case RUSAGE_CHILDREN:
|
case RUSAGE_CHILDREN:
|
||||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
|
||||||
utime = p->signal->cutime;
|
utime = p->signal->cutime;
|
||||||
stime = p->signal->cstime;
|
stime = p->signal->cstime;
|
||||||
r->ru_nvcsw = p->signal->cnvcsw;
|
r->ru_nvcsw = p->signal->cnvcsw;
|
||||||
r->ru_nivcsw = p->signal->cnivcsw;
|
r->ru_nivcsw = p->signal->cnivcsw;
|
||||||
r->ru_minflt = p->signal->cmin_flt;
|
r->ru_minflt = p->signal->cmin_flt;
|
||||||
r->ru_majflt = p->signal->cmaj_flt;
|
r->ru_majflt = p->signal->cmaj_flt;
|
||||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
|
||||||
|
|
||||||
if (who == RUSAGE_CHILDREN)
|
if (who == RUSAGE_CHILDREN)
|
||||||
break;
|
break;
|
||||||
|
@ -1941,8 +1928,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_lock)
|
unlock_task_sighand(p, &flags);
|
||||||
read_unlock(&tasklist_lock);
|
rcu_read_unlock();
|
||||||
|
|
||||||
cputime_to_timeval(utime, &r->ru_utime);
|
cputime_to_timeval(utime, &r->ru_utime);
|
||||||
cputime_to_timeval(stime, &r->ru_stime);
|
cputime_to_timeval(stime, &r->ru_stime);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue