sched: Provide a wake up API without sending freq notifications

Each time a task wakes up, scheduler evaluates its load and notifies
governor if the resulting frequency of destination CPU is larger than
a threshold. However, some governor wakes up a separate task that
handles frequency change, which again calls wake_up_process().

This is dangerous because if the task being woken up meets the
threshold and ends up being moved around, there is a potential for
endless recursive notifications.

Introduce a new API for waking up a task without triggering
frequency notification.

Change-Id: I24261af81b7dc410c7fb01eaa90920b8d66fbd2a
Signed-off-by: Junjie Wu <junjiew@codeaurora.org>
This commit is contained in:
Junjie Wu 2016-01-05 10:53:30 -08:00 committed by David Keitel
parent 71a8c392b7
commit efa673322f
3 changed files with 33 additions and 5 deletions

View file

@ -2596,6 +2596,7 @@ extern void xtime_update(unsigned long ticks);
extern int wake_up_state(struct task_struct *tsk, unsigned int state);
extern int wake_up_process(struct task_struct *tsk);
extern int wake_up_process_no_notif(struct task_struct *tsk);
extern void wake_up_new_task(struct task_struct *tsk);
#ifdef CONFIG_SMP
extern void kick_process(struct task_struct *tsk);

View file

@ -4360,6 +4360,9 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
u64 wallclock;
struct related_thread_group *grp = NULL;
#endif
bool freq_notif_allowed = !(wake_flags & WF_NO_NOTIFIER);
wake_flags &= ~WF_NO_NOTIFIER;
/*
* If we are going to wake up a thread waiting for CONDITION we
@ -4477,11 +4480,14 @@ out:
atomic_notifier_call_chain(&migration_notifier_head,
0, (void *)&mnd);
if (!same_freq_domain(src_cpu, cpu)) {
check_for_freq_change(cpu_rq(cpu));
check_for_freq_change(cpu_rq(src_cpu));
} else if (heavy_task)
check_for_freq_change(cpu_rq(cpu));
if (freq_notif_allowed) {
if (!same_freq_domain(src_cpu, cpu)) {
check_for_freq_change(cpu_rq(cpu));
check_for_freq_change(cpu_rq(src_cpu));
} else if (heavy_task) {
check_for_freq_change(cpu_rq(cpu));
}
}
return success;
}
@ -4561,6 +4567,26 @@ int wake_up_process(struct task_struct *p)
}
EXPORT_SYMBOL(wake_up_process);
/**
* wake_up_process_no_notif - Wake up a specific process without notifying
* governor
* @p: The process to be woken up.
*
* Attempt to wake up the nominated process and move it to the set of runnable
* processes.
*
* Return: 1 if the process was woken up, 0 if it was already running.
*
* It may be assumed that this function implies a write memory barrier before
* changing the task state if and only if any tasks are woken up.
*/
int wake_up_process_no_notif(struct task_struct *p)
{
WARN_ON(task_is_stopped_or_traced(p));
return try_to_wake_up(p, TASK_NORMAL, WF_NO_NOTIFIER);
}
EXPORT_SYMBOL(wake_up_process_no_notif);
int wake_up_state(struct task_struct *p, unsigned int state)
{
return try_to_wake_up(p, state, 0);

View file

@ -1596,6 +1596,7 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
#define WF_SYNC 0x01 /* waker goes to sleep after wakeup */
#define WF_FORK 0x02 /* child wakeup after fork */
#define WF_MIGRATED 0x4 /* internal use, task got migrated */
#define WF_NO_NOTIFIER 0x08 /* do not notify governor */
/*
* To aid in avoiding the subversion of "niceness" due to uneven distribution