aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunjie Wu <junjiew@codeaurora.org>2016-01-05 10:53:30 -0800
committerArvin Quilao <arquilao@gmail.com>2017-03-16 05:39:43 +0000
commit5b7d255bb491272f1967fcf57a94d573b3bf47ac (patch)
tree4641655cbc292b0f733e00bddf6a3240edcedb4e
parent4590668c49ea3396128af7defbd580148cf0528d (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.h1
-rw-r--r--kernel/sched/core.c36
-rw-r--r--kernel/sched/sched.h1
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)
{