diff options
| author | Junjie Wu <junjiew@codeaurora.org> | 2016-01-05 10:53:30 -0800 |
|---|---|---|
| committer | Arvin Quilao <arquilao@gmail.com> | 2017-03-16 05:39:43 +0000 |
| commit | 5b7d255bb491272f1967fcf57a94d573b3bf47ac (patch) | |
| tree | 4641655cbc292b0f733e00bddf6a3240edcedb4e | |
| parent | 4590668c49ea3396128af7defbd580148cf0528d (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>
| -rw-r--r-- | include/linux/sched.h | 1 | ||||
| -rw-r--r-- | kernel/sched/core.c | 36 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 1 |
3 files changed, 33 insertions, 5 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 87c885874e1..1b6a35f5bea 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2155,6 +2155,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); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index cbb76fd0593..6157fde6503 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3062,6 +3062,9 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) struct rq *rq; u64 wallclock; #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 @@ -3146,11 +3149,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; } @@ -3218,6 +3224,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 7a4633ca1c4..1800c427dd9 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1133,6 +1133,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 */ static inline void update_load_add(struct load_weight *lw, unsigned long inc) { |
