Skip to content

Commit

Permalink
timers: fix itimer/many thread hang, v2
Browse files Browse the repository at this point in the history
This is the second resubmission of the posix timer rework patch, posted
a few days ago.

This includes the changes from the previous resubmittion, which addressed
Oleg Nesterov's comments, removing the RCU stuff from the patch and
un-inlining the thread_group_cputime() function for SMP.

In addition, per Ingo Molnar it simplifies the UP code, consolidating much
of it with the SMP version and depending on lower-level SMP/UP handling to
take care of the differences.

It also cleans up some UP compile errors, moves the scheduler stats-related
macros into kernel/sched_stats.h, cleans up a merge error in
kernel/fork.c and has a few other minor fixes and cleanups as suggested
by Oleg and Ingo. Thanks for the review, guys.

Signed-off-by: Frank Mayhar <fmayhar@google.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Frank Mayhar authored and Ingo Molnar committed Sep 23, 2008
1 parent 5ce73a4 commit bb34d92
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 311 deletions.
1 change: 1 addition & 0 deletions include/linux/kernel_stat.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ static inline int kstat_irqs(int irq)
return sum;
}

extern unsigned long long task_delta_exec(struct task_struct *);
extern void account_user_time(struct task_struct *, cputime_t);
extern void account_user_time_scaled(struct task_struct *, cputime_t);
extern void account_system_time(struct task_struct *, int, cputime_t);
Expand Down
183 changes: 5 additions & 178 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,15 +454,9 @@ struct task_cputime {
* This structure contains the version of task_cputime, above, that is
* used for thread group CPU clock calculations.
*/
#ifdef CONFIG_SMP
struct thread_group_cputime {
struct task_cputime *totals;
};
#else
struct thread_group_cputime {
struct task_cputime totals;
};
#endif

/*
* NOTE! "signal_struct" does not have it's own
Expand Down Expand Up @@ -2124,193 +2118,26 @@ static inline int spin_needbreak(spinlock_t *lock)
/*
* Thread group CPU time accounting.
*/
#ifdef CONFIG_SMP

extern int thread_group_cputime_alloc_smp(struct task_struct *);
extern void thread_group_cputime_smp(struct task_struct *, struct task_cputime *);
extern int thread_group_cputime_alloc(struct task_struct *);
extern void thread_group_cputime(struct task_struct *, struct task_cputime *);

static inline void thread_group_cputime_init(struct signal_struct *sig)
{
sig->cputime.totals = NULL;
}

static inline int thread_group_cputime_clone_thread(struct task_struct *curr,
struct task_struct *new)
static inline int thread_group_cputime_clone_thread(struct task_struct *curr)
{
if (curr->signal->cputime.totals)
return 0;
return thread_group_cputime_alloc_smp(curr);
return thread_group_cputime_alloc(curr);
}

static inline void thread_group_cputime_free(struct signal_struct *sig)
{
free_percpu(sig->cputime.totals);
}

/**
* thread_group_cputime - Sum the thread group time fields across all CPUs.
*
* This is a wrapper for the real routine, thread_group_cputime_smp(). See
* that routine for details.
*/
static inline void thread_group_cputime(
struct task_struct *tsk,
struct task_cputime *times)
{
thread_group_cputime_smp(tsk, times);
}

/**
* thread_group_cputime_account_user - Maintain utime for a thread group.
*
* @tgtimes: Pointer to thread_group_cputime structure.
* @cputime: Time value by which to increment the utime field of that
* structure.
*
* If thread group time is being maintained, get the structure for the
* running CPU and update the utime field there.
*/
static inline void thread_group_cputime_account_user(
struct thread_group_cputime *tgtimes,
cputime_t cputime)
{
if (tgtimes->totals) {
struct task_cputime *times;

times = per_cpu_ptr(tgtimes->totals, get_cpu());
times->utime = cputime_add(times->utime, cputime);
put_cpu_no_resched();
}
}

/**
* thread_group_cputime_account_system - Maintain stime for a thread group.
*
* @tgtimes: Pointer to thread_group_cputime structure.
* @cputime: Time value by which to increment the stime field of that
* structure.
*
* If thread group time is being maintained, get the structure for the
* running CPU and update the stime field there.
*/
static inline void thread_group_cputime_account_system(
struct thread_group_cputime *tgtimes,
cputime_t cputime)
{
if (tgtimes->totals) {
struct task_cputime *times;

times = per_cpu_ptr(tgtimes->totals, get_cpu());
times->stime = cputime_add(times->stime, cputime);
put_cpu_no_resched();
}
}

/**
* thread_group_cputime_account_exec_runtime - Maintain exec runtime for a
* thread group.
*
* @tgtimes: Pointer to thread_group_cputime structure.
* @ns: Time value by which to increment the sum_exec_runtime field
* of that structure.
*
* If thread group time is being maintained, get the structure for the
* running CPU and update the sum_exec_runtime field there.
*/
static inline void thread_group_cputime_account_exec_runtime(
struct thread_group_cputime *tgtimes,
unsigned long long ns)
{
if (tgtimes->totals) {
struct task_cputime *times;

times = per_cpu_ptr(tgtimes->totals, get_cpu());
times->sum_exec_runtime += ns;
put_cpu_no_resched();
}
}

#else /* CONFIG_SMP */

static inline void thread_group_cputime_init(struct signal_struct *sig)
{
sig->cputime.totals.utime = cputime_zero;
sig->cputime.totals.stime = cputime_zero;
sig->cputime.totals.sum_exec_runtime = 0;
}

static inline int thread_group_cputime_alloc(struct task_struct *tsk)
{
return 0;
}

static inline void thread_group_cputime_free(struct signal_struct *sig)
{
}

static inline int thread_group_cputime_clone_thread(struct task_struct *curr,
struct task_struct *tsk)
{
return 0;
}

static inline void thread_group_cputime(struct task_struct *tsk,
struct task_cputime *cputime)
{
*cputime = tsk->signal->cputime.totals;
}

static inline void thread_group_cputime_account_user(
struct thread_group_cputime *tgtimes,
cputime_t cputime)
{
tgtimes->totals.utime = cputime_add(tgtimes->totals.utime, cputime);
}

static inline void thread_group_cputime_account_system(
struct thread_group_cputime *tgtimes,
cputime_t cputime)
{
tgtimes->totals.stime = cputime_add(tgtimes->totals.stime, cputime);
}

static inline void thread_group_cputime_account_exec_runtime(
struct thread_group_cputime *tgtimes,
unsigned long long ns)
{
tgtimes->totals.sum_exec_runtime += ns;
}

#endif /* CONFIG_SMP */

static inline void account_group_user_time(struct task_struct *tsk,
cputime_t cputime)
{
struct signal_struct *sig;

sig = tsk->signal;
if (likely(sig))
thread_group_cputime_account_user(&sig->cputime, cputime);
}

static inline void account_group_system_time(struct task_struct *tsk,
cputime_t cputime)
{
struct signal_struct *sig;

sig = tsk->signal;
if (likely(sig))
thread_group_cputime_account_system(&sig->cputime, cputime);
}

static inline void account_group_exec_runtime(struct task_struct *tsk,
unsigned long long ns)
{
struct signal_struct *sig;

sig = tsk->signal;
if (likely(sig))
thread_group_cputime_account_exec_runtime(&sig->cputime, ns);
free_percpu(sig->cputime.totals);
}

/*
Expand Down
5 changes: 1 addition & 4 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
int ret;

if (clone_flags & CLONE_THREAD) {
ret = thread_group_cputime_clone_thread(current, tsk);
ret = thread_group_cputime_clone_thread(current);
if (likely(!ret)) {
atomic_inc(&current->signal->count);
atomic_inc(&current->signal->live);
Expand Down Expand Up @@ -834,9 +834,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
task_io_accounting_init(&sig->ioac);
INIT_LIST_HEAD(&sig->cpu_timers[0]);
INIT_LIST_HEAD(&sig->cpu_timers[1]);
INIT_LIST_HEAD(&sig->cpu_timers[2]);
taskstats_tgid_init(sig);

task_lock(current->group_leader);
Expand Down
Loading

0 comments on commit bb34d92

Please sign in to comment.