Commit dd8e157f authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] acct: report single record for multithreaded process

This patch changes process accounting to write just one record for a
process with many NPTL threads, rather than one record for each thread.  No
record is written until the last thread exits.  The process's record shows
the cumulative time of all the threads that ever lived in that process
(thread group).  This seems like the clearly right thing and I assume it is
what anyone using process accounting really would like to see.

There is a race condition between multiple threads exiting at the same time
to decide which one should write the accounting record.  I couldn't think
of anything clever using existing bookkeeping that would get this right, so
I added another counter for this.  (There may be some potential to clean up
existing places that figure out how many non-zombie threads are in the
group, now that this count is available.)
Signed-off-by: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent af8b3bb2
......@@ -267,6 +267,7 @@ struct sighand_struct {
*/
struct signal_struct {
atomic_t count;
atomic_t live;
/* current thread group signal load-balancing target: */
task_t *curr_target;
......
......@@ -427,8 +427,12 @@ static void do_acct_process(long exitcode, struct file *file)
#endif
do_div(elapsed, AHZ);
ac.ac_btime = xtime.tv_sec - elapsed;
ac.ac_utime = encode_comp_t(jiffies_to_AHZ(current->utime));
ac.ac_stime = encode_comp_t(jiffies_to_AHZ(current->stime));
ac.ac_utime = encode_comp_t(jiffies_to_AHZ(
current->signal->utime +
current->group_leader->utime));
ac.ac_stime = encode_comp_t(jiffies_to_AHZ(
current->signal->stime +
current->group_leader->stime));
/* we really need to bite the bullet and change layout */
ac.ac_uid = current->uid;
ac.ac_gid = current->gid;
......@@ -441,8 +445,8 @@ static void do_acct_process(long exitcode, struct file *file)
ac.ac_gid16 = current->gid;
#endif
#if ACCT_VERSION==3
ac.ac_pid = current->pid;
ac.ac_ppid = current->parent->pid;
ac.ac_pid = current->tgid;
ac.ac_ppid = current->parent->tgid;
#endif
read_lock(&tasklist_lock); /* pin current->signal */
......@@ -475,8 +479,10 @@ static void do_acct_process(long exitcode, struct file *file)
ac.ac_mem = encode_comp_t(vsize);
ac.ac_io = encode_comp_t(0 /* current->io_usage */); /* %% */
ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
ac.ac_minflt = encode_comp_t(current->min_flt);
ac.ac_majflt = encode_comp_t(current->maj_flt);
ac.ac_minflt = encode_comp_t(current->signal->min_flt +
current->group_leader->min_flt);
ac.ac_majflt = encode_comp_t(current->signal->maj_flt +
current->group_leader->maj_flt);
ac.ac_swaps = encode_comp_t(0);
ac.ac_exitcode = exitcode;
......
......@@ -807,7 +807,8 @@ asmlinkage NORET_TYPE void do_exit(long code)
ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP);
}
acct_process(code);
if (atomic_dec_and_test(&tsk->signal->live))
acct_process(code);
__exit_mm(tsk);
exit_sem(tsk);
......
......@@ -718,6 +718,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
if (clone_flags & CLONE_THREAD) {
atomic_inc(&current->signal->count);
atomic_inc(&current->signal->live);
return 0;
}
sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
......@@ -725,6 +726,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
if (!sig)
return -ENOMEM;
atomic_set(&sig->count, 1);
atomic_set(&sig->live, 1);
sig->group_exit = 0;
sig->group_exit_code = 0;
sig->group_exit_task = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment