summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2010-07-20 14:30:57 +0200
committerThomas Gleixner <tglx@linutronix.de>2010-07-20 19:11:56 +0200
commit8e7dbdf187d6a6896873a32537fed62111a5910e (patch)
tree0d104ad7adec643295e991328918e25fbedb5cf1
parent5706af4a7052a5048f3e4a2cbc65ee66c71bdfa8 (diff)
downloadlwn-8e7dbdf187d6a6896873a32537fed62111a5910e.tar.gz
lwn-8e7dbdf187d6a6896873a32537fed62111a5910e.zip
cpu-hotplug: Don't wake up the desched thread from idle_task_exit()
When idle tasks exits then we do not want to wake the cpu bound desched thread. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/sched.h6
-rw-r--r--kernel/fork.c23
-rw-r--r--kernel/sched.c4
3 files changed, 19 insertions, 14 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 82d06e3ed04b..4610e2c769a3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2290,7 +2290,7 @@ extern struct mm_struct * mm_alloc(void);
/* mmdrop drops the mm and the page tables */
extern void __mmdrop(struct mm_struct *);
-extern void __mmdrop_delayed(struct mm_struct *);
+extern void __mmdrop_delayed(struct mm_struct *, int wake);
static inline void mmdrop(struct mm_struct * mm)
{
@@ -2298,10 +2298,10 @@ static inline void mmdrop(struct mm_struct * mm)
__mmdrop(mm);
}
-static inline void mmdrop_delayed(struct mm_struct * mm)
+static inline void mmdrop_delayed(struct mm_struct * mm, int wake)
{
if (atomic_dec_and_test(&mm->mm_count))
- __mmdrop_delayed(mm);
+ __mmdrop_delayed(mm, wake);
}
/* mmput gets rid of the mappings and all user-space */
diff --git a/kernel/fork.c b/kernel/fork.c
index ebe00bafe70e..1d4acdf6d708 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1803,24 +1803,26 @@ int unshare_files(struct files_struct **displaced)
return 0;
}
-static int mmdrop_complete(void)
+static int mmdrop_complete(int cpu)
{
struct list_head *head;
int ret = 0;
- head = &get_cpu_var(delayed_drop_list);
+ preempt_disable();
+ head = &per_cpu(delayed_drop_list, cpu);
while (!list_empty(head)) {
struct mm_struct *mm = list_entry(head->next,
struct mm_struct, delayed_drop);
list_del(&mm->delayed_drop);
- put_cpu_var(delayed_drop_list);
+ preempt_enable();
__mmdrop(mm);
ret = 1;
- head = &get_cpu_var(delayed_drop_list);
+ preempt_disable();
+ head = &per_cpu(delayed_drop_list, cpu);
}
- put_cpu_var(delayed_drop_list);
+ preempt_enable();
return ret;
}
@@ -1829,7 +1831,7 @@ static int mmdrop_complete(void)
* We dont want to do complex work from the scheduler, thus
* we delay the work to a per-CPU worker thread:
*/
-void __mmdrop_delayed(struct mm_struct *mm)
+void __mmdrop_delayed(struct mm_struct *mm, int wake)
{
struct task_struct *desched_task;
struct list_head *head;
@@ -1837,7 +1839,7 @@ void __mmdrop_delayed(struct mm_struct *mm)
head = &get_cpu_var(delayed_drop_list);
list_add_tail(&mm->delayed_drop, head);
desched_task = __get_cpu_var(desched_task);
- if (desched_task)
+ if (desched_task && wake)
wake_up_process(desched_task);
put_cpu_var(delayed_drop_list);
}
@@ -1852,13 +1854,16 @@ static void takeover_delayed_drop(int hotcpu)
struct mm_struct, delayed_drop);
list_del(&mm->delayed_drop);
- __mmdrop_delayed(mm);
+ __mmdrop_delayed(mm, 1);
}
}
#endif
static int desched_thread(void * __bind_cpu)
{
+
+ int cpu = (unsigned long)__bind_cpu;
+
set_user_nice(current, -10);
current->flags |= PF_NOFREEZE;
current->extra_flags |= PFE_SOFTIRQ;
@@ -1867,7 +1872,7 @@ static int desched_thread(void * __bind_cpu)
while (!kthread_should_stop()) {
- if (mmdrop_complete())
+ if (mmdrop_complete(cpu))
continue;
schedule();
diff --git a/kernel/sched.c b/kernel/sched.c
index bbc181fee05d..056167771b9c 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2939,7 +2939,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
* to do complex work from within the scheduler:
*/
if (mm)
- mmdrop_delayed(mm);
+ mmdrop_delayed(mm, 1);
if (unlikely(prev_state == TASK_DEAD)) {
/*
* Remove function-return probe instances associated with this
@@ -7814,7 +7814,7 @@ void idle_task_exit(void)
if (mm != &init_mm)
switch_mm(mm, &init_mm, current);
#ifdef CONFIG_PREEMPT_RT
- mmdrop_delayed(mm);
+ mmdrop_delayed(mm, 0);
#else
mmdrop(mm);
#endif