diff options
| author | Junjie Wu <junjiew@codeaurora.org> | 2016-01-05 10:53:30 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:25:17 -0700 |
| commit | efa673322fd6917acb69361fc01f746a13b3fcde (patch) | |
| tree | 870145507079abe1e9ffba81314888533c2b7745 /kernel | |
| parent | 71a8c392b7f024f8e1ce08ec1401c321f7323cb3 (diff) | |
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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sched/core.c | 36 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 1 |
2 files changed, 32 insertions, 5 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 76e265ad1abf..01837c230d4d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -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); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c30c12097d02..0e55971e3e96 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -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 |
