timers: fix itimer/many thread hang, v2
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>
This commit is contained in:
committed by
Ingo Molnar
parent
5ce73a4a5a
commit
bb34d92f64
@ -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
|
||||
@ -2124,195 +2118,28 @@ 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reevaluate whether the task has signals pending delivery.
|
||||
* Wake the task if so.
|
||||
|
Reference in New Issue
Block a user