From: Michael Holzheu If a non-leader thread calls exec(), in the de_thread() function it gets some of the identity of the old thread group leader e.g. the PID and the start time. But it keeps the old CPU times. This may lead to confusion in user space, because CPU time can go backwards for the thread group leader. For example the top command shows the following for that test case: # top -H PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 17278 root 20 0 84128 664 500 R >>9999.0<< 0.0 0:02.75 pthread_exec To fix this problem, this patch exchanges the accounting data between the exec() calling thread an the thread group leader in de_thread(). One problem with this patch could be that the scheduler might get confused by the CPU time change. Signed-off-by: Michael Holzheu --- fs/exec.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) --- a/fs/exec.c +++ b/fs/exec.c @@ -844,16 +844,32 @@ static int de_thread(struct task_struct /* * The only record we have of the real-time age of a - * process, regardless of execs it's done, is start_time. + * process, regardless of execs it's done, is start_time + * and the accounting data. * All the past CPU time is accumulated in signal_struct * from sister threads now dead. But in this non-leader * exec, nothing survives from the original leader thread, * whose birth marks the true age of this process now. * When we take on its identity by switching to its PID, we - * also take its birthdate (always earlier than our own). + * also take its birthdate (always earlier than our own) + * and the accounting data. */ tsk->start_time = leader->start_time; - + swap(tsk->nvcsw, leader->nvcsw); + swap(tsk->nivcsw, leader->nivcsw); + swap(tsk->min_flt, leader->min_flt); + swap(tsk->ioac, leader->ioac); + swap(tsk->utime, leader->utime); + swap(tsk->stime, leader->stime); + swap(tsk->gtime, leader->gtime); + swap(tsk->sttime, leader->sttime); + swap(tsk->acct_time, leader->acct_time); + swap(tsk->real_start_time, leader->real_start_time); +#ifndef CONFIG_VIRT_CPU_ACCOUNTING + swap(tsk->prev_utime, leader->prev_utime); + swap(tsk->prev_stime, leader->prev_stime); + swap(tsk->prev_sttime, leader->prev_sttime); +#endif BUG_ON(!same_thread_group(leader, tsk)); BUG_ON(has_group_leader_pid(tsk)); /*