11367 lines · 288.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  kernel/sched/core.c * *  Core kernel scheduler code and related syscalls * *  Copyright (C) 1991-2002  Linus Torvalds */#include <linux/highmem.h>#include <linux/hrtimer_api.h>#include <linux/ktime_api.h>#include <linux/sched/signal.h>#include <linux/syscalls_api.h>#include <linux/debug_locks.h>#include <linux/prefetch.h>#include <linux/capability.h>#include <linux/pgtable_api.h>#include <linux/wait_bit.h>#include <linux/jiffies.h>#include <linux/spinlock_api.h>#include <linux/cpumask_api.h>#include <linux/lockdep_api.h>#include <linux/hardirq.h>#include <linux/softirq.h>#include <linux/refcount_api.h>#include <linux/topology.h>#include <linux/sched/clock.h>#include <linux/sched/cond_resched.h>#include <linux/sched/cputime.h>#include <linux/sched/debug.h>#include <linux/sched/hotplug.h>#include <linux/sched/init.h>#include <linux/sched/isolation.h>#include <linux/sched/loadavg.h>#include <linux/sched/mm.h>#include <linux/sched/nohz.h>#include <linux/sched/rseq_api.h>#include <linux/sched/rt.h> #include <linux/blkdev.h>#include <linux/context_tracking.h>#include <linux/cpuset.h>#include <linux/delayacct.h>#include <linux/init_task.h>#include <linux/interrupt.h>#include <linux/ioprio.h>#include <linux/kallsyms.h>#include <linux/kcov.h>#include <linux/kprobes.h>#include <linux/llist_api.h>#include <linux/mmu_context.h>#include <linux/mmzone.h>#include <linux/mutex_api.h>#include <linux/nmi.h>#include <linux/nospec.h>#include <linux/perf_event_api.h>#include <linux/profile.h>#include <linux/psi.h>#include <linux/rcuwait_api.h>#include <linux/sched/wake_q.h>#include <linux/scs.h>#include <linux/slab.h>#include <linux/syscalls.h>#include <linux/vtime.h>#include <linux/wait_api.h>#include <linux/workqueue_api.h> #ifdef CONFIG_PREEMPT_DYNAMIC# ifdef CONFIG_GENERIC_ENTRY#  include <linux/entry-common.h># endif#endif #include <uapi/linux/sched/types.h> #include <asm/irq_regs.h>#include <asm/switch_to.h>#include <asm/tlb.h> #define CREATE_TRACE_POINTS#include <linux/sched/rseq_api.h>#include <trace/events/sched.h>#undef CREATE_TRACE_POINTS #include "sched.h"#include "stats.h"#include "autogroup.h" #include "autogroup.h"#include "pelt.h"#include "smp.h"#include "stats.h" #include "../workqueue_internal.h"#include "../../io_uring/io-wq.h"#include "../smpboot.h" /* * Export tracepoints that act as a bare tracehook (ie: have no trace event * associated with them) to allow external modules to probe them. */EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_cfs_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_rt_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_dl_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_se_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_thermal_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(sched_cpu_capacity_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_se_tp);EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp); DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); #ifdef CONFIG_SCHED_DEBUG/* * Debugging: various feature bits * * If SCHED_DEBUG is disabled, each compilation unit has its own copy of * sysctl_sched_features, defined in sched.h, to allow constants propagation * at compile time and compiler optimization based on features default. */#define SCHED_FEAT(name, enabled)	\	(1UL << __SCHED_FEAT_##name) * enabled |const_debug unsigned int sysctl_sched_features =#include "features.h"	0;#undef SCHED_FEAT /* * Print a warning if need_resched is set for the given duration (if * LATENCY_WARN is enabled). * * If sysctl_resched_latency_warn_once is set, only one warning will be shown * per boot. */__read_mostly int sysctl_resched_latency_warn_ms = 100;__read_mostly int sysctl_resched_latency_warn_once = 1;#endif /* CONFIG_SCHED_DEBUG */ /* * Number of tasks to iterate in a single balance run. * Limited because this is done with IRQs disabled. */const_debug unsigned int sysctl_sched_nr_migrate = SCHED_NR_MIGRATE_BREAK; __read_mostly int scheduler_running; #ifdef CONFIG_SCHED_CORE DEFINE_STATIC_KEY_FALSE(__sched_core_enabled); /* kernel prio, less is more */static inline int __task_prio(struct task_struct *p){	if (p->sched_class == &stop_sched_class) /* trumps deadline */		return -2; 	if (rt_prio(p->prio)) /* includes deadline */		return p->prio; /* [-1, 99] */ 	if (p->sched_class == &idle_sched_class)		return MAX_RT_PRIO + NICE_WIDTH; /* 140 */ 	return MAX_RT_PRIO + MAX_NICE; /* 120, squash fair */} /* * l(a,b) * le(a,b) := !l(b,a) * g(a,b)  := l(b,a) * ge(a,b) := !l(a,b) */ /* real prio, less is less */static inline bool prio_less(struct task_struct *a, struct task_struct *b, bool in_fi){ 	int pa = __task_prio(a), pb = __task_prio(b); 	if (-pa < -pb)		return true; 	if (-pb < -pa)		return false; 	if (pa == -1) /* dl_prio() doesn't work because of stop_class above */		return !dl_time_before(a->dl.deadline, b->dl.deadline); 	if (pa == MAX_RT_PRIO + MAX_NICE)	/* fair */		return cfs_prio_less(a, b, in_fi); 	return false;} static inline bool __sched_core_less(struct task_struct *a, struct task_struct *b){	if (a->core_cookie < b->core_cookie)		return true; 	if (a->core_cookie > b->core_cookie)		return false; 	/* flip prio, so high prio is leftmost */	if (prio_less(b, a, !!task_rq(a)->core->core_forceidle_count))		return true; 	return false;} #define __node_2_sc(node) rb_entry((node), struct task_struct, core_node) static inline bool rb_sched_core_less(struct rb_node *a, const struct rb_node *b){	return __sched_core_less(__node_2_sc(a), __node_2_sc(b));} static inline int rb_sched_core_cmp(const void *key, const struct rb_node *node){	const struct task_struct *p = __node_2_sc(node);	unsigned long cookie = (unsigned long)key; 	if (cookie < p->core_cookie)		return -1; 	if (cookie > p->core_cookie)		return 1; 	return 0;} void sched_core_enqueue(struct rq *rq, struct task_struct *p){	rq->core->core_task_seq++; 	if (!p->core_cookie)		return; 	rb_add(&p->core_node, &rq->core_tree, rb_sched_core_less);} void sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags){	rq->core->core_task_seq++; 	if (sched_core_enqueued(p)) {		rb_erase(&p->core_node, &rq->core_tree);		RB_CLEAR_NODE(&p->core_node);	} 	/*	 * Migrating the last task off the cpu, with the cpu in forced idle	 * state. Reschedule to create an accounting edge for forced idle,	 * and re-examine whether the core is still in forced idle state.	 */	if (!(flags & DEQUEUE_SAVE) && rq->nr_running == 1 &&	    rq->core->core_forceidle_count && rq->curr == rq->idle)		resched_curr(rq);} /* * Find left-most (aka, highest priority) task matching @cookie. */static struct task_struct *sched_core_find(struct rq *rq, unsigned long cookie){	struct rb_node *node; 	node = rb_find_first((void *)cookie, &rq->core_tree, rb_sched_core_cmp);	/*	 * The idle task always matches any cookie!	 */	if (!node)		return idle_sched_class.pick_task(rq); 	return __node_2_sc(node);} static struct task_struct *sched_core_next(struct task_struct *p, unsigned long cookie){	struct rb_node *node = &p->core_node; 	node = rb_next(node);	if (!node)		return NULL; 	p = container_of(node, struct task_struct, core_node);	if (p->core_cookie != cookie)		return NULL; 	return p;} /* * Magic required such that: * *	raw_spin_rq_lock(rq); *	... *	raw_spin_rq_unlock(rq); * * ends up locking and unlocking the _same_ lock, and all CPUs * always agree on what rq has what lock. * * XXX entirely possible to selectively enable cores, don't bother for now. */ static DEFINE_MUTEX(sched_core_mutex);static atomic_t sched_core_count;static struct cpumask sched_core_mask; static void sched_core_lock(int cpu, unsigned long *flags){	const struct cpumask *smt_mask = cpu_smt_mask(cpu);	int t, i = 0; 	local_irq_save(*flags);	for_each_cpu(t, smt_mask)		raw_spin_lock_nested(&cpu_rq(t)->__lock, i++);} static void sched_core_unlock(int cpu, unsigned long *flags){	const struct cpumask *smt_mask = cpu_smt_mask(cpu);	int t; 	for_each_cpu(t, smt_mask)		raw_spin_unlock(&cpu_rq(t)->__lock);	local_irq_restore(*flags);} static void __sched_core_flip(bool enabled){	unsigned long flags;	int cpu, t; 	cpus_read_lock(); 	/*	 * Toggle the online cores, one by one.	 */	cpumask_copy(&sched_core_mask, cpu_online_mask);	for_each_cpu(cpu, &sched_core_mask) {		const struct cpumask *smt_mask = cpu_smt_mask(cpu); 		sched_core_lock(cpu, &flags); 		for_each_cpu(t, smt_mask)			cpu_rq(t)->core_enabled = enabled; 		cpu_rq(cpu)->core->core_forceidle_start = 0; 		sched_core_unlock(cpu, &flags); 		cpumask_andnot(&sched_core_mask, &sched_core_mask, smt_mask);	} 	/*	 * Toggle the offline CPUs.	 */	for_each_cpu_andnot(cpu, cpu_possible_mask, cpu_online_mask)		cpu_rq(cpu)->core_enabled = enabled; 	cpus_read_unlock();} static void sched_core_assert_empty(void){	int cpu; 	for_each_possible_cpu(cpu)		WARN_ON_ONCE(!RB_EMPTY_ROOT(&cpu_rq(cpu)->core_tree));} static void __sched_core_enable(void){	static_branch_enable(&__sched_core_enabled);	/*	 * Ensure all previous instances of raw_spin_rq_*lock() have finished	 * and future ones will observe !sched_core_disabled().	 */	synchronize_rcu();	__sched_core_flip(true);	sched_core_assert_empty();} static void __sched_core_disable(void){	sched_core_assert_empty();	__sched_core_flip(false);	static_branch_disable(&__sched_core_enabled);} void sched_core_get(void){	if (atomic_inc_not_zero(&sched_core_count))		return; 	mutex_lock(&sched_core_mutex);	if (!atomic_read(&sched_core_count))		__sched_core_enable(); 	smp_mb__before_atomic();	atomic_inc(&sched_core_count);	mutex_unlock(&sched_core_mutex);} static void __sched_core_put(struct work_struct *work){	if (atomic_dec_and_mutex_lock(&sched_core_count, &sched_core_mutex)) {		__sched_core_disable();		mutex_unlock(&sched_core_mutex);	}} void sched_core_put(void){	static DECLARE_WORK(_work, __sched_core_put); 	/*	 * "There can be only one"	 *	 * Either this is the last one, or we don't actually need to do any	 * 'work'. If it is the last *again*, we rely on	 * WORK_STRUCT_PENDING_BIT.	 */	if (!atomic_add_unless(&sched_core_count, -1, 1))		schedule_work(&_work);} #else /* !CONFIG_SCHED_CORE */ static inline void sched_core_enqueue(struct rq *rq, struct task_struct *p) { }static inline voidsched_core_dequeue(struct rq *rq, struct task_struct *p, int flags) { } #endif /* CONFIG_SCHED_CORE */ /* * Serialization rules: * * Lock order: * *   p->pi_lock *     rq->lock *       hrtimer_cpu_base->lock (hrtimer_start() for bandwidth controls) * *  rq1->lock *    rq2->lock  where: rq1 < rq2 * * Regular state: * * Normal scheduling state is serialized by rq->lock. __schedule() takes the * local CPU's rq->lock, it optionally removes the task from the runqueue and * always looks at the local rq data structures to find the most eligible task * to run next. * * Task enqueue is also under rq->lock, possibly taken from another CPU. * Wakeups from another LLC domain might use an IPI to transfer the enqueue to * the local CPU to avoid bouncing the runqueue state around [ see * ttwu_queue_wakelist() ] * * Task wakeup, specifically wakeups that involve migration, are horribly * complicated to avoid having to take two rq->locks. * * Special state: * * System-calls and anything external will use task_rq_lock() which acquires * both p->pi_lock and rq->lock. As a consequence the state they change is * stable while holding either lock: * *  - sched_setaffinity()/ *    set_cpus_allowed_ptr():	p->cpus_ptr, p->nr_cpus_allowed *  - set_user_nice():		p->se.load, p->*prio *  - __sched_setscheduler():	p->sched_class, p->policy, p->*prio, *				p->se.load, p->rt_priority, *				p->dl.dl_{runtime, deadline, period, flags, bw, density} *  - sched_setnuma():		p->numa_preferred_nid *  - sched_move_task():	p->sched_task_group *  - uclamp_update_active()	p->uclamp* * * p->state <- TASK_*: * *   is changed locklessly using set_current_state(), __set_current_state() or *   set_special_state(), see their respective comments, or by *   try_to_wake_up(). This latter uses p->pi_lock to serialize against *   concurrent self. * * p->on_rq <- { 0, 1 = TASK_ON_RQ_QUEUED, 2 = TASK_ON_RQ_MIGRATING }: * *   is set by activate_task() and cleared by deactivate_task(), under *   rq->lock. Non-zero indicates the task is runnable, the special *   ON_RQ_MIGRATING state is used for migration without holding both *   rq->locks. It indicates task_cpu() is not stable, see task_rq_lock(). * * p->on_cpu <- { 0, 1 }: * *   is set by prepare_task() and cleared by finish_task() such that it will be *   set before p is scheduled-in and cleared after p is scheduled-out, both *   under rq->lock. Non-zero indicates the task is running on its CPU. *

Lines 1–500 of 11367.