Skip to content

Commit f2469a1

Browse files
KAGA-KOKOPeter Zijlstra
authored andcommitted
sched/core: Wait for tasks being pushed away on hotplug
RT kernels need to ensure that all tasks which are not per CPU kthreads have left the outgoing CPU to guarantee that no tasks are force migrated within a migrate disabled section. There is also some desire to (ab)use fine grained CPU hotplug control to clear a CPU from active state to force migrate tasks which are not per CPU kthreads away for power control purposes. Add a mechanism which waits until all tasks which should leave the CPU after the CPU active flag is cleared have moved to a different online CPU. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Valentin Schneider <[email protected]> Reviewed-by: Daniel Bristot de Oliveira <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 2558aac commit f2469a1

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

kernel/sched/core.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6896,8 +6896,21 @@ static void balance_push(struct rq *rq)
68966896
* Both the cpu-hotplug and stop task are in this case and are
68976897
* required to complete the hotplug process.
68986898
*/
6899-
if (is_per_cpu_kthread(push_task))
6899+
if (is_per_cpu_kthread(push_task)) {
6900+
/*
6901+
* If this is the idle task on the outgoing CPU try to wake
6902+
* up the hotplug control thread which might wait for the
6903+
* last task to vanish. The rcuwait_active() check is
6904+
* accurate here because the waiter is pinned on this CPU
6905+
* and can't obviously be running in parallel.
6906+
*/
6907+
if (!rq->nr_running && rcuwait_active(&rq->hotplug_wait)) {
6908+
raw_spin_unlock(&rq->lock);
6909+
rcuwait_wake_up(&rq->hotplug_wait);
6910+
raw_spin_lock(&rq->lock);
6911+
}
69006912
return;
6913+
}
69016914

69026915
get_task_struct(push_task);
69036916
/*
@@ -6928,6 +6941,20 @@ static void balance_push_set(int cpu, bool on)
69286941
rq_unlock_irqrestore(rq, &rf);
69296942
}
69306943

6944+
/*
6945+
* Invoked from a CPUs hotplug control thread after the CPU has been marked
6946+
* inactive. All tasks which are not per CPU kernel threads are either
6947+
* pushed off this CPU now via balance_push() or placed on a different CPU
6948+
* during wakeup. Wait until the CPU is quiescent.
6949+
*/
6950+
static void balance_hotplug_wait(void)
6951+
{
6952+
struct rq *rq = this_rq();
6953+
6954+
rcuwait_wait_event(&rq->hotplug_wait, rq->nr_running == 1,
6955+
TASK_UNINTERRUPTIBLE);
6956+
}
6957+
69316958
#else
69326959

69336960
static inline void balance_push(struct rq *rq)
@@ -6938,6 +6965,10 @@ static inline void balance_push_set(int cpu, bool on)
69386965
{
69396966
}
69406967

6968+
static inline void balance_hotplug_wait(void)
6969+
{
6970+
}
6971+
69416972
#endif /* CONFIG_HOTPLUG_CPU */
69426973

69436974
void set_rq_online(struct rq *rq)
@@ -7092,6 +7123,10 @@ int sched_cpu_deactivate(unsigned int cpu)
70927123
return ret;
70937124
}
70947125
sched_domains_numa_masks_clear(cpu);
7126+
7127+
/* Wait for all non per CPU kernel threads to vanish. */
7128+
balance_hotplug_wait();
7129+
70957130
return 0;
70967131
}
70977132

@@ -7332,6 +7367,9 @@ void __init sched_init(void)
73327367

73337368
rq_csd_init(rq, &rq->nohz_csd, nohz_csd_func);
73347369
#endif
7370+
#ifdef CONFIG_HOTPLUG_CPU
7371+
rcuwait_init(&rq->hotplug_wait);
7372+
#endif
73357373
#endif /* CONFIG_SMP */
73367374
hrtick_rq_init(rq);
73377375
atomic_set(&rq->nr_iowait, 0);

kernel/sched/sched.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,10 @@ struct rq {
10041004

10051005
/* This is used to determine avg_idle's max value */
10061006
u64 max_idle_balance_cost;
1007+
1008+
#ifdef CONFIG_HOTPLUG_CPU
1009+
struct rcuwait hotplug_wait;
1010+
#endif
10071011
#endif /* CONFIG_SMP */
10081012

10091013
#ifdef CONFIG_IRQ_TIME_ACCOUNTING

0 commit comments

Comments
 (0)