diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a10b545c2070..05685bf30120 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4675,6 +4675,12 @@ sbni= [NET] Granch SBNI12 leased line adapter + sched_timeslice= + [KNL] Time slice in us for BMQ/PDS scheduler. + Format: (must be >= 1000) + Default: 4000 + See Documentation/scheduler/sched-BMQ.txt + sched_debug [KNL] Enables verbose scheduler debug messages. schedstats= [KNL,X86] Enable or disable scheduled statistics. diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 1d56a6b73a4e..e08ffb857277 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -1515,3 +1515,13 @@ is 10 seconds. The softlockup threshold is (``2 * watchdog_thresh``). Setting this tunable to zero will disable lockup detection altogether. + +yield_type: +=========== + +BMQ/PDS CPU scheduler only. This determines what type of yield calls +to sched_yield will perform. + + 0 - No yield. + 1 - Deboost and requeue task. (default) + 2 - Set run queue skip task. diff --git a/Documentation/scheduler/sched-BMQ.txt b/Documentation/scheduler/sched-BMQ.txt new file mode 100644 index 000000000000..05c84eec0f31 --- /dev/null +++ b/Documentation/scheduler/sched-BMQ.txt @@ -0,0 +1,110 @@ + BitMap queue CPU Scheduler + -------------------------- + +CONTENT +======== + + Background + Design + Overview + Task policy + Priority management + BitMap Queue + CPU Assignment and Migration + + +Background +========== + +BitMap Queue CPU scheduler, referred to as BMQ from here on, is an evolution +of previous Priority and Deadline based Skiplist multiple queue scheduler(PDS), +and inspired by Zircon scheduler. The goal of it is to keep the scheduler code +simple, while efficiency and scalable for interactive tasks, such as desktop, +movie playback and gaming etc. + +Design +====== + +Overview +-------- + +BMQ use per CPU run queue design, each CPU(logical) has it's own run queue, +each CPU is responsible for scheduling the tasks that are putting into it's +run queue. + +The run queue is a set of priority queues. Note that these queues are fifo +queue for non-rt tasks or priority queue for rt tasks in data structure. See +BitMap Queue below for details. BMQ is optimized for non-rt tasks in the fact +that most applications are non-rt tasks. No matter the queue is fifo or +priority, In each queue is an ordered list of runnable tasks awaiting execution +and the data structures are the same. When it is time for a new task to run, +the scheduler simply looks the lowest numbered queueue that contains a task, +and runs the first task from the head of that queue. And per CPU idle task is +also in the run queue, so the scheduler can always find a task to run on from +its run queue. + +Each task will assigned the same timeslice(default 4ms) when it is picked to +start running. Task will be reinserted at the end of the appropriate priority +queue when it uses its whole timeslice. When the scheduler selects a new task +from the priority queue it sets the CPU's preemption timer for the remainder of +the previous timeslice. When that timer fires the scheduler will stop execution +on that task, select another task and start over again. + +If a task blocks waiting for a shared resource then it's taken out of its +priority queue and is placed in a wait queue for the shared resource. When it +is unblocked it will be reinserted in the appropriate priority queue of an +eligible CPU. + +Task policy +----------- + +BMQ supports DEADLINE, FIFO, RR, NORMAL, BATCH and IDLE task policy like the +mainline CFS scheduler. But BMQ is heavy optimized for non-rt task, that's +NORMAL/BATCH/IDLE policy tasks. Below is the implementation detail of each +policy. + +DEADLINE + It is squashed as priority 0 FIFO task. + +FIFO/RR + All RT tasks share one single priority queue in BMQ run queue designed. The +complexity of insert operation is O(n). BMQ is not designed for system runs +with major rt policy tasks. + +NORMAL/BATCH/IDLE + BATCH and IDLE tasks are treated as the same policy. They compete CPU with +NORMAL policy tasks, but they just don't boost. To control the priority of +NORMAL/BATCH/IDLE tasks, simply use nice level. + +ISO + ISO policy is not supported in BMQ. Please use nice level -20 NORMAL policy +task instead. + +Priority management +------------------- + +RT tasks have priority from 0-99. For non-rt tasks, there are three different +factors used to determine the effective priority of a task. The effective +priority being what is used to determine which queue it will be in. + +The first factor is simply the task’s static priority. Which is assigned from +task's nice level, within [-20, 19] in userland's point of view and [0, 39] +internally. + +The second factor is the priority boost. This is a value bounded between +[-MAX_PRIORITY_ADJ, MAX_PRIORITY_ADJ] used to offset the base priority, it is +modified by the following cases: + +*When a thread has used up its entire timeslice, always deboost its boost by +increasing by one. +*When a thread gives up cpu control(voluntary or non-voluntary) to reschedule, +and its switch-in time(time after last switch and run) below the thredhold +based on its priority boost, will boost its boost by decreasing by one buti is +capped at 0 (won’t go negative). + +The intent in this system is to ensure that interactive threads are serviced +quickly. These are usually the threads that interact directly with the user +and cause user-perceivable latency. These threads usually do little work and +spend most of their time blocked awaiting another user event. So they get the +priority boost from unblocking while background threads that do most of the +processing receive the priority penalty for using their entire timeslice. diff --git a/fs/proc/base.c b/fs/proc/base.c index b3422cda2a91..7ab99c9eaa5b 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -479,7 +479,7 @@ static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns, seq_puts(m, "0 0 0\n"); else seq_printf(m, "%llu %llu %lu\n", - (unsigned long long)task->se.sum_exec_runtime, + (unsigned long long)tsk_seruntime(task), (unsigned long long)task->sched_info.run_delay, task->sched_info.pcount); diff --git a/include/asm-generic/resource.h b/include/asm-generic/resource.h index 8874f681b056..59eb72bf7d5f 100644 --- a/include/asm-generic/resource.h +++ b/include/asm-generic/resource.h @@ -23,7 +23,7 @@ [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY }, \ [RLIMIT_SIGPENDING] = { 0, 0 }, \ [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ - [RLIMIT_NICE] = { 0, 0 }, \ + [RLIMIT_NICE] = { 30, 30 }, \ [RLIMIT_RTPRIO] = { 0, 0 }, \ [RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY }, \ } diff --git a/include/linux/sched.h b/include/linux/sched.h index 6e3a5eeec509..02647c8568af 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -35,6 +35,7 @@ #include #include #include +#include #include /* task_struct member predeclarations (sorted alphabetically): */ @@ -670,12 +671,18 @@ struct task_struct { unsigned int ptrace; #ifdef CONFIG_SMP - int on_cpu; struct __call_single_node wake_entry; +#endif +#if defined(CONFIG_SMP) || defined(CONFIG_SCHED_ALT) + int on_cpu; +#endif + +#ifdef CONFIG_SMP #ifdef CONFIG_THREAD_INFO_IN_TASK /* Current CPU: */ unsigned int cpu; #endif +#ifndef CONFIG_SCHED_ALT unsigned int wakee_flips; unsigned long wakee_flip_decay_ts; struct task_struct *last_wakee; @@ -689,6 +696,7 @@ struct task_struct { */ int recent_used_cpu; int wake_cpu; +#endif /* !CONFIG_SCHED_ALT */ #endif int on_rq; @@ -697,13 +705,33 @@ struct task_struct { int normal_prio; unsigned int rt_priority; +#ifdef CONFIG_SCHED_ALT + u64 last_ran; + s64 time_slice; +#ifdef CONFIG_SCHED_BMQ + int boost_prio; + int bmq_idx; + struct list_head bmq_node; +#endif /* CONFIG_SCHED_BMQ */ +#ifdef CONFIG_SCHED_PDS + u64 deadline; + u64 priodl; + /* skip list level */ + int sl_level; + /* skip list node */ + struct skiplist_node sl_node; +#endif /* CONFIG_SCHED_PDS */ + /* sched_clock time spent running */ + u64 sched_time; +#else /* !CONFIG_SCHED_ALT */ const struct sched_class *sched_class; struct sched_entity se; struct sched_rt_entity rt; + struct sched_dl_entity dl; +#endif #ifdef CONFIG_CGROUP_SCHED struct task_group *sched_task_group; #endif - struct sched_dl_entity dl; #ifdef CONFIG_UCLAMP_TASK /* @@ -1385,6 +1413,15 @@ struct task_struct { */ }; +#ifdef CONFIG_SCHED_ALT +#define tsk_seruntime(t) ((t)->sched_time) +/* replace the uncertian rt_timeout with 0UL */ +#define tsk_rttimeout(t) (0UL) +#else /* CFS */ +#define tsk_seruntime(t) ((t)->se.sum_exec_runtime) +#define tsk_rttimeout(t) ((t)->rt.timeout) +#endif /* !CONFIG_SCHED_ALT */ + static inline struct pid *task_pid(struct task_struct *task) { return task->thread_pid; diff --git a/include/linux/sched/deadline.h b/include/linux/sched/deadline.h index 1aff00b65f3c..179d77c8360e 100644 --- a/include/linux/sched/deadline.h +++ b/include/linux/sched/deadline.h @@ -1,5 +1,24 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifdef CONFIG_SCHED_ALT + +static inline int dl_task(struct task_struct *p) +{ + return 0; +} + +#ifdef CONFIG_SCHED_BMQ +#define __tsk_deadline(p) (0UL) +#endif + +#ifdef CONFIG_SCHED_PDS +#define __tsk_deadline(p) ((p)->priodl) +#endif + +#else + +#define __tsk_deadline(p) ((p)->dl.deadline) + /* * SCHED_DEADLINE tasks has negative priorities, reflecting * the fact that any of them has higher prio than RT and @@ -19,6 +38,7 @@ static inline int dl_task(struct task_struct *p) { return dl_prio(p->prio); } +#endif /* CONFIG_SCHED_ALT */ static inline bool dl_time_before(u64 a, u64 b) { diff --git a/include/linux/sched/prio.h b/include/linux/sched/prio.h index 7d64feafc408..42730d27ceb5 100644 --- a/include/linux/sched/prio.h +++ b/include/linux/sched/prio.h @@ -20,11 +20,20 @@ */ #define MAX_USER_RT_PRIO 100 + #define MAX_RT_PRIO MAX_USER_RT_PRIO #define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH) #define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2) +/* +/- priority levels from the base priority */ +#ifdef CONFIG_SCHED_BMQ +#define MAX_PRIORITY_ADJ 7 +#endif +#ifdef CONFIG_SCHED_PDS +#define MAX_PRIORITY_ADJ 0 +#endif + /* * Convert user-nice values [ -20 ... 0 ... 19 ] * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h index e5af028c08b4..0a7565d0d3cf 100644 --- a/include/linux/sched/rt.h +++ b/include/linux/sched/rt.h @@ -24,8 +24,10 @@ static inline bool task_is_realtime(struct task_struct *tsk) if (policy == SCHED_FIFO || policy == SCHED_RR) return true; +#ifndef CONFIG_SCHED_ALT if (policy == SCHED_DEADLINE) return true; +#endif return false; } diff --git a/include/linux/skip_list.h b/include/linux/skip_list.h new file mode 100644 index 000000000000..637c83ecbd6b --- /dev/null +++ b/include/linux/skip_list.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Alfred Chen. + * + * Code based on Con Kolivas's skip list implementation for BFS, and + * which is based on example originally by William Pugh. + * + * Skip Lists are a probabilistic alternative to balanced trees, as + * described in the June 1990 issue of CACM and were invented by + * William Pugh in 1987. + * + * A couple of comments about this implementation: + * + * This file only provides a infrastructure of skip list. + * + * skiplist_node is embedded into container data structure, to get rid + * the dependency of kmalloc/kfree operation in scheduler code. + * + * A customized search function should be defined using DEFINE_SKIPLIST_INSERT + * macro and be used for skip list insert operation. + * + * Random Level is also not defined in this file, instead, it should be + * customized implemented and set to node->level then pass to the customized + * skiplist_insert function. + * + * Levels start at zero and go up to (NUM_SKIPLIST_LEVEL -1) + * + * NUM_SKIPLIST_LEVEL in this implementation is 8 instead of origin 16, + * considering that there will be 256 entries to enable the top level when using + * random level p=0.5, and that number is more than enough for a run queue usage + * in a scheduler usage. And it also help to reduce the memory usage of the + * embedded skip list node in task_struct to about 50%. + * + * The insertion routine has been implemented so as to use the + * dirty hack described in the CACM paper: if a random level is + * generated that is more than the current maximum level, the + * current maximum level plus one is used instead. + * + * BFS Notes: In this implementation of skiplists, there are bidirectional + * next/prev pointers and the insert function returns a pointer to the actual + * node the value is stored. The key here is chosen by the scheduler so as to + * sort tasks according to the priority list requirements and is no longer used + * by the scheduler after insertion. The scheduler lookup, however, occurs in + * O(1) time because it is always the first item in the level 0 linked list. + * Since the task struct stores a copy of the node pointer upon skiplist_insert, + * it can also remove it much faster than the original implementation with the + * aid of prev<->next pointer manipulation and no searching. + */ +#ifndef _LINUX_SKIP_LIST_H +#define _LINUX_SKIP_LIST_H + +#include + +#define NUM_SKIPLIST_LEVEL (4) + +struct skiplist_node { + int level; /* Levels in this node */ + struct skiplist_node *next[NUM_SKIPLIST_LEVEL]; + struct skiplist_node *prev[NUM_SKIPLIST_LEVEL]; +}; + +#define SKIPLIST_NODE_INIT(name) { 0,\ + {&name, &name, &name, &name},\ + {&name, &name, &name, &name},\ + } + +/** + * INIT_SKIPLIST_NODE -- init a skiplist_node, expecially for header + * @node: the skip list node to be inited. + */ +static inline void INIT_SKIPLIST_NODE(struct skiplist_node *node) +{ + int i; + + node->level = 0; + for (i = 0; i < NUM_SKIPLIST_LEVEL; i++) { + WRITE_ONCE(node->next[i], node); + node->prev[i] = node; + } +} + +/** + * skiplist_entry - get the struct for this entry + * @ptr: the &struct skiplist_node pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the skiplist_node within the struct. + */ +#define skiplist_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * DEFINE_SKIPLIST_INSERT_FUNC -- macro to define a customized skip list insert + * function, which takes two parameters, first one is the header node of the + * skip list, second one is the skip list node to be inserted + * @func_name: the customized skip list insert function name + * @search_func: the search function to be used, which takes two parameters, + * 1st one is the itrator of skiplist_node in the list, the 2nd is the skip list + * node to be inserted, the function should return true if search should be + * continued, otherwise return false. + * Returns 1 if @node is inserted as the first item of skip list at level zero, + * otherwise 0 + */ +#define DEFINE_SKIPLIST_INSERT_FUNC(func_name, search_func)\ +static inline int func_name(struct skiplist_node *head, struct skiplist_node *node)\ +{\ + struct skiplist_node *p, *q;\ + unsigned int k = head->level;\ + unsigned int l = node->level;\ +\ + p = head;\ + if (l > k) {\ + l = node->level = ++head->level;\ +\ + node->next[l] = head;\ + node->prev[l] = head;\ + head->next[l] = node;\ + head->prev[l] = node;\ +\ + do {\ + while (q = p->next[k], q != head && search_func(q, node))\ + p = q;\ +\ + node->prev[k] = p;\ + node->next[k] = q;\ + q->prev[k] = node;\ + p->next[k] = node;\ + } while (k--);\ +\ + return (p == head);\ + }\ +\ + while (k > l) {\ + while (q = p->next[k], q != head && search_func(q, node))\ + p = q;\ + k--;\ + }\ +\ + do {\ + while (q = p->next[k], q != head && search_func(q, node))\ + p = q;\ +\ + node->prev[k] = p;\ + node->next[k] = q;\ + q->prev[k] = node;\ + p->next[k] = node;\ + } while (k--);\ +\ + return (p == head);\ +} + +/** + * skiplist_del_init -- delete skip list node from a skip list and reset it's + * init state + * @head: the header node of the skip list to be deleted from. + * @node: the skip list node to be deleted, the caller need to ensure @node is + * in skip list which @head represent. + * Returns 1 if @node is the first item of skip level at level zero, otherwise 0 + */ +static inline int +skiplist_del_init(struct skiplist_node *head, struct skiplist_node *node) +{ + unsigned int i, level = node->level; + + for (i = 0; i <= level; i++) { + node->prev[i]->next[i] = node->next[i]; + node->next[i]->prev[i] = node->prev[i]; + } + if (level == head->level && level) { + while (head->next[level] == head && level) + level--; + head->level = level; + } + + return (node->prev[0] == head); +} +#endif /* _LINUX_SKIP_LIST_H */ diff --git a/init/Kconfig b/init/Kconfig index 29ad68325028..cba4fff25c17 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -774,9 +774,39 @@ config GENERIC_SCHED_CLOCK menu "Scheduler features" +menuconfig SCHED_ALT + bool "Alternative CPU Schedulers" + default y + help + This feature enable alternative CPU scheduler" + +if SCHED_ALT + +choice + prompt "Alternative CPU Scheduler" + default SCHED_BMQ + +config SCHED_BMQ + bool "BMQ CPU scheduler" + help + The BitMap Queue CPU scheduler for excellent interactivity and + responsiveness on the desktop and solid scalability on normal + hardware and commodity servers. + +config SCHED_PDS + bool "PDS CPU scheduler" + help + The Priority and Deadline based Skip list multiple queue CPU + Scheduler. + +endchoice + +endif + config UCLAMP_TASK bool "Enable utilization clamping for RT/FAIR tasks" depends on CPU_FREQ_GOV_SCHEDUTIL + depends on !SCHED_ALT help This feature enables the scheduler to track the clamped utilization of each CPU based on RUNNABLE tasks scheduled on that CPU. @@ -862,6 +892,7 @@ config NUMA_BALANCING depends on ARCH_SUPPORTS_NUMA_BALANCING depends on !ARCH_WANT_NUMA_VARIABLE_LOCALITY depends on SMP && NUMA && MIGRATION + depends on !SCHED_ALT help This option adds support for automatic NUMA aware memory/task placement. The mechanism is quite primitive and is based on migrating memory when @@ -954,6 +985,7 @@ config FAIR_GROUP_SCHED depends on CGROUP_SCHED default CGROUP_SCHED +if !SCHED_ALT config CFS_BANDWIDTH bool "CPU bandwidth provisioning for FAIR_GROUP_SCHED" depends on FAIR_GROUP_SCHED @@ -976,6 +1008,7 @@ config RT_GROUP_SCHED realtime bandwidth for them. See Documentation/scheduler/sched-rt-group.rst for more information. +endif #!SCHED_ALT endif #CGROUP_SCHED config UCLAMP_TASK_GROUP @@ -1204,6 +1237,7 @@ config CHECKPOINT_RESTORE config SCHED_AUTOGROUP bool "Automatic process group scheduling" + depends on !SCHED_ALT select CGROUPS select CGROUP_SCHED select FAIR_GROUP_SCHED diff --git a/init/init_task.c b/init/init_task.c index 3711cdaafed2..4f8a2d4a05d9 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -75,9 +75,20 @@ struct task_struct init_task .stack = init_stack, .usage = REFCOUNT_INIT(2), .flags = PF_KTHREAD, +#ifdef CONFIG_SCHED_BMQ + .prio = DEFAULT_PRIO + MAX_PRIORITY_ADJ, + .static_prio = DEFAULT_PRIO, + .normal_prio = DEFAULT_PRIO + MAX_PRIORITY_ADJ, +#endif +#ifdef CONFIG_SCHED_PDS + .prio = MAX_USER_RT_PRIO, + .static_prio = DEFAULT_PRIO, + .normal_prio = MAX_USER_RT_PRIO, +#else .prio = MAX_PRIO - 20, .static_prio = MAX_PRIO - 20, .normal_prio = MAX_PRIO - 20, +#endif .policy = SCHED_NORMAL, .cpus_ptr = &init_task.cpus_mask, .cpus_mask = CPU_MASK_ALL, @@ -87,6 +98,19 @@ struct task_struct init_task .restart_block = { .fn = do_no_restart_syscall, }, +#ifdef CONFIG_SCHED_ALT +#ifdef CONFIG_SCHED_BMQ + .boost_prio = 0, + .bmq_idx = 15, + .bmq_node = LIST_HEAD_INIT(init_task.bmq_node), +#endif +#ifdef CONFIG_SCHED_PDS + .deadline = 0, + .sl_level = 0, + .sl_node = SKIPLIST_NODE_INIT(init_task.sl_node), +#endif + .time_slice = HZ, +#else .se = { .group_node = LIST_HEAD_INIT(init_task.se.group_node), }, @@ -94,6 +118,7 @@ struct task_struct init_task .run_list = LIST_HEAD_INIT(init_task.rt.run_list), .time_slice = RR_TIMESLICE, }, +#endif .tasks = LIST_HEAD_INIT(init_task.tasks), #ifdef CONFIG_SMP .pushable_tasks = PLIST_NODE_INIT(init_task.pushable_tasks, MAX_PRIO), diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 53c70c470a38..8cb38cccb68a 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -636,7 +636,7 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial) return ret; } -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) && !defined(CONFIG_SCHED_ALT) /* * Helper routine for generate_sched_domains(). * Do cpusets a, b have overlapping effective cpus_allowed masks? @@ -1032,7 +1032,7 @@ static void rebuild_sched_domains_locked(void) /* Have scheduler rebuild the domains */ partition_and_rebuild_sched_domains(ndoms, doms, attr); } -#else /* !CONFIG_SMP */ +#else /* !CONFIG_SMP || CONFIG_SCHED_ALT */ static void rebuild_sched_domains_locked(void) { } diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 27725754ac99..769d773c7182 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -106,7 +106,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) */ t1 = tsk->sched_info.pcount; t2 = tsk->sched_info.run_delay; - t3 = tsk->se.sum_exec_runtime; + t3 = tsk_seruntime(tsk); d->cpu_count += t1; diff --git a/kernel/exit.c b/kernel/exit.c index 04029e35e69a..5ee0dc0b9175 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -122,7 +122,7 @@ static void __exit_signal(struct task_struct *tsk) sig->curr_target = next_thread(tsk); } - add_device_randomness((const void*) &tsk->se.sum_exec_runtime, + add_device_randomness((const void*) &tsk_seruntime(tsk), sizeof(unsigned long long)); /* @@ -143,7 +143,7 @@ static void __exit_signal(struct task_struct *tsk) sig->inblock += task_io_get_inblock(tsk); sig->oublock += task_io_get_oublock(tsk); task_io_accounting_add(&sig->ioac, &tsk->ioac); - sig->sum_sched_runtime += tsk->se.sum_exec_runtime; + sig->sum_sched_runtime += tsk_seruntime(tsk); sig->nr_threads--; __unhash_process(tsk, group_dead); write_sequnlock(&sig->stats_lock); diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c index f6310f848f34..4176ad070bc9 100644 --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c @@ -306,7 +306,11 @@ static bool klp_try_switch_task(struct task_struct *task) */ rq = task_rq_lock(task, &flags); +#ifdef CONFIG_SCHED_ALT + if (task_running(task) && task != current) { +#else if (task_running(rq, task) && task != current) { +#endif snprintf(err_buf, STACK_ERR_BUF_SIZE, "%s: %s:%d is running\n", __func__, task->comm, task->pid); diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 2f8cd616d3b2..87576e687335 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -227,15 +227,19 @@ static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock, * Only use with rt_mutex_waiter_{less,equal}() */ #define task_to_waiter(p) \ - &(struct rt_mutex_waiter){ .prio = (p)->prio, .deadline = (p)->dl.deadline } + &(struct rt_mutex_waiter){ .prio = (p)->prio, .deadline = __tsk_deadline(p) } static inline int rt_mutex_waiter_less(struct rt_mutex_waiter *left, struct rt_mutex_waiter *right) { +#ifdef CONFIG_SCHED_PDS + return (left->deadline < right->deadline); +#else if (left->prio < right->prio) return 1; +#ifndef CONFIG_SCHED_BMQ /* * If both waiters have dl_prio(), we check the deadlines of the * associated tasks. @@ -244,17 +248,23 @@ rt_mutex_waiter_less(struct rt_mutex_waiter *left, */ if (dl_prio(left->prio)) return dl_time_before(left->deadline, right->deadline); +#endif return 0; +#endif } static inline int rt_mutex_waiter_equal(struct rt_mutex_waiter *left, struct rt_mutex_waiter *right) { +#ifdef CONFIG_SCHED_PDS + return (left->deadline == right->deadline); +#else if (left->prio != right->prio) return 0; +#ifndef CONFIG_SCHED_BMQ /* * If both waiters have dl_prio(), we check the deadlines of the * associated tasks. @@ -263,8 +273,10 @@ rt_mutex_waiter_equal(struct rt_mutex_waiter *left, */ if (dl_prio(left->prio)) return left->deadline == right->deadline; +#endif return 1; +#endif } static void @@ -678,7 +690,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, * the values of the node being removed. */ waiter->prio = task->prio; - waiter->deadline = task->dl.deadline; + waiter->deadline = __tsk_deadline(task); rt_mutex_enqueue(lock, waiter); @@ -951,7 +963,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, waiter->task = task; waiter->lock = lock; waiter->prio = task->prio; - waiter->deadline = task->dl.deadline; + waiter->deadline = __tsk_deadline(task); /* Get the top priority waiter on the lock */ if (rt_mutex_has_waiters(lock)) diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile index 5fc9c9b70862..eb6d7d87779f 100644 --- a/kernel/sched/Makefile +++ b/kernel/sched/Makefile @@ -22,14 +22,20 @@ ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer endif -obj-y += core.o loadavg.o clock.o cputime.o -obj-y += idle.o fair.o rt.o deadline.o -obj-y += wait.o wait_bit.o swait.o completion.o - -obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o topology.o stop_task.o pelt.o +ifdef CONFIG_SCHED_ALT +obj-y += alt_core.o alt_debug.o +else +obj-y += core.o +obj-y += fair.o rt.o deadline.o +obj-$(CONFIG_SMP) += cpudeadline.o stop_task.o obj-$(CONFIG_SCHED_AUTOGROUP) += autogroup.o -obj-$(CONFIG_SCHEDSTATS) += stats.o obj-$(CONFIG_SCHED_DEBUG) += debug.o +endif +obj-y += loadavg.o clock.o cputime.o +obj-y += idle.o +obj-y += wait.o wait_bit.o swait.o completion.o +obj-$(CONFIG_SMP) += cpupri.o pelt.o topology.o +obj-$(CONFIG_SCHEDSTATS) += stats.o obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o diff --git a/kernel/sched/alt_core.c b/kernel/sched/alt_core.c new file mode 100644 index 000000000000..0066b97100bb --- /dev/null +++ b/kernel/sched/alt_core.c @@ -0,0 +1,6914 @@ +/* + * kernel/sched/alt_core.c + * + * Core alternative kernel scheduler code and related syscalls + * + * Copyright (C) 1991-2002 Linus Torvalds + * + * 2009-08-13 Brainfuck deadline scheduling policy by Con Kolivas deletes + * a whole lot of those previous things. + * 2017-09-06 Priority and Deadline based Skip list multiple queue kernel + * scheduler by Alfred Chen. + * 2019-02-20 BMQ(BitMap Queue) kernel scheduler by Alfred Chen. + */ +#define CREATE_TRACE_POINTS +#include +#undef CREATE_TRACE_POINTS + +#include "sched.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "../workqueue_internal.h" +#include "../../fs/io-wq.h" +#include "../smpboot.h" + +#include "pelt.h" +#include "smp.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_irq_tp); + +#define ALT_SCHED_VERSION "v5.11-r3" + +/* rt_prio(prio) defined in include/linux/sched/rt.h */ +#define rt_task(p) rt_prio((p)->prio) +#define rt_policy(policy) ((policy) == SCHED_FIFO || (policy) == SCHED_RR) +#define task_has_rt_policy(p) (rt_policy((p)->policy)) + +#define STOP_PRIO (MAX_RT_PRIO - 1) + +/* Default time slice is 4 in ms, can be set via kernel parameter "sched_timeslice" */ +u64 sched_timeslice_ns __read_mostly = (4 * 1000 * 1000); + +static int __init sched_timeslice(char *str) +{ + int timeslice_us; + + get_option(&str, ×lice_us); + if (timeslice_us >= 1000) + sched_timeslice_ns = timeslice_us * 1000; + + return 0; +} +early_param("sched_timeslice", sched_timeslice); + +/* Reschedule if less than this many μs left */ +#define RESCHED_NS (100 * 1000) + +/** + * sched_yield_type - Choose what sort of yield sched_yield will perform. + * 0: No yield. + * 1: Deboost and requeue task. (default) + * 2: Set rq skip task. + */ +int sched_yield_type __read_mostly = 1; + +#ifdef CONFIG_SMP +static cpumask_t sched_rq_pending_mask ____cacheline_aligned_in_smp; + +DEFINE_PER_CPU(cpumask_t [NR_CPU_AFFINITY_LEVELS], sched_cpu_affinity_masks); +DEFINE_PER_CPU(cpumask_t *, sched_cpu_affinity_end_mask); + +DEFINE_PER_CPU(cpumask_t [NR_CPU_AFFINITY_LEVELS], sched_cpu_topo_masks); +DEFINE_PER_CPU(cpumask_t *, sched_cpu_llc_mask); + +#ifdef CONFIG_SCHED_SMT +DEFINE_STATIC_KEY_FALSE(sched_smt_present); +EXPORT_SYMBOL_GPL(sched_smt_present); +#endif + +/* + * Keep a unique ID per domain (we use the first CPUs number in the cpumask of + * the domain), this allows us to quickly tell if two cpus are in the same cache + * domain, see cpus_share_cache(). + */ +DEFINE_PER_CPU(int, sd_llc_id); +#endif /* CONFIG_SMP */ + +static DEFINE_MUTEX(sched_hotcpu_mutex); + +DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); + +#ifndef prepare_arch_switch +# define prepare_arch_switch(next) do { } while (0) +#endif +#ifndef finish_arch_post_lock_switch +# define finish_arch_post_lock_switch() do { } while (0) +#endif + +#define IDLE_WM (IDLE_TASK_SCHED_PRIO) + +#ifdef CONFIG_SCHED_SMT +static cpumask_t sched_sg_idle_mask ____cacheline_aligned_in_smp; +#endif +static cpumask_t sched_rq_watermark[SCHED_BITS] ____cacheline_aligned_in_smp; + +#ifdef CONFIG_SCHED_BMQ +#include "bmq_imp.h" +#endif +#ifdef CONFIG_SCHED_PDS +#include "pds_imp.h" +#endif + +static inline void update_sched_rq_watermark(struct rq *rq) +{ + unsigned long watermark = sched_queue_watermark(rq); + unsigned long last_wm = rq->watermark; + unsigned long i; + int cpu; + + /*printk(KERN_INFO "sched: watermark(%d) %d, last %d\n", + cpu_of(rq), watermark, last_wm);*/ + if (watermark == last_wm) + return; + + rq->watermark = watermark; + cpu = cpu_of(rq); + if (watermark < last_wm) { + for (i = watermark + 1; i <= last_wm; i++) + cpumask_andnot(&sched_rq_watermark[i], + &sched_rq_watermark[i], cpumask_of(cpu)); +#ifdef CONFIG_SCHED_SMT + if (!static_branch_likely(&sched_smt_present)) + return; + if (IDLE_WM == last_wm) + cpumask_andnot(&sched_sg_idle_mask, + &sched_sg_idle_mask, cpu_smt_mask(cpu)); +#endif + return; + } + /* last_wm < watermark */ + for (i = last_wm + 1; i <= watermark; i++) + cpumask_set_cpu(cpu, &sched_rq_watermark[i]); +#ifdef CONFIG_SCHED_SMT + if (!static_branch_likely(&sched_smt_present)) + return; + if (IDLE_WM == watermark) { + cpumask_t tmp; + cpumask_and(&tmp, cpu_smt_mask(cpu), &sched_rq_watermark[IDLE_WM]); + if (cpumask_equal(&tmp, cpu_smt_mask(cpu))) + cpumask_or(&sched_sg_idle_mask, cpu_smt_mask(cpu), + &sched_sg_idle_mask); + } +#endif +} + +static inline struct task_struct *rq_runnable_task(struct rq *rq) +{ + struct task_struct *next = sched_rq_first_task(rq); + + if (unlikely(next == rq->skip)) + next = sched_rq_next_task(next, rq); + + return next; +} + +/* + * 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()/ + * cpu_cgroup_fork(): 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. + * + * [ The astute reader will observe that it is possible for two tasks on one + * CPU to have ->on_cpu = 1 at the same time. ] + * + * task_cpu(p): is changed by set_task_cpu(), the rules are: + * + * - Don't call set_task_cpu() on a blocked task: + * + * We don't care what CPU we're not running on, this simplifies hotplug, + * the CPU assignment of blocked tasks isn't required to be valid. + * + * - for try_to_wake_up(), called under p->pi_lock: + * + * This allows try_to_wake_up() to only take one rq->lock, see its comment. + * + * - for migration called under rq->lock: + * [ see task_on_rq_migrating() in task_rq_lock() ] + * + * o move_queued_task() + * o detach_task() + * + * - for migration called under double_rq_lock(): + * + * o __migrate_swap_task() + * o push_rt_task() / pull_rt_task() + * o push_dl_task() / pull_dl_task() + * o dl_task_offline_migration() + * + */ + +/* + * Context: p->pi_lock + */ +static inline struct rq +*__task_access_lock(struct task_struct *p, raw_spinlock_t **plock) +{ + struct rq *rq; + for (;;) { + rq = task_rq(p); + if (p->on_cpu || task_on_rq_queued(p)) { + raw_spin_lock(&rq->lock); + if (likely((p->on_cpu || task_on_rq_queued(p)) + && rq == task_rq(p))) { + *plock = &rq->lock; + return rq; + } + raw_spin_unlock(&rq->lock); + } else if (task_on_rq_migrating(p)) { + do { + cpu_relax(); + } while (unlikely(task_on_rq_migrating(p))); + } else { + *plock = NULL; + return rq; + } + } +} + +static inline void +__task_access_unlock(struct task_struct *p, raw_spinlock_t *lock) +{ + if (NULL != lock) + raw_spin_unlock(lock); +} + +static inline struct rq +*task_access_lock_irqsave(struct task_struct *p, raw_spinlock_t **plock, + unsigned long *flags) +{ + struct rq *rq; + for (;;) { + rq = task_rq(p); + if (p->on_cpu || task_on_rq_queued(p)) { + raw_spin_lock_irqsave(&rq->lock, *flags); + if (likely((p->on_cpu || task_on_rq_queued(p)) + && rq == task_rq(p))) { + *plock = &rq->lock; + return rq; + } + raw_spin_unlock_irqrestore(&rq->lock, *flags); + } else if (task_on_rq_migrating(p)) { + do { + cpu_relax(); + } while (unlikely(task_on_rq_migrating(p))); + } else { + raw_spin_lock_irqsave(&p->pi_lock, *flags); + if (likely(!p->on_cpu && !p->on_rq && + rq == task_rq(p))) { + *plock = &p->pi_lock; + return rq; + } + raw_spin_unlock_irqrestore(&p->pi_lock, *flags); + } + } +} + +static inline void +task_access_unlock_irqrestore(struct task_struct *p, raw_spinlock_t *lock, + unsigned long *flags) +{ + raw_spin_unlock_irqrestore(lock, *flags); +} + +/* + * __task_rq_lock - lock the rq @p resides on. + */ +struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf) + __acquires(rq->lock) +{ + struct rq *rq; + + lockdep_assert_held(&p->pi_lock); + + for (;;) { + rq = task_rq(p); + raw_spin_lock(&rq->lock); + if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) + return rq; + raw_spin_unlock(&rq->lock); + + while (unlikely(task_on_rq_migrating(p))) + cpu_relax(); + } +} + +/* + * task_rq_lock - lock p->pi_lock and lock the rq @p resides on. + */ +struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf) + __acquires(p->pi_lock) + __acquires(rq->lock) +{ + struct rq *rq; + + for (;;) { + raw_spin_lock_irqsave(&p->pi_lock, rf->flags); + rq = task_rq(p); + raw_spin_lock(&rq->lock); + /* + * move_queued_task() task_rq_lock() + * + * ACQUIRE (rq->lock) + * [S] ->on_rq = MIGRATING [L] rq = task_rq() + * WMB (__set_task_cpu()) ACQUIRE (rq->lock); + * [S] ->cpu = new_cpu [L] task_rq() + * [L] ->on_rq + * RELEASE (rq->lock) + * + * If we observe the old CPU in task_rq_lock(), the acquire of + * the old rq->lock will fully serialize against the stores. + * + * If we observe the new CPU in task_rq_lock(), the address + * dependency headed by '[L] rq = task_rq()' and the acquire + * will pair with the WMB to ensure we then also see migrating. + */ + if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) { + return rq; + } + raw_spin_unlock(&rq->lock); + raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags); + + while (unlikely(task_on_rq_migrating(p))) + cpu_relax(); + } +} + +static inline void +rq_lock_irqsave(struct rq *rq, struct rq_flags *rf) + __acquires(rq->lock) +{ + raw_spin_lock_irqsave(&rq->lock, rf->flags); +} + +static inline void +rq_unlock_irqrestore(struct rq *rq, struct rq_flags *rf) + __releases(rq->lock) +{ + raw_spin_unlock_irqrestore(&rq->lock, rf->flags); +} + +/* + * RQ-clock updating methods: + */ + +static void update_rq_clock_task(struct rq *rq, s64 delta) +{ +/* + * In theory, the compile should just see 0 here, and optimize out the call + * to sched_rt_avg_update. But I don't trust it... + */ + s64 __maybe_unused steal = 0, irq_delta = 0; + +#ifdef CONFIG_IRQ_TIME_ACCOUNTING + irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time; + + /* + * Since irq_time is only updated on {soft,}irq_exit, we might run into + * this case when a previous update_rq_clock() happened inside a + * {soft,}irq region. + * + * When this happens, we stop ->clock_task and only update the + * prev_irq_time stamp to account for the part that fit, so that a next + * update will consume the rest. This ensures ->clock_task is + * monotonic. + * + * It does however cause some slight miss-attribution of {soft,}irq + * time, a more accurate solution would be to update the irq_time using + * the current rq->clock timestamp, except that would require using + * atomic ops. + */ + if (irq_delta > delta) + irq_delta = delta; + + rq->prev_irq_time += irq_delta; + delta -= irq_delta; +#endif +#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING + if (static_key_false((¶virt_steal_rq_enabled))) { + steal = paravirt_steal_clock(cpu_of(rq)); + steal -= rq->prev_steal_time_rq; + + if (unlikely(steal > delta)) + steal = delta; + + rq->prev_steal_time_rq += steal; + delta -= steal; + } +#endif + + rq->clock_task += delta; + +#ifdef CONFIG_HAVE_SCHED_AVG_IRQ + if ((irq_delta + steal)) + update_irq_load_avg(rq, irq_delta + steal); +#endif +} + +static inline void update_rq_clock(struct rq *rq) +{ + s64 delta = sched_clock_cpu(cpu_of(rq)) - rq->clock; + + if (unlikely(delta <= 0)) + return; + rq->clock += delta; + update_rq_clock_task(rq, delta); +} + +#ifdef CONFIG_NO_HZ_FULL +/* + * Tick may be needed by tasks in the runqueue depending on their policy and + * requirements. If tick is needed, lets send the target an IPI to kick it out + * of nohz mode if necessary. + */ +static inline void sched_update_tick_dependency(struct rq *rq) +{ + int cpu = cpu_of(rq); + + if (!tick_nohz_full_cpu(cpu)) + return; + + if (rq->nr_running < 2) + tick_nohz_dep_clear_cpu(cpu, TICK_DEP_BIT_SCHED); + else + tick_nohz_dep_set_cpu(cpu, TICK_DEP_BIT_SCHED); +} +#else /* !CONFIG_NO_HZ_FULL */ +static inline void sched_update_tick_dependency(struct rq *rq) { } +#endif + +/* + * Add/Remove/Requeue task to/from the runqueue routines + * Context: rq->lock + */ +static inline void dequeue_task(struct task_struct *p, struct rq *rq, int flags) +{ + lockdep_assert_held(&rq->lock); + + /*printk(KERN_INFO "sched: dequeue(%d) %px %016llx\n", cpu_of(rq), p, p->priodl);*/ + WARN_ONCE(task_rq(p) != rq, "sched: dequeue task reside on cpu%d from cpu%d\n", + task_cpu(p), cpu_of(rq)); + + __SCHED_DEQUEUE_TASK(p, rq, flags, update_sched_rq_watermark(rq)); + --rq->nr_running; +#ifdef CONFIG_SMP + if (1 == rq->nr_running) + cpumask_clear_cpu(cpu_of(rq), &sched_rq_pending_mask); +#endif + + sched_update_tick_dependency(rq); +} + +static inline void enqueue_task(struct task_struct *p, struct rq *rq, int flags) +{ + lockdep_assert_held(&rq->lock); + + /*printk(KERN_INFO "sched: enqueue(%d) %px %016llx\n", cpu_of(rq), p, p->priodl);*/ + WARN_ONCE(task_rq(p) != rq, "sched: enqueue task reside on cpu%d to cpu%d\n", + task_cpu(p), cpu_of(rq)); + + __SCHED_ENQUEUE_TASK(p, rq, flags); + update_sched_rq_watermark(rq); + ++rq->nr_running; +#ifdef CONFIG_SMP + if (2 == rq->nr_running) + cpumask_set_cpu(cpu_of(rq), &sched_rq_pending_mask); +#endif + + sched_update_tick_dependency(rq); + + /* + * If in_iowait is set, the code below may not trigger any cpufreq + * utilization updates, so do it here explicitly with the IOWAIT flag + * passed. + */ + if (p->in_iowait) + cpufreq_update_util(rq, SCHED_CPUFREQ_IOWAIT); +} + +static inline void requeue_task(struct task_struct *p, struct rq *rq) +{ + lockdep_assert_held(&rq->lock); + /*printk(KERN_INFO "sched: requeue(%d) %px %016llx\n", cpu_of(rq), p, p->priodl);*/ + WARN_ONCE(task_rq(p) != rq, "sched: cpu[%d] requeue task reside on cpu%d\n", + cpu_of(rq), task_cpu(p)); + + __SCHED_REQUEUE_TASK(p, rq, update_sched_rq_watermark(rq)); +} + +/* + * cmpxchg based fetch_or, macro so it works for different integer types + */ +#define fetch_or(ptr, mask) \ + ({ \ + typeof(ptr) _ptr = (ptr); \ + typeof(mask) _mask = (mask); \ + typeof(*_ptr) _old, _val = *_ptr; \ + \ + for (;;) { \ + _old = cmpxchg(_ptr, _val, _val | _mask); \ + if (_old == _val) \ + break; \ + _val = _old; \ + } \ + _old; \ +}) + +#if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG) +/* + * Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG, + * this avoids any races wrt polling state changes and thereby avoids + * spurious IPIs. + */ +static bool set_nr_and_not_polling(struct task_struct *p) +{ + struct thread_info *ti = task_thread_info(p); + return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG); +} + +/* + * Atomically set TIF_NEED_RESCHED if TIF_POLLING_NRFLAG is set. + * + * If this returns true, then the idle task promises to call + * sched_ttwu_pending() and reschedule soon. + */ +static bool set_nr_if_polling(struct task_struct *p) +{ + struct thread_info *ti = task_thread_info(p); + typeof(ti->flags) old, val = READ_ONCE(ti->flags); + + for (;;) { + if (!(val & _TIF_POLLING_NRFLAG)) + return false; + if (val & _TIF_NEED_RESCHED) + return true; + old = cmpxchg(&ti->flags, val, val | _TIF_NEED_RESCHED); + if (old == val) + break; + val = old; + } + return true; +} + +#else +static bool set_nr_and_not_polling(struct task_struct *p) +{ + set_tsk_need_resched(p); + return true; +} + +#ifdef CONFIG_SMP +static bool set_nr_if_polling(struct task_struct *p) +{ + return false; +} +#endif +#endif + +static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task) +{ + struct wake_q_node *node = &task->wake_q; + + /* + * Atomically grab the task, if ->wake_q is !nil already it means + * it's already queued (either by us or someone else) and will get the + * wakeup due to that. + * + * In order to ensure that a pending wakeup will observe our pending + * state, even in the failed case, an explicit smp_mb() must be used. + */ + smp_mb__before_atomic(); + if (unlikely(cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL))) + return false; + + /* + * The head is context local, there can be no concurrency. + */ + *head->lastp = node; + head->lastp = &node->next; + return true; +} + +/** + * wake_q_add() - queue a wakeup for 'later' waking. + * @head: the wake_q_head to add @task to + * @task: the task to queue for 'later' wakeup + * + * Queue a task for later wakeup, most likely by the wake_up_q() call in the + * same context, _HOWEVER_ this is not guaranteed, the wakeup can come + * instantly. + * + * This function must be used as-if it were wake_up_process(); IOW the task + * must be ready to be woken at this location. + */ +void wake_q_add(struct wake_q_head *head, struct task_struct *task) +{ + if (__wake_q_add(head, task)) + get_task_struct(task); +} + +/** + * wake_q_add_safe() - safely queue a wakeup for 'later' waking. + * @head: the wake_q_head to add @task to + * @task: the task to queue for 'later' wakeup + * + * Queue a task for later wakeup, most likely by the wake_up_q() call in the + * same context, _HOWEVER_ this is not guaranteed, the wakeup can come + * instantly. + * + * This function must be used as-if it were wake_up_process(); IOW the task + * must be ready to be woken at this location. + * + * This function is essentially a task-safe equivalent to wake_q_add(). Callers + * that already hold reference to @task can call the 'safe' version and trust + * wake_q to do the right thing depending whether or not the @task is already + * queued for wakeup. + */ +void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task) +{ + if (!__wake_q_add(head, task)) + put_task_struct(task); +} + +void wake_up_q(struct wake_q_head *head) +{ + struct wake_q_node *node = head->first; + + while (node != WAKE_Q_TAIL) { + struct task_struct *task; + + task = container_of(node, struct task_struct, wake_q); + BUG_ON(!task); + /* task can safely be re-inserted now: */ + node = node->next; + task->wake_q.next = NULL; + + /* + * wake_up_process() executes a full barrier, which pairs with + * the queueing in wake_q_add() so as not to miss wakeups. + */ + wake_up_process(task); + put_task_struct(task); + } +} + +/* + * resched_curr - mark rq's current task 'to be rescheduled now'. + * + * On UP this means the setting of the need_resched flag, on SMP it + * might also involve a cross-CPU call to trigger the scheduler on + * the target CPU. + */ +void resched_curr(struct rq *rq) +{ + struct task_struct *curr = rq->curr; + int cpu; + + lockdep_assert_held(&rq->lock); + + if (test_tsk_need_resched(curr)) + return; + + cpu = cpu_of(rq); + if (cpu == smp_processor_id()) { + set_tsk_need_resched(curr); + set_preempt_need_resched(); + return; + } + + if (set_nr_and_not_polling(curr)) + smp_send_reschedule(cpu); + else + trace_sched_wake_idle_without_ipi(cpu); +} + +void resched_cpu(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + raw_spin_lock_irqsave(&rq->lock, flags); + if (cpu_online(cpu) || cpu == smp_processor_id()) + resched_curr(cpu_rq(cpu)); + raw_spin_unlock_irqrestore(&rq->lock, flags); +} + +#ifdef CONFIG_SMP +#ifdef CONFIG_NO_HZ_COMMON +void nohz_balance_enter_idle(int cpu) {} + +void select_nohz_load_balancer(int stop_tick) {} + +void set_cpu_sd_state_idle(void) {} + +/* + * In the semi idle case, use the nearest busy CPU for migrating timers + * from an idle CPU. This is good for power-savings. + * + * We don't do similar optimization for completely idle system, as + * selecting an idle CPU will add more delays to the timers than intended + * (as that CPU's timer base may not be uptodate wrt jiffies etc). + */ +int get_nohz_timer_target(void) +{ + int i, cpu = smp_processor_id(), default_cpu = -1; + struct cpumask *mask; + + if (housekeeping_cpu(cpu, HK_FLAG_TIMER)) { + if (!idle_cpu(cpu)) + return cpu; + default_cpu = cpu; + } + + for (mask = per_cpu(sched_cpu_affinity_masks, cpu) + 1; + mask < per_cpu(sched_cpu_affinity_end_mask, cpu); mask++) + for_each_cpu_and(i, mask, housekeeping_cpumask(HK_FLAG_TIMER)) + if (!idle_cpu(i)) + return i; + + if (default_cpu == -1) + default_cpu = housekeeping_any_cpu(HK_FLAG_TIMER); + cpu = default_cpu; + + return cpu; +} + +/* + * When add_timer_on() enqueues a timer into the timer wheel of an + * idle CPU then this timer might expire before the next timer event + * which is scheduled to wake up that CPU. In case of a completely + * idle system the next event might even be infinite time into the + * future. wake_up_idle_cpu() ensures that the CPU is woken up and + * leaves the inner idle loop so the newly added timer is taken into + * account when the CPU goes back to idle and evaluates the timer + * wheel for the next timer event. + */ +static inline void wake_up_idle_cpu(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + if (cpu == smp_processor_id()) + return; + + if (set_nr_and_not_polling(rq->idle)) + smp_send_reschedule(cpu); + else + trace_sched_wake_idle_without_ipi(cpu); +} + +static inline bool wake_up_full_nohz_cpu(int cpu) +{ + /* + * We just need the target to call irq_exit() and re-evaluate + * the next tick. The nohz full kick at least implies that. + * If needed we can still optimize that later with an + * empty IRQ. + */ + if (cpu_is_offline(cpu)) + return true; /* Don't try to wake offline CPUs. */ + if (tick_nohz_full_cpu(cpu)) { + if (cpu != smp_processor_id() || + tick_nohz_tick_stopped()) + tick_nohz_full_kick_cpu(cpu); + return true; + } + + return false; +} + +void wake_up_nohz_cpu(int cpu) +{ + if (!wake_up_full_nohz_cpu(cpu)) + wake_up_idle_cpu(cpu); +} + +static void nohz_csd_func(void *info) +{ + struct rq *rq = info; + int cpu = cpu_of(rq); + unsigned int flags; + + /* + * Release the rq::nohz_csd. + */ + flags = atomic_fetch_andnot(NOHZ_KICK_MASK, nohz_flags(cpu)); + WARN_ON(!(flags & NOHZ_KICK_MASK)); + + rq->idle_balance = idle_cpu(cpu); + if (rq->idle_balance && !need_resched()) { + rq->nohz_idle_balance = flags; + raise_softirq_irqoff(SCHED_SOFTIRQ); + } +} + +#endif /* CONFIG_NO_HZ_COMMON */ +#endif /* CONFIG_SMP */ + +static inline void check_preempt_curr(struct rq *rq) +{ + if (sched_rq_first_task(rq) != rq->curr) + resched_curr(rq); +} + +#ifdef CONFIG_SCHED_HRTICK +/* + * Use HR-timers to deliver accurate preemption points. + */ + +static void hrtick_clear(struct rq *rq) +{ + if (hrtimer_active(&rq->hrtick_timer)) + hrtimer_cancel(&rq->hrtick_timer); +} + +/* + * High-resolution timer tick. + * Runs from hardirq context with interrupts disabled. + */ +static enum hrtimer_restart hrtick(struct hrtimer *timer) +{ + struct rq *rq = container_of(timer, struct rq, hrtick_timer); + struct task_struct *p; + + WARN_ON_ONCE(cpu_of(rq) != smp_processor_id()); + + raw_spin_lock(&rq->lock); + p = rq->curr; + p->time_slice = 0; + resched_curr(rq); + raw_spin_unlock(&rq->lock); + + return HRTIMER_NORESTART; +} + +/* + * Use hrtick when: + * - enabled by features + * - hrtimer is actually high res + */ +static inline int hrtick_enabled(struct rq *rq) +{ + /** + * Alt schedule FW doesn't support sched_feat yet + if (!sched_feat(HRTICK)) + return 0; + */ + if (!cpu_active(cpu_of(rq))) + return 0; + return hrtimer_is_hres_active(&rq->hrtick_timer); +} + +#ifdef CONFIG_SMP + +static void __hrtick_restart(struct rq *rq) +{ + struct hrtimer *timer = &rq->hrtick_timer; + + hrtimer_start_expires(timer, HRTIMER_MODE_ABS_PINNED_HARD); +} + +/* + * called from hardirq (IPI) context + */ +static void __hrtick_start(void *arg) +{ + struct rq *rq = arg; + + raw_spin_lock(&rq->lock); + __hrtick_restart(rq); + raw_spin_unlock(&rq->lock); +} + +/* + * Called to set the hrtick timer state. + * + * called with rq->lock held and irqs disabled + */ +void hrtick_start(struct rq *rq, u64 delay) +{ + struct hrtimer *timer = &rq->hrtick_timer; + ktime_t time; + s64 delta; + + /* + * Don't schedule slices shorter than 10000ns, that just + * doesn't make sense and can cause timer DoS. + */ + delta = max_t(s64, delay, 10000LL); + time = ktime_add_ns(timer->base->get_time(), delta); + + hrtimer_set_expires(timer, time); + + if (rq == this_rq()) + __hrtick_restart(rq); + else + smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd); +} + +#else +/* + * Called to set the hrtick timer state. + * + * called with rq->lock held and irqs disabled + */ +void hrtick_start(struct rq *rq, u64 delay) +{ + /* + * Don't schedule slices shorter than 10000ns, that just + * doesn't make sense. Rely on vruntime for fairness. + */ + delay = max_t(u64, delay, 10000LL); + hrtimer_start(&rq->hrtick_timer, ns_to_ktime(delay), + HRTIMER_MODE_REL_PINNED_HARD); +} +#endif /* CONFIG_SMP */ + +static void hrtick_rq_init(struct rq *rq) +{ +#ifdef CONFIG_SMP + INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq); +#endif + + hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); + rq->hrtick_timer.function = hrtick; +} +#else /* CONFIG_SCHED_HRTICK */ +static inline int hrtick_enabled(struct rq *rq) +{ + return 0; +} + +static inline void hrtick_clear(struct rq *rq) +{ +} + +static inline void hrtick_rq_init(struct rq *rq) +{ +} +#endif /* CONFIG_SCHED_HRTICK */ + +/* + * Calculate the current priority, i.e. the priority + * taken into account by the scheduler. This value might + * be boosted by RT tasks as it will be RT if the task got + * RT-boosted. If not then it returns p->normal_prio. + */ +static int effective_prio(struct task_struct *p) +{ + p->normal_prio = normal_prio(p); + /* + * If we are RT tasks or we were boosted to RT priority, + * keep the priority unchanged. Otherwise, update priority + * to the normal priority: + */ + if (!rt_prio(p->prio)) + return p->normal_prio; + return p->prio; +} + +/* + * activate_task - move a task to the runqueue. + * + * Context: rq->lock + */ +static void activate_task(struct task_struct *p, struct rq *rq) +{ + enqueue_task(p, rq, ENQUEUE_WAKEUP); + p->on_rq = TASK_ON_RQ_QUEUED; + cpufreq_update_util(rq, 0); +} + +/* + * deactivate_task - remove a task from the runqueue. + * + * Context: rq->lock + */ +static inline void deactivate_task(struct task_struct *p, struct rq *rq) +{ + dequeue_task(p, rq, DEQUEUE_SLEEP); + p->on_rq = 0; + cpufreq_update_util(rq, 0); +} + +static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) +{ +#ifdef CONFIG_SMP + /* + * After ->cpu is set up to a new value, task_access_lock(p, ...) can be + * successfully executed on another CPU. We must ensure that updates of + * per-task data have been completed by this moment. + */ + smp_wmb(); + +#ifdef CONFIG_THREAD_INFO_IN_TASK + WRITE_ONCE(p->cpu, cpu); +#else + WRITE_ONCE(task_thread_info(p)->cpu, cpu); +#endif +#endif +} + +static inline bool is_migration_disabled(struct task_struct *p) +{ +#ifdef CONFIG_SMP + return p->migration_disabled; +#else + return false; +#endif +} + +#define SCA_CHECK 0x01 +#define SCA_MIGRATE_DISABLE 0x02 +#define SCA_MIGRATE_ENABLE 0x04 + +#ifdef CONFIG_SMP + +void set_task_cpu(struct task_struct *p, unsigned int new_cpu) +{ +#ifdef CONFIG_SCHED_DEBUG + /* + * We should never call set_task_cpu() on a blocked task, + * ttwu() will sort out the placement. + */ + WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING && + !p->on_rq); +#ifdef CONFIG_LOCKDEP + /* + * The caller should hold either p->pi_lock or rq->lock, when changing + * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks. + * + * sched_move_task() holds both and thus holding either pins the cgroup, + * see task_group(). + */ + WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) || + lockdep_is_held(&task_rq(p)->lock))); +#endif + /* + * Clearly, migrating tasks to offline CPUs is a fairly daft thing. + */ + WARN_ON_ONCE(!cpu_online(new_cpu)); + + WARN_ON_ONCE(is_migration_disabled(p)); +#endif + if (task_cpu(p) == new_cpu) + return; + trace_sched_migrate_task(p, new_cpu); + rseq_migrate(p); + perf_event_task_migrate(p); + + __set_task_cpu(p, new_cpu); +} + +static inline bool is_per_cpu_kthread(struct task_struct *p) +{ + return ((p->flags & PF_KTHREAD) && (1 == p->nr_cpus_allowed)); +} + +#define MDF_FORCE_ENABLED 0x80 + +static void +__do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32 flags); + +static int __set_cpus_allowed_ptr(struct task_struct *p, + const struct cpumask *new_mask, + u32 flags); + +void migrate_disable(void) +{ + struct task_struct *p = current; + + if (p->migration_disabled) { + p->migration_disabled++; + return; + } + + preempt_disable(); + this_rq()->nr_pinned++; + p->migration_disabled = 1; + p->migration_flags &= ~MDF_FORCE_ENABLED; + + /* + * Violates locking rules! see comment in __do_set_cpus_allowed(). + */ + if (p->cpus_ptr == &p->cpus_mask) + __do_set_cpus_allowed(p, cpumask_of(smp_processor_id()), SCA_MIGRATE_DISABLE); + + preempt_enable(); +} +EXPORT_SYMBOL_GPL(migrate_disable); + +void migrate_enable(void) +{ + struct task_struct *p = current; + + if (0 == p->migration_disabled) + return; + + if (p->migration_disabled > 1) { + p->migration_disabled--; + return; + } + + /* + * Ensure stop_task runs either before or after this, and that + * __set_cpus_allowed_ptr(SCA_MIGRATE_ENABLE) doesn't schedule(). + */ + preempt_disable(); + /* + * Assumption: current should be running on allowed cpu + */ + WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &p->cpus_mask)); + if (p->cpus_ptr != &p->cpus_mask) + __do_set_cpus_allowed(p, &p->cpus_mask, SCA_MIGRATE_ENABLE); + /* + * Mustn't clear migration_disabled() until cpus_ptr points back at the + * regular cpus_mask, otherwise things that race (eg. + * select_fallback_rq) get confused. + */ + barrier(); + p->migration_disabled = 0; + this_rq()->nr_pinned--; + preempt_enable(); +} +EXPORT_SYMBOL_GPL(migrate_enable); + +static inline bool rq_has_pinned_tasks(struct rq *rq) +{ + return rq->nr_pinned; +} + +/* + * Per-CPU kthreads are allowed to run on !active && online CPUs, see + * __set_cpus_allowed_ptr() and select_fallback_rq(). + */ +static inline bool is_cpu_allowed(struct task_struct *p, int cpu) +{ + /* When not in the task's cpumask, no point in looking further. */ + if (!cpumask_test_cpu(cpu, p->cpus_ptr)) + return false; + + /* migrate_disabled() must be allowed to finish. */ + if (is_migration_disabled(p)) + return cpu_online(cpu); + + /* Non kernel threads are not allowed during either online or offline. */ + if (!(p->flags & PF_KTHREAD)) + return cpu_active(cpu); + + /* KTHREAD_IS_PER_CPU is always allowed. */ + if (kthread_is_per_cpu(p)) + return cpu_online(cpu); + + /* Regular kernel threads don't get to stay during offline. */ + if (cpu_rq(cpu)->balance_push) + return false; + + /* But are allowed during online. */ + return cpu_online(cpu); +} + +/* + * This is how migration works: + * + * 1) we invoke migration_cpu_stop() on the target CPU using + * stop_one_cpu(). + * 2) stopper starts to run (implicitly forcing the migrated thread + * off the CPU) + * 3) it checks whether the migrated task is still in the wrong runqueue. + * 4) if it's in the wrong runqueue then the migration thread removes + * it and puts it into the right queue. + * 5) stopper completes and stop_one_cpu() returns and the migration + * is done. + */ + +/* + * move_queued_task - move a queued task to new rq. + * + * Returns (locked) new rq. Old rq's lock is released. + */ +static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int + new_cpu) +{ + lockdep_assert_held(&rq->lock); + + WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING); + dequeue_task(p, rq, 0); + set_task_cpu(p, new_cpu); + raw_spin_unlock(&rq->lock); + + rq = cpu_rq(new_cpu); + + raw_spin_lock(&rq->lock); + BUG_ON(task_cpu(p) != new_cpu); + enqueue_task(p, rq, 0); + p->on_rq = TASK_ON_RQ_QUEUED; + check_preempt_curr(rq); + + return rq; +} + +struct migration_arg { + struct task_struct *task; + int dest_cpu; +}; + +/* + * Move (not current) task off this CPU, onto the destination CPU. We're doing + * this because either it can't run here any more (set_cpus_allowed() + * away from this CPU, or CPU going down), or because we're + * attempting to rebalance this task on exec (sched_exec). + * + * So we race with normal scheduler movements, but that's OK, as long + * as the task is no longer on this CPU. + */ +static struct rq *__migrate_task(struct rq *rq, struct task_struct *p, int + dest_cpu) +{ + /* Affinity changed (again). */ + if (!is_cpu_allowed(p, dest_cpu)) + return rq; + + update_rq_clock(rq); + return move_queued_task(rq, p, dest_cpu); +} + +/* + * migration_cpu_stop - this will be executed by a highprio stopper thread + * and performs thread migration by bumping thread off CPU then + * 'pushing' onto another runqueue. + */ +static int migration_cpu_stop(void *data) +{ + struct migration_arg *arg = data; + struct task_struct *p = arg->task; + struct rq *rq = this_rq(); + + /* + * The original target CPU might have gone down and we might + * be on another CPU but it doesn't matter. + */ + local_irq_disable(); + /* + * We need to explicitly wake pending tasks before running + * __migrate_task() such that we will not miss enforcing cpus_ptr + * during wakeups, see set_cpus_allowed_ptr()'s TASK_WAKING test. + */ + flush_smp_call_function_from_idle(); + + raw_spin_lock(&p->pi_lock); + raw_spin_lock(&rq->lock); + /* + * If task_rq(p) != rq, it cannot be migrated here, because we're + * holding rq->lock, if p->on_rq == 0 it cannot get enqueued because + * we're holding p->pi_lock. + */ + if (task_rq(p) == rq && task_on_rq_queued(p)) + rq = __migrate_task(rq, p, arg->dest_cpu); + raw_spin_unlock(&rq->lock); + raw_spin_unlock(&p->pi_lock); + + local_irq_enable(); + return 0; +} + +static inline void +set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask, u32 flags) +{ + if (flags & (SCA_MIGRATE_ENABLE | SCA_MIGRATE_DISABLE)) { + p->cpus_ptr = new_mask; + return; + } + + cpumask_copy(&p->cpus_mask, new_mask); + p->nr_cpus_allowed = cpumask_weight(new_mask); +} + +static void +__do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32 flags) +{ + /* + * This here violates the locking rules for affinity, since we're only + * supposed to change these variables while holding both rq->lock and + * p->pi_lock. + * + * HOWEVER, it magically works, because ttwu() is the only code that + * accesses these variables under p->pi_lock and only does so after + * smp_cond_load_acquire(&p->on_cpu, !VAL), and we're in __schedule() + * before finish_task(). + * + * XXX do further audits, this smells like something putrid. + */ + if (flags & (SCA_MIGRATE_DISABLE | SCA_MIGRATE_ENABLE)) + SCHED_WARN_ON(!p->on_cpu); + else + lockdep_assert_held(&p->pi_lock); + + set_cpus_allowed_common(p, new_mask, flags); +} + +void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask) +{ + __do_set_cpus_allowed(p, new_mask, 0); +} + +#endif + +/** + * task_curr - is this task currently executing on a CPU? + * @p: the task in question. + * + * Return: 1 if the task is currently executing. 0 otherwise. + */ +inline int task_curr(const struct task_struct *p) +{ + return cpu_curr(task_cpu(p)) == p; +} + +#ifdef CONFIG_SMP +/* + * wait_task_inactive - wait for a thread to unschedule. + * + * If @match_state is nonzero, it's the @p->state value just checked and + * not expected to change. If it changes, i.e. @p might have woken up, + * then return zero. When we succeed in waiting for @p to be off its CPU, + * we return a positive number (its total switch count). If a second call + * a short while later returns the same number, the caller can be sure that + * @p has remained unscheduled the whole time. + * + * The caller must ensure that the task *will* unschedule sometime soon, + * else this function might spin for a *long* time. This function can't + * be called with interrupts off, or it may introduce deadlock with + * smp_call_function() if an IPI is sent by the same process we are + * waiting to become inactive. + */ +unsigned long wait_task_inactive(struct task_struct *p, long match_state) +{ + unsigned long flags; + bool running, on_rq; + unsigned long ncsw; + struct rq *rq; + raw_spinlock_t *lock; + + for (;;) { + rq = task_rq(p); + + /* + * If the task is actively running on another CPU + * still, just relax and busy-wait without holding + * any locks. + * + * NOTE! Since we don't hold any locks, it's not + * even sure that "rq" stays as the right runqueue! + * But we don't care, since this will return false + * if the runqueue has changed and p is actually now + * running somewhere else! + */ + while (task_running(p) && p == rq->curr) { + if (match_state && unlikely(p->state != match_state)) + return 0; + cpu_relax(); + } + + /* + * Ok, time to look more closely! We need the rq + * lock now, to be *sure*. If we're wrong, we'll + * just go back and repeat. + */ + task_access_lock_irqsave(p, &lock, &flags); + trace_sched_wait_task(p); + running = task_running(p); + on_rq = p->on_rq; + ncsw = 0; + if (!match_state || p->state == match_state) + ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ + task_access_unlock_irqrestore(p, lock, &flags); + + /* + * If it changed from the expected state, bail out now. + */ + if (unlikely(!ncsw)) + break; + + /* + * Was it really running after all now that we + * checked with the proper locks actually held? + * + * Oops. Go back and try again.. + */ + if (unlikely(running)) { + cpu_relax(); + continue; + } + + /* + * It's not enough that it's not actively running, + * it must be off the runqueue _entirely_, and not + * preempted! + * + * So if it was still runnable (but just not actively + * running right now), it's preempted, and we should + * yield - it could be a while. + */ + if (unlikely(on_rq)) { + ktime_t to = NSEC_PER_SEC / HZ; + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_hrtimeout(&to, HRTIMER_MODE_REL); + continue; + } + + /* + * Ahh, all good. It wasn't running, and it wasn't + * runnable, which means that it will never become + * running in the future either. We're all done! + */ + break; + } + + return ncsw; +} + +/*** + * kick_process - kick a running thread to enter/exit the kernel + * @p: the to-be-kicked thread + * + * Cause a process which is running on another CPU to enter + * kernel-mode, without any delay. (to get signals handled.) + * + * NOTE: this function doesn't have to take the runqueue lock, + * because all it wants to ensure is that the remote task enters + * the kernel. If the IPI races and the task has been migrated + * to another CPU then no harm is done and the purpose has been + * achieved as well. + */ +void kick_process(struct task_struct *p) +{ + int cpu; + + preempt_disable(); + cpu = task_cpu(p); + if ((cpu != smp_processor_id()) && task_curr(p)) + smp_send_reschedule(cpu); + preempt_enable(); +} +EXPORT_SYMBOL_GPL(kick_process); + +/* + * ->cpus_ptr is protected by both rq->lock and p->pi_lock + * + * A few notes on cpu_active vs cpu_online: + * + * - cpu_active must be a subset of cpu_online + * + * - on CPU-up we allow per-CPU kthreads on the online && !active CPU, + * see __set_cpus_allowed_ptr(). At this point the newly online + * CPU isn't yet part of the sched domains, and balancing will not + * see it. + * + * - on cpu-down we clear cpu_active() to mask the sched domains and + * avoid the load balancer to place new tasks on the to be removed + * CPU. Existing tasks will remain running there and will be taken + * off. + * + * This means that fallback selection must not select !active CPUs. + * And can assume that any active CPU must be online. Conversely + * select_task_rq() below may allow selection of !active CPUs in order + * to satisfy the above rules. + */ +static int select_fallback_rq(int cpu, struct task_struct *p) +{ + int nid = cpu_to_node(cpu); + const struct cpumask *nodemask = NULL; + enum { cpuset, possible, fail } state = cpuset; + int dest_cpu; + + /* + * If the node that the CPU is on has been offlined, cpu_to_node() + * will return -1. There is no CPU on the node, and we should + * select the CPU on the other node. + */ + if (nid != -1) { + nodemask = cpumask_of_node(nid); + + /* Look for allowed, online CPU in same node. */ + for_each_cpu(dest_cpu, nodemask) { + if (!cpu_active(dest_cpu)) + continue; + if (cpumask_test_cpu(dest_cpu, p->cpus_ptr)) + return dest_cpu; + } + } + + for (;;) { + /* Any allowed, online CPU? */ + for_each_cpu(dest_cpu, p->cpus_ptr) { + if (!is_cpu_allowed(p, dest_cpu)) + continue; + goto out; + } + + /* No more Mr. Nice Guy. */ + switch (state) { + case cpuset: + if (IS_ENABLED(CONFIG_CPUSETS)) { + cpuset_cpus_allowed_fallback(p); + state = possible; + break; + } + fallthrough; + case possible: + /* + * XXX When called from select_task_rq() we only + * hold p->pi_lock and again violate locking order. + * + * More yuck to audit. + */ + do_set_cpus_allowed(p, cpu_possible_mask); + state = fail; + break; + + case fail: + BUG(); + break; + } + } + +out: + if (state != cpuset) { + /* + * Don't tell them about moving exiting tasks or + * kernel threads (both mm NULL), since they never + * leave kernel. + */ + if (p->mm && printk_ratelimit()) { + printk_deferred("process %d (%s) no longer affine to cpu%d\n", + task_pid_nr(p), p->comm, cpu); + } + } + + return dest_cpu; +} + +static inline int select_task_rq(struct task_struct *p, struct rq *rq) +{ + cpumask_t chk_mask, tmp; + + if (unlikely(!cpumask_and(&chk_mask, p->cpus_ptr, cpu_online_mask))) + return select_fallback_rq(task_cpu(p), p); + + if ( +#ifdef CONFIG_SCHED_SMT + cpumask_and(&tmp, &chk_mask, &sched_sg_idle_mask) || +#endif + cpumask_and(&tmp, &chk_mask, &sched_rq_watermark[IDLE_WM]) || + cpumask_and(&tmp, &chk_mask, + &sched_rq_watermark[task_sched_prio(p, rq) + 1])) + return best_mask_cpu(task_cpu(p), &tmp); + + return best_mask_cpu(task_cpu(p), &chk_mask); +} + +void sched_set_stop_task(int cpu, struct task_struct *stop) +{ + static struct lock_class_key stop_pi_lock; + struct sched_param stop_param = { .sched_priority = STOP_PRIO }; + struct sched_param start_param = { .sched_priority = 0 }; + struct task_struct *old_stop = cpu_rq(cpu)->stop; + + if (stop) { + /* + * Make it appear like a SCHED_FIFO task, its something + * userspace knows about and won't get confused about. + * + * Also, it will make PI more or less work without too + * much confusion -- but then, stop work should not + * rely on PI working anyway. + */ + sched_setscheduler_nocheck(stop, SCHED_FIFO, &stop_param); + + /* + * The PI code calls rt_mutex_setprio() with ->pi_lock held to + * adjust the effective priority of a task. As a result, + * rt_mutex_setprio() can trigger (RT) balancing operations, + * which can then trigger wakeups of the stop thread to push + * around the current task. + * + * The stop task itself will never be part of the PI-chain, it + * never blocks, therefore that ->pi_lock recursion is safe. + * Tell lockdep about this by placing the stop->pi_lock in its + * own class. + */ + lockdep_set_class(&stop->pi_lock, &stop_pi_lock); + } + + cpu_rq(cpu)->stop = stop; + + if (old_stop) { + /* + * Reset it back to a normal scheduling policy so that + * it can die in pieces. + */ + sched_setscheduler_nocheck(old_stop, SCHED_NORMAL, &start_param); + } +} + +/* + * Change a given task's CPU affinity. Migrate the thread to a + * proper CPU and schedule it away if the CPU it's executing on + * is removed from the allowed bitmask. + * + * NOTE: the caller must have a valid reference to the task, the + * task must not exit() & deallocate itself prematurely. The + * call is not atomic; no spinlocks may be held. + */ +static int __set_cpus_allowed_ptr(struct task_struct *p, + const struct cpumask *new_mask, + u32 flags) +{ + const struct cpumask *cpu_valid_mask = cpu_active_mask; + int dest_cpu; + unsigned long irq_flags; + struct rq *rq; + raw_spinlock_t *lock; + int ret = 0; + + raw_spin_lock_irqsave(&p->pi_lock, irq_flags); + rq = __task_access_lock(p, &lock); + + if (p->flags & PF_KTHREAD || is_migration_disabled(p)) { + /* + * Kernel threads are allowed on online && !active CPUs, + * however, during cpu-hot-unplug, even these might get pushed + * away if not KTHREAD_IS_PER_CPU. + * + * Specifically, migration_disabled() tasks must not fail the + * cpumask_any_and_distribute() pick below, esp. so on + * SCA_MIGRATE_ENABLE, otherwise we'll not call + * set_cpus_allowed_common() and actually reset p->cpus_ptr. + */ + cpu_valid_mask = cpu_online_mask; + } + + /* + * Must re-check here, to close a race against __kthread_bind(), + * sched_setaffinity() is not guaranteed to observe the flag. + */ + if ((flags & SCA_CHECK) && (p->flags & PF_NO_SETAFFINITY)) { + ret = -EINVAL; + goto out; + } + + if (cpumask_equal(&p->cpus_mask, new_mask)) + goto out; + + dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask); + if (dest_cpu >= nr_cpu_ids) { + ret = -EINVAL; + goto out; + } + + __do_set_cpus_allowed(p, new_mask, flags); + + if (p->flags & PF_KTHREAD) { + /* + * For kernel threads that do indeed end up on online && + * !active we want to ensure they are strict per-CPU threads. + */ + WARN_ON(cpumask_intersects(new_mask, cpu_online_mask) && + !cpumask_intersects(new_mask, cpu_active_mask) && + p->nr_cpus_allowed != 1); + } + + /* Can the task run on the task's current CPU? If so, we're done */ + if (cpumask_test_cpu(task_cpu(p), new_mask)) + goto out; + + if (p->migration_disabled) { + if (p->cpus_ptr != &p->cpus_mask) + __do_set_cpus_allowed(p, &p->cpus_mask, SCA_MIGRATE_ENABLE); + p->migration_disabled = 0; + p->migration_flags |= MDF_FORCE_ENABLED; + /* When p is migrate_disabled, rq->lock should be held */ + rq->nr_pinned--; + } + + if (task_running(p) || p->state == TASK_WAKING) { + struct migration_arg arg = { p, dest_cpu }; + + /* Need help from migration thread: drop lock and wait. */ + __task_access_unlock(p, lock); + raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags); + stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg); + return 0; + } + if (task_on_rq_queued(p)) { + /* + * OK, since we're going to drop the lock immediately + * afterwards anyway. + */ + update_rq_clock(rq); + rq = move_queued_task(rq, p, dest_cpu); + lock = &rq->lock; + } + +out: + __task_access_unlock(p, lock); + raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags); + + return ret; +} + +int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) +{ + return __set_cpus_allowed_ptr(p, new_mask, 0); +} +EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr); + +#else /* CONFIG_SMP */ + +static inline int select_task_rq(struct task_struct *p, struct rq *rq) +{ + return 0; +} + +static inline int +__set_cpus_allowed_ptr(struct task_struct *p, + const struct cpumask *new_mask, + u32 flags) +{ + return set_cpus_allowed_ptr(p, new_mask); +} + +static inline bool rq_has_pinned_tasks(struct rq *rq) +{ + return false; +} + +#endif /* !CONFIG_SMP */ + +static void +ttwu_stat(struct task_struct *p, int cpu, int wake_flags) +{ + struct rq *rq; + + if (!schedstat_enabled()) + return; + + rq = this_rq(); + +#ifdef CONFIG_SMP + if (cpu == rq->cpu) + __schedstat_inc(rq->ttwu_local); + else { + /** Alt schedule FW ToDo: + * How to do ttwu_wake_remote + */ + } +#endif /* CONFIG_SMP */ + + __schedstat_inc(rq->ttwu_count); +} + +/* + * Mark the task runnable and perform wakeup-preemption. + */ +static inline void +ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags) +{ + check_preempt_curr(rq); + p->state = TASK_RUNNING; + trace_sched_wakeup(p); +} + +static inline void +ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags) +{ + if (p->sched_contributes_to_load) + rq->nr_uninterruptible--; + + if ( +#ifdef CONFIG_SMP + !(wake_flags & WF_MIGRATED) && +#endif + p->in_iowait) { + delayacct_blkio_end(p); + atomic_dec(&task_rq(p)->nr_iowait); + } + + activate_task(p, rq); + ttwu_do_wakeup(rq, p, 0); +} + +/* + * Consider @p being inside a wait loop: + * + * for (;;) { + * set_current_state(TASK_UNINTERRUPTIBLE); + * + * if (CONDITION) + * break; + * + * schedule(); + * } + * __set_current_state(TASK_RUNNING); + * + * between set_current_state() and schedule(). In this case @p is still + * runnable, so all that needs doing is change p->state back to TASK_RUNNING in + * an atomic manner. + * + * By taking task_rq(p)->lock we serialize against schedule(), if @p->on_rq + * then schedule() must still happen and p->state can be changed to + * TASK_RUNNING. Otherwise we lost the race, schedule() has happened, and we + * need to do a full wakeup with enqueue. + * + * Returns: %true when the wakeup is done, + * %false otherwise. + */ +static int ttwu_runnable(struct task_struct *p, int wake_flags) +{ + struct rq *rq; + raw_spinlock_t *lock; + int ret = 0; + + rq = __task_access_lock(p, &lock); + if (task_on_rq_queued(p)) { + /* check_preempt_curr() may use rq clock */ + update_rq_clock(rq); + ttwu_do_wakeup(rq, p, wake_flags); + ret = 1; + } + __task_access_unlock(p, lock); + + return ret; +} + +#ifdef CONFIG_SMP +void sched_ttwu_pending(void *arg) +{ + struct llist_node *llist = arg; + struct rq *rq = this_rq(); + struct task_struct *p, *t; + struct rq_flags rf; + + if (!llist) + return; + + /* + * rq::ttwu_pending racy indication of out-standing wakeups. + * Races such that false-negatives are possible, since they + * are shorter lived that false-positives would be. + */ + WRITE_ONCE(rq->ttwu_pending, 0); + + rq_lock_irqsave(rq, &rf); + update_rq_clock(rq); + + llist_for_each_entry_safe(p, t, llist, wake_entry.llist) { + if (WARN_ON_ONCE(p->on_cpu)) + smp_cond_load_acquire(&p->on_cpu, !VAL); + + if (WARN_ON_ONCE(task_cpu(p) != cpu_of(rq))) + set_task_cpu(p, cpu_of(rq)); + + ttwu_do_activate(rq, p, p->sched_remote_wakeup ? WF_MIGRATED : 0); + } + + rq_unlock_irqrestore(rq, &rf); +} + +void send_call_function_single_ipi(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + if (!set_nr_if_polling(rq->idle)) + arch_send_call_function_single_ipi(cpu); + else + trace_sched_wake_idle_without_ipi(cpu); +} + +/* + * Queue a task on the target CPUs wake_list and wake the CPU via IPI if + * necessary. The wakee CPU on receipt of the IPI will queue the task + * via sched_ttwu_wakeup() for activation so the wakee incurs the cost + * of the wakeup instead of the waker. + */ +static void __ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags) +{ + struct rq *rq = cpu_rq(cpu); + + p->sched_remote_wakeup = !!(wake_flags & WF_MIGRATED); + + WRITE_ONCE(rq->ttwu_pending, 1); + __smp_call_single_queue(cpu, &p->wake_entry.llist); +} + +static inline bool ttwu_queue_cond(int cpu, int wake_flags) +{ + /* + * Do not complicate things with the async wake_list while the CPU is + * in hotplug state. + */ + if (!cpu_active(cpu)) + return false; + + /* + * If the CPU does not share cache, then queue the task on the + * remote rqs wakelist to avoid accessing remote data. + */ + if (!cpus_share_cache(smp_processor_id(), cpu)) + return true; + + /* + * If the task is descheduling and the only running task on the + * CPU then use the wakelist to offload the task activation to + * the soon-to-be-idle CPU as the current CPU is likely busy. + * nr_running is checked to avoid unnecessary task stacking. + */ + if ((wake_flags & WF_ON_CPU) && cpu_rq(cpu)->nr_running <= 1) + return true; + + return false; +} + +static bool ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags) +{ + if (__is_defined(ALT_SCHED_TTWU_QUEUE) && ttwu_queue_cond(cpu, wake_flags)) { + if (WARN_ON_ONCE(cpu == smp_processor_id())) + return false; + + sched_clock_cpu(cpu); /* Sync clocks across CPUs */ + __ttwu_queue_wakelist(p, cpu, wake_flags); + return true; + } + + return false; +} + +void wake_up_if_idle(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + rcu_read_lock(); + + if (!is_idle_task(rcu_dereference(rq->curr))) + goto out; + + if (set_nr_if_polling(rq->idle)) { + trace_sched_wake_idle_without_ipi(cpu); + } else { + raw_spin_lock_irqsave(&rq->lock, flags); + if (is_idle_task(rq->curr)) + smp_send_reschedule(cpu); + /* Else CPU is not idle, do nothing here */ + raw_spin_unlock_irqrestore(&rq->lock, flags); + } + +out: + rcu_read_unlock(); +} + +bool cpus_share_cache(int this_cpu, int that_cpu) +{ + return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu); +} +#else /* !CONFIG_SMP */ + +static inline bool ttwu_queue_wakelist(struct task_struct *p, int cpu, int wake_flags) +{ + return false; +} + +#endif /* CONFIG_SMP */ + +static inline void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) +{ + struct rq *rq = cpu_rq(cpu); + + if (ttwu_queue_wakelist(p, cpu, wake_flags)) + return; + + raw_spin_lock(&rq->lock); + update_rq_clock(rq); + ttwu_do_activate(rq, p, wake_flags); + raw_spin_unlock(&rq->lock); +} + +/* + * Notes on Program-Order guarantees on SMP systems. + * + * MIGRATION + * + * The basic program-order guarantee on SMP systems is that when a task [t] + * migrates, all its activity on its old CPU [c0] happens-before any subsequent + * execution on its new CPU [c1]. + * + * For migration (of runnable tasks) this is provided by the following means: + * + * A) UNLOCK of the rq(c0)->lock scheduling out task t + * B) migration for t is required to synchronize *both* rq(c0)->lock and + * rq(c1)->lock (if not at the same time, then in that order). + * C) LOCK of the rq(c1)->lock scheduling in task + * + * Transitivity guarantees that B happens after A and C after B. + * Note: we only require RCpc transitivity. + * Note: the CPU doing B need not be c0 or c1 + * + * Example: + * + * CPU0 CPU1 CPU2 + * + * LOCK rq(0)->lock + * sched-out X + * sched-in Y + * UNLOCK rq(0)->lock + * + * LOCK rq(0)->lock // orders against CPU0 + * dequeue X + * UNLOCK rq(0)->lock + * + * LOCK rq(1)->lock + * enqueue X + * UNLOCK rq(1)->lock + * + * LOCK rq(1)->lock // orders against CPU2 + * sched-out Z + * sched-in X + * UNLOCK rq(1)->lock + * + * + * BLOCKING -- aka. SLEEP + WAKEUP + * + * For blocking we (obviously) need to provide the same guarantee as for + * migration. However the means are completely different as there is no lock + * chain to provide order. Instead we do: + * + * 1) smp_store_release(X->on_cpu, 0) -- finish_task() + * 2) smp_cond_load_acquire(!X->on_cpu) -- try_to_wake_up() + * + * Example: + * + * CPU0 (schedule) CPU1 (try_to_wake_up) CPU2 (schedule) + * + * LOCK rq(0)->lock LOCK X->pi_lock + * dequeue X + * sched-out X + * smp_store_release(X->on_cpu, 0); + * + * smp_cond_load_acquire(&X->on_cpu, !VAL); + * X->state = WAKING + * set_task_cpu(X,2) + * + * LOCK rq(2)->lock + * enqueue X + * X->state = RUNNING + * UNLOCK rq(2)->lock + * + * LOCK rq(2)->lock // orders against CPU1 + * sched-out Z + * sched-in X + * UNLOCK rq(2)->lock + * + * UNLOCK X->pi_lock + * UNLOCK rq(0)->lock + * + * + * However; for wakeups there is a second guarantee we must provide, namely we + * must observe the state that lead to our wakeup. That is, not only must our + * task observe its own prior state, it must also observe the stores prior to + * its wakeup. + * + * This means that any means of doing remote wakeups must order the CPU doing + * the wakeup against the CPU the task is going to end up running on. This, + * however, is already required for the regular Program-Order guarantee above, + * since the waking CPU is the one issueing the ACQUIRE (smp_cond_load_acquire). + * + */ + +/** + * try_to_wake_up - wake up a thread + * @p: the thread to be awakened + * @state: the mask of task states that can be woken + * @wake_flags: wake modifier flags (WF_*) + * + * Conceptually does: + * + * If (@state & @p->state) @p->state = TASK_RUNNING. + * + * If the task was not queued/runnable, also place it back on a runqueue. + * + * This function is atomic against schedule() which would dequeue the task. + * + * It issues a full memory barrier before accessing @p->state, see the comment + * with set_current_state(). + * + * Uses p->pi_lock to serialize against concurrent wake-ups. + * + * Relies on p->pi_lock stabilizing: + * - p->sched_class + * - p->cpus_ptr + * - p->sched_task_group + * in order to do migration, see its use of select_task_rq()/set_task_cpu(). + * + * Tries really hard to only take one task_rq(p)->lock for performance. + * Takes rq->lock in: + * - ttwu_runnable() -- old rq, unavoidable, see comment there; + * - ttwu_queue() -- new rq, for enqueue of the task; + * - psi_ttwu_dequeue() -- much sadness :-( accounting will kill us. + * + * As a consequence we race really badly with just about everything. See the + * many memory barriers and their comments for details. + * + * Return: %true if @p->state changes (an actual wakeup was done), + * %false otherwise. + */ +static int try_to_wake_up(struct task_struct *p, unsigned int state, + int wake_flags) +{ + unsigned long flags; + int cpu, success = 0; + + preempt_disable(); + if (p == current) { + /* + * We're waking current, this means 'p->on_rq' and 'task_cpu(p) + * == smp_processor_id()'. Together this means we can special + * case the whole 'p->on_rq && ttwu_runnable()' case below + * without taking any locks. + * + * In particular: + * - we rely on Program-Order guarantees for all the ordering, + * - we're serialized against set_special_state() by virtue of + * it disabling IRQs (this allows not taking ->pi_lock). + */ + if (!(p->state & state)) + goto out; + + success = 1; + trace_sched_waking(p); + p->state = TASK_RUNNING; + trace_sched_wakeup(p); + goto out; + } + + /* + * If we are going to wake up a thread waiting for CONDITION we + * need to ensure that CONDITION=1 done by the caller can not be + * reordered with p->state check below. This pairs with smp_store_mb() + * in set_current_state() that the waiting thread does. + */ + raw_spin_lock_irqsave(&p->pi_lock, flags); + smp_mb__after_spinlock(); + if (!(p->state & state)) + goto unlock; + + trace_sched_waking(p); + + /* We're going to change ->state: */ + success = 1; + + /* + * Ensure we load p->on_rq _after_ p->state, otherwise it would + * be possible to, falsely, observe p->on_rq == 0 and get stuck + * in smp_cond_load_acquire() below. + * + * sched_ttwu_pending() try_to_wake_up() + * STORE p->on_rq = 1 LOAD p->state + * UNLOCK rq->lock + * + * __schedule() (switch to task 'p') + * LOCK rq->lock smp_rmb(); + * smp_mb__after_spinlock(); + * UNLOCK rq->lock + * + * [task p] + * STORE p->state = UNINTERRUPTIBLE LOAD p->on_rq + * + * Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in + * __schedule(). See the comment for smp_mb__after_spinlock(). + * + * A similar smb_rmb() lives in try_invoke_on_locked_down_task(). + */ + smp_rmb(); + if (READ_ONCE(p->on_rq) && ttwu_runnable(p, wake_flags)) + goto unlock; + +#ifdef CONFIG_SMP + /* + * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be + * possible to, falsely, observe p->on_cpu == 0. + * + * One must be running (->on_cpu == 1) in order to remove oneself + * from the runqueue. + * + * __schedule() (switch to task 'p') try_to_wake_up() + * STORE p->on_cpu = 1 LOAD p->on_rq + * UNLOCK rq->lock + * + * __schedule() (put 'p' to sleep) + * LOCK rq->lock smp_rmb(); + * smp_mb__after_spinlock(); + * STORE p->on_rq = 0 LOAD p->on_cpu + * + * Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in + * __schedule(). See the comment for smp_mb__after_spinlock(). + * + * Form a control-dep-acquire with p->on_rq == 0 above, to ensure + * schedule()'s deactivate_task() has 'happened' and p will no longer + * care about it's own p->state. See the comment in __schedule(). + */ + smp_acquire__after_ctrl_dep(); + + /* + * We're doing the wakeup (@success == 1), they did a dequeue (p->on_rq + * == 0), which means we need to do an enqueue, change p->state to + * TASK_WAKING such that we can unlock p->pi_lock before doing the + * enqueue, such as ttwu_queue_wakelist(). + */ + p->state = TASK_WAKING; + + /* + * If the owning (remote) CPU is still in the middle of schedule() with + * this task as prev, considering queueing p on the remote CPUs wake_list + * which potentially sends an IPI instead of spinning on p->on_cpu to + * let the waker make forward progress. This is safe because IRQs are + * disabled and the IPI will deliver after on_cpu is cleared. + * + * Ensure we load task_cpu(p) after p->on_cpu: + * + * set_task_cpu(p, cpu); + * STORE p->cpu = @cpu + * __schedule() (switch to task 'p') + * LOCK rq->lock + * smp_mb__after_spin_lock() smp_cond_load_acquire(&p->on_cpu) + * STORE p->on_cpu = 1 LOAD p->cpu + * + * to ensure we observe the correct CPU on which the task is currently + * scheduling. + */ + if (smp_load_acquire(&p->on_cpu) && + ttwu_queue_wakelist(p, task_cpu(p), wake_flags | WF_ON_CPU)) + goto unlock; + + /* + * If the owning (remote) CPU is still in the middle of schedule() with + * this task as prev, wait until it's done referencing the task. + * + * Pairs with the smp_store_release() in finish_task(). + * + * This ensures that tasks getting woken will be fully ordered against + * their previous state and preserve Program Order. + */ + smp_cond_load_acquire(&p->on_cpu, !VAL); + + sched_task_ttwu(p); + + cpu = select_task_rq(p, this_rq()); + + if (cpu != task_cpu(p)) { + if (p->in_iowait) { + delayacct_blkio_end(p); + atomic_dec(&task_rq(p)->nr_iowait); + } + + wake_flags |= WF_MIGRATED; + psi_ttwu_dequeue(p); + set_task_cpu(p, cpu); + } +#else + cpu = task_cpu(p); +#endif /* CONFIG_SMP */ + + ttwu_queue(p, cpu, wake_flags); +unlock: + raw_spin_unlock_irqrestore(&p->pi_lock, flags); +out: + if (success) + ttwu_stat(p, task_cpu(p), wake_flags); + preempt_enable(); + + return success; +} + +/** + * try_invoke_on_locked_down_task - Invoke a function on task in fixed state + * @p: Process for which the function is to be invoked, can be @current. + * @func: Function to invoke. + * @arg: Argument to function. + * + * If the specified task can be quickly locked into a definite state + * (either sleeping or on a given runqueue), arrange to keep it in that + * state while invoking @func(@arg). This function can use ->on_rq and + * task_curr() to work out what the state is, if required. Given that + * @func can be invoked with a runqueue lock held, it had better be quite + * lightweight. + * + * Returns: + * @false if the task slipped out from under the locks. + * @true if the task was locked onto a runqueue or is sleeping. + * However, @func can override this by returning @false. + */ +bool try_invoke_on_locked_down_task(struct task_struct *p, bool (*func)(struct task_struct *t, void *arg), void *arg) +{ + struct rq_flags rf; + bool ret = false; + struct rq *rq; + + raw_spin_lock_irqsave(&p->pi_lock, rf.flags); + if (p->on_rq) { + rq = __task_rq_lock(p, &rf); + if (task_rq(p) == rq) + ret = func(p, arg); + __task_rq_unlock(rq, &rf); + } else { + switch (p->state) { + case TASK_RUNNING: + case TASK_WAKING: + break; + default: + smp_rmb(); // See smp_rmb() comment in try_to_wake_up(). + if (!p->on_rq) + ret = func(p, arg); + } + } + raw_spin_unlock_irqrestore(&p->pi_lock, rf.flags); + return ret; +} + +/** + * wake_up_process - Wake up a specific process + * @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. + * + * This function executes a full memory barrier before accessing the task state. + */ +int wake_up_process(struct task_struct *p) +{ + return try_to_wake_up(p, TASK_NORMAL, 0); +} +EXPORT_SYMBOL(wake_up_process); + +int wake_up_state(struct task_struct *p, unsigned int state) +{ + return try_to_wake_up(p, state, 0); +} + +/* + * Perform scheduler related setup for a newly forked process p. + * p is forked by current. + * + * __sched_fork() is basic setup used by init_idle() too: + */ +static inline void __sched_fork(unsigned long clone_flags, struct task_struct *p) +{ + p->on_rq = 0; + p->on_cpu = 0; + p->utime = 0; + p->stime = 0; + p->sched_time = 0; + +#ifdef CONFIG_PREEMPT_NOTIFIERS + INIT_HLIST_HEAD(&p->preempt_notifiers); +#endif + +#ifdef CONFIG_COMPACTION + p->capture_control = NULL; +#endif +#ifdef CONFIG_SMP + p->wake_entry.u_flags = CSD_TYPE_TTWU; +#endif +} + +/* + * fork()/clone()-time setup: + */ +int sched_fork(unsigned long clone_flags, struct task_struct *p) +{ + unsigned long flags; + struct rq *rq; + + __sched_fork(clone_flags, p); + /* + * We mark the process as NEW here. This guarantees that + * nobody will actually run it, and a signal or other external + * event cannot wake it up and insert it on the runqueue either. + */ + p->state = TASK_NEW; + + /* + * Make sure we do not leak PI boosting priority to the child. + */ + p->prio = current->normal_prio; + + /* + * Revert to default priority/policy on fork if requested. + */ + if (unlikely(p->sched_reset_on_fork)) { + if (task_has_rt_policy(p)) { + p->policy = SCHED_NORMAL; + p->static_prio = NICE_TO_PRIO(0); + p->rt_priority = 0; + } else if (PRIO_TO_NICE(p->static_prio) < 0) + p->static_prio = NICE_TO_PRIO(0); + + p->prio = p->normal_prio = normal_prio(p); + + /* + * We don't need the reset flag anymore after the fork. It has + * fulfilled its duty: + */ + p->sched_reset_on_fork = 0; + } + + /* + * The child is not yet in the pid-hash so no cgroup attach races, + * and the cgroup is pinned to this child due to cgroup_fork() + * is ran before sched_fork(). + * + * Silence PROVE_RCU. + */ + raw_spin_lock_irqsave(&p->pi_lock, flags); + /* + * Share the timeslice between parent and child, thus the + * total amount of pending timeslices in the system doesn't change, + * resulting in more scheduling fairness. + */ + rq = this_rq(); + raw_spin_lock(&rq->lock); + + rq->curr->time_slice /= 2; + p->time_slice = rq->curr->time_slice; +#ifdef CONFIG_SCHED_HRTICK + hrtick_start(rq, rq->curr->time_slice); +#endif + + if (p->time_slice < RESCHED_NS) { + p->time_slice = sched_timeslice_ns; + resched_curr(rq); + } + sched_task_fork(p, rq); + raw_spin_unlock(&rq->lock); + + rseq_migrate(p); + /* + * We're setting the CPU for the first time, we don't migrate, + * so use __set_task_cpu(). + */ + __set_task_cpu(p, cpu_of(rq)); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); + +#ifdef CONFIG_SCHED_INFO + if (unlikely(sched_info_on())) + memset(&p->sched_info, 0, sizeof(p->sched_info)); +#endif + init_task_preempt_count(p); + + return 0; +} + +void sched_post_fork(struct task_struct *p) {} + +#ifdef CONFIG_SCHEDSTATS + +DEFINE_STATIC_KEY_FALSE(sched_schedstats); +static bool __initdata __sched_schedstats = false; + +static void set_schedstats(bool enabled) +{ + if (enabled) + static_branch_enable(&sched_schedstats); + else + static_branch_disable(&sched_schedstats); +} + +void force_schedstat_enabled(void) +{ + if (!schedstat_enabled()) { + pr_info("kernel profiling enabled schedstats, disable via kernel.sched_schedstats.\n"); + static_branch_enable(&sched_schedstats); + } +} + +static int __init setup_schedstats(char *str) +{ + int ret = 0; + if (!str) + goto out; + + /* + * This code is called before jump labels have been set up, so we can't + * change the static branch directly just yet. Instead set a temporary + * variable so init_schedstats() can do it later. + */ + if (!strcmp(str, "enable")) { + __sched_schedstats = true; + ret = 1; + } else if (!strcmp(str, "disable")) { + __sched_schedstats = false; + ret = 1; + } +out: + if (!ret) + pr_warn("Unable to parse schedstats=\n"); + + return ret; +} +__setup("schedstats=", setup_schedstats); + +static void __init init_schedstats(void) +{ + set_schedstats(__sched_schedstats); +} + +#ifdef CONFIG_PROC_SYSCTL +int sysctl_schedstats(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table t; + int err; + int state = static_branch_likely(&sched_schedstats); + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + t = *table; + t.data = &state; + err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); + if (err < 0) + return err; + if (write) + set_schedstats(state); + return err; +} +#endif /* CONFIG_PROC_SYSCTL */ +#else /* !CONFIG_SCHEDSTATS */ +static inline void init_schedstats(void) {} +#endif /* CONFIG_SCHEDSTATS */ + +/* + * wake_up_new_task - wake up a newly created task for the first time. + * + * This function will do some initial scheduler statistics housekeeping + * that must be done for every newly created context, then puts the task + * on the runqueue and wakes it. + */ +void wake_up_new_task(struct task_struct *p) +{ + unsigned long flags; + struct rq *rq; + + raw_spin_lock_irqsave(&p->pi_lock, flags); + + p->state = TASK_RUNNING; + + rq = cpu_rq(select_task_rq(p, this_rq())); +#ifdef CONFIG_SMP + rseq_migrate(p); + /* + * Fork balancing, do it here and not earlier because: + * - cpus_ptr can change in the fork path + * - any previously selected CPU might disappear through hotplug + * Use __set_task_cpu() to avoid calling sched_class::migrate_task_rq, + * as we're not fully set-up yet. + */ + __set_task_cpu(p, cpu_of(rq)); +#endif + + raw_spin_lock(&rq->lock); + + update_rq_clock(rq); + activate_task(p, rq); + trace_sched_wakeup_new(p); + check_preempt_curr(rq); + + raw_spin_unlock(&rq->lock); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); +} + +#ifdef CONFIG_PREEMPT_NOTIFIERS + +static DEFINE_STATIC_KEY_FALSE(preempt_notifier_key); + +void preempt_notifier_inc(void) +{ + static_branch_inc(&preempt_notifier_key); +} +EXPORT_SYMBOL_GPL(preempt_notifier_inc); + +void preempt_notifier_dec(void) +{ + static_branch_dec(&preempt_notifier_key); +} +EXPORT_SYMBOL_GPL(preempt_notifier_dec); + +/** + * preempt_notifier_register - tell me when current is being preempted & rescheduled + * @notifier: notifier struct to register + */ +void preempt_notifier_register(struct preempt_notifier *notifier) +{ + if (!static_branch_unlikely(&preempt_notifier_key)) + WARN(1, "registering preempt_notifier while notifiers disabled\n"); + + hlist_add_head(¬ifier->link, ¤t->preempt_notifiers); +} +EXPORT_SYMBOL_GPL(preempt_notifier_register); + +/** + * preempt_notifier_unregister - no longer interested in preemption notifications + * @notifier: notifier struct to unregister + * + * This is *not* safe to call from within a preemption notifier. + */ +void preempt_notifier_unregister(struct preempt_notifier *notifier) +{ + hlist_del(¬ifier->link); +} +EXPORT_SYMBOL_GPL(preempt_notifier_unregister); + +static void __fire_sched_in_preempt_notifiers(struct task_struct *curr) +{ + struct preempt_notifier *notifier; + + hlist_for_each_entry(notifier, &curr->preempt_notifiers, link) + notifier->ops->sched_in(notifier, raw_smp_processor_id()); +} + +static __always_inline void fire_sched_in_preempt_notifiers(struct task_struct *curr) +{ + if (static_branch_unlikely(&preempt_notifier_key)) + __fire_sched_in_preempt_notifiers(curr); +} + +static void +__fire_sched_out_preempt_notifiers(struct task_struct *curr, + struct task_struct *next) +{ + struct preempt_notifier *notifier; + + hlist_for_each_entry(notifier, &curr->preempt_notifiers, link) + notifier->ops->sched_out(notifier, next); +} + +static __always_inline void +fire_sched_out_preempt_notifiers(struct task_struct *curr, + struct task_struct *next) +{ + if (static_branch_unlikely(&preempt_notifier_key)) + __fire_sched_out_preempt_notifiers(curr, next); +} + +#else /* !CONFIG_PREEMPT_NOTIFIERS */ + +static inline void fire_sched_in_preempt_notifiers(struct task_struct *curr) +{ +} + +static inline void +fire_sched_out_preempt_notifiers(struct task_struct *curr, + struct task_struct *next) +{ +} + +#endif /* CONFIG_PREEMPT_NOTIFIERS */ + +static inline void prepare_task(struct task_struct *next) +{ + /* + * Claim the task as running, we do this before switching to it + * such that any running task will have this set. + * + * See the ttwu() WF_ON_CPU case and its ordering comment. + */ + WRITE_ONCE(next->on_cpu, 1); +} + +static inline void finish_task(struct task_struct *prev) +{ +#ifdef CONFIG_SMP + /* + * This must be the very last reference to @prev from this CPU. After + * p->on_cpu is cleared, the task can be moved to a different CPU. We + * must ensure this doesn't happen until the switch is completely + * finished. + * + * In particular, the load of prev->state in finish_task_switch() must + * happen before this. + * + * Pairs with the smp_cond_load_acquire() in try_to_wake_up(). + */ + smp_store_release(&prev->on_cpu, 0); +#else + prev->on_cpu = 0; +#endif +} + +#ifdef CONFIG_SMP + +static void do_balance_callbacks(struct rq *rq, struct callback_head *head) +{ + void (*func)(struct rq *rq); + struct callback_head *next; + + lockdep_assert_held(&rq->lock); + + while (head) { + func = (void (*)(struct rq *))head->func; + next = head->next; + head->next = NULL; + head = next; + + func(rq); + } +} + +static void balance_push(struct rq *rq); + +struct callback_head balance_push_callback = { + .next = NULL, + .func = (void (*)(struct callback_head *))balance_push, +}; + +static inline struct callback_head *splice_balance_callbacks(struct rq *rq) +{ + struct callback_head *head = rq->balance_callback; + + if (head) { + lockdep_assert_held(&rq->lock); + rq->balance_callback = NULL; + } + + return head; +} + +static void __balance_callbacks(struct rq *rq) +{ + do_balance_callbacks(rq, splice_balance_callbacks(rq)); +} + +static inline void balance_callbacks(struct rq *rq, struct callback_head *head) +{ + unsigned long flags; + + if (unlikely(head)) { + raw_spin_lock_irqsave(&rq->lock, flags); + do_balance_callbacks(rq, head); + raw_spin_unlock_irqrestore(&rq->lock, flags); + } +} + +#else + +static inline void __balance_callbacks(struct rq *rq) +{ +} + +static inline struct callback_head *splice_balance_callbacks(struct rq *rq) +{ + return NULL; +} + +static inline void balance_callbacks(struct rq *rq, struct callback_head *head) +{ +} + +#endif + +static inline void +prepare_lock_switch(struct rq *rq, struct task_struct *next) +{ + /* + * Since the runqueue lock will be released by the next + * task (which is an invalid locking op but in the case + * of the scheduler it's an obvious special-case), so we + * do an early lockdep release here: + */ + spin_release(&rq->lock.dep_map, _THIS_IP_); +#ifdef CONFIG_DEBUG_SPINLOCK + /* this is a valid case when another task releases the spinlock */ + rq->lock.owner = next; +#endif +} + +static inline void finish_lock_switch(struct rq *rq) +{ + /* + * If we are tracking spinlock dependencies then we have to + * fix up the runqueue lock - which gets 'carried over' from + * prev into current: + */ + spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_); + __balance_callbacks(rq); + raw_spin_unlock_irq(&rq->lock); +} + +/* + * NOP if the arch has not defined these: + */ + +#ifndef prepare_arch_switch +# define prepare_arch_switch(next) do { } while (0) +#endif + +#ifndef finish_arch_post_lock_switch +# define finish_arch_post_lock_switch() do { } while (0) +#endif + +static inline void kmap_local_sched_out(void) +{ +#ifdef CONFIG_KMAP_LOCAL + if (unlikely(current->kmap_ctrl.idx)) + __kmap_local_sched_out(); +#endif +} + +static inline void kmap_local_sched_in(void) +{ +#ifdef CONFIG_KMAP_LOCAL + if (unlikely(current->kmap_ctrl.idx)) + __kmap_local_sched_in(); +#endif +} + +/** + * prepare_task_switch - prepare to switch tasks + * @rq: the runqueue preparing to switch + * @next: the task we are going to switch to. + * + * This is called with the rq lock held and interrupts off. It must + * be paired with a subsequent finish_task_switch after the context + * switch. + * + * prepare_task_switch sets up locking and calls architecture specific + * hooks. + */ +static inline void +prepare_task_switch(struct rq *rq, struct task_struct *prev, + struct task_struct *next) +{ + kcov_prepare_switch(prev); + sched_info_switch(rq, prev, next); + perf_event_task_sched_out(prev, next); + rseq_preempt(prev); + fire_sched_out_preempt_notifiers(prev, next); + kmap_local_sched_out(); + prepare_task(next); + prepare_arch_switch(next); +} + +/** + * finish_task_switch - clean up after a task-switch + * @rq: runqueue associated with task-switch + * @prev: the thread we just switched away from. + * + * finish_task_switch must be called after the context switch, paired + * with a prepare_task_switch call before the context switch. + * finish_task_switch will reconcile locking set up by prepare_task_switch, + * and do any other architecture-specific cleanup actions. + * + * Note that we may have delayed dropping an mm in context_switch(). If + * so, we finish that here outside of the runqueue lock. (Doing it + * with the lock held can cause deadlocks; see schedule() for + * details.) + * + * The context switch have flipped the stack from under us and restored the + * local variables which were saved when this task called schedule() in the + * past. prev == current is still correct but we need to recalculate this_rq + * because prev may have moved to another CPU. + */ +static struct rq *finish_task_switch(struct task_struct *prev) + __releases(rq->lock) +{ + struct rq *rq = this_rq(); + struct mm_struct *mm = rq->prev_mm; + long prev_state; + + /* + * The previous task will have left us with a preempt_count of 2 + * because it left us after: + * + * schedule() + * preempt_disable(); // 1 + * __schedule() + * raw_spin_lock_irq(&rq->lock) // 2 + * + * Also, see FORK_PREEMPT_COUNT. + */ + if (WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET, + "corrupted preempt_count: %s/%d/0x%x\n", + current->comm, current->pid, preempt_count())) + preempt_count_set(FORK_PREEMPT_COUNT); + + rq->prev_mm = NULL; + + /* + * A task struct has one reference for the use as "current". + * If a task dies, then it sets TASK_DEAD in tsk->state and calls + * schedule one last time. The schedule call will never return, and + * the scheduled task must drop that reference. + * + * We must observe prev->state before clearing prev->on_cpu (in + * finish_task), otherwise a concurrent wakeup can get prev + * running on another CPU and we could rave with its RUNNING -> DEAD + * transition, resulting in a double drop. + */ + prev_state = prev->state; + vtime_task_switch(prev); + perf_event_task_sched_in(prev, current); + finish_task(prev); + finish_lock_switch(rq); + finish_arch_post_lock_switch(); + kcov_finish_switch(current); + /* + * kmap_local_sched_out() is invoked with rq::lock held and + * interrupts disabled. There is no requirement for that, but the + * sched out code does not have an interrupt enabled section. + * Restoring the maps on sched in does not require interrupts being + * disabled either. + */ + kmap_local_sched_in(); + + fire_sched_in_preempt_notifiers(current); + /* + * When switching through a kernel thread, the loop in + * membarrier_{private,global}_expedited() may have observed that + * kernel thread and not issued an IPI. It is therefore possible to + * schedule between user->kernel->user threads without passing though + * switch_mm(). Membarrier requires a barrier after storing to + * rq->curr, before returning to userspace, so provide them here: + * + * - a full memory barrier for {PRIVATE,GLOBAL}_EXPEDITED, implicitly + * provided by mmdrop(), + * - a sync_core for SYNC_CORE. + */ + if (mm) { + membarrier_mm_sync_core_before_usermode(mm); + mmdrop(mm); + } + if (unlikely(prev_state == TASK_DEAD)) { + /* + * Remove function-return probe instances associated with this + * task and put them back on the free list. + */ + kprobe_flush_task(prev); + + /* Task is done with its stack. */ + put_task_stack(prev); + + put_task_struct_rcu_user(prev); + } + + tick_nohz_task_switch(); + return rq; +} + +/** + * schedule_tail - first thing a freshly forked thread must call. + * @prev: the thread we just switched away from. + */ +asmlinkage __visible void schedule_tail(struct task_struct *prev) + __releases(rq->lock) +{ + struct rq *rq; + + /* + * New tasks start with FORK_PREEMPT_COUNT, see there and + * finish_task_switch() for details. + * + * finish_task_switch() will drop rq->lock() and lower preempt_count + * and the preempt_enable() will end up enabling preemption (on + * PREEMPT_COUNT kernels). + */ + + rq = finish_task_switch(prev); + preempt_enable(); + + if (current->set_child_tid) + put_user(task_pid_vnr(current), current->set_child_tid); + + calculate_sigpending(); +} + +/* + * context_switch - switch to the new MM and the new thread's register state. + */ +static __always_inline struct rq * +context_switch(struct rq *rq, struct task_struct *prev, + struct task_struct *next) +{ + prepare_task_switch(rq, prev, next); + + /* + * For paravirt, this is coupled with an exit in switch_to to + * combine the page table reload and the switch backend into + * one hypercall. + */ + arch_start_context_switch(prev); + + /* + * kernel -> kernel lazy + transfer active + * user -> kernel lazy + mmgrab() active + * + * kernel -> user switch + mmdrop() active + * user -> user switch + */ + if (!next->mm) { // to kernel + enter_lazy_tlb(prev->active_mm, next); + + next->active_mm = prev->active_mm; + if (prev->mm) // from user + mmgrab(prev->active_mm); + else + prev->active_mm = NULL; + } else { // to user + membarrier_switch_mm(rq, prev->active_mm, next->mm); + /* + * sys_membarrier() requires an smp_mb() between setting + * rq->curr / membarrier_switch_mm() and returning to userspace. + * + * The below provides this either through switch_mm(), or in + * case 'prev->active_mm == next->mm' through + * finish_task_switch()'s mmdrop(). + */ + switch_mm_irqs_off(prev->active_mm, next->mm, next); + + if (!prev->mm) { // from kernel + /* will mmdrop() in finish_task_switch(). */ + rq->prev_mm = prev->active_mm; + prev->active_mm = NULL; + } + } + + prepare_lock_switch(rq, next); + + /* Here we just switch the register state and the stack. */ + switch_to(prev, next, prev); + barrier(); + + return finish_task_switch(prev); +} + +/* + * nr_running, nr_uninterruptible and nr_context_switches: + * + * externally visible scheduler statistics: current number of runnable + * threads, total number of context switches performed since bootup. + */ +unsigned long nr_running(void) +{ + unsigned long i, sum = 0; + + for_each_online_cpu(i) + sum += cpu_rq(i)->nr_running; + + return sum; +} + +/* + * Check if only the current task is running on the CPU. + * + * Caution: this function does not check that the caller has disabled + * preemption, thus the result might have a time-of-check-to-time-of-use + * race. The caller is responsible to use it correctly, for example: + * + * - from a non-preemptible section (of course) + * + * - from a thread that is bound to a single CPU + * + * - in a loop with very short iterations (e.g. a polling loop) + */ +bool single_task_running(void) +{ + return raw_rq()->nr_running == 1; +} +EXPORT_SYMBOL(single_task_running); + +unsigned long long nr_context_switches(void) +{ + int i; + unsigned long long sum = 0; + + for_each_possible_cpu(i) + sum += cpu_rq(i)->nr_switches; + + return sum; +} + +/* + * Consumers of these two interfaces, like for example the cpuidle menu + * governor, are using nonsensical data. Preferring shallow idle state selection + * for a CPU that has IO-wait which might not even end up running the task when + * it does become runnable. + */ + +unsigned long nr_iowait_cpu(int cpu) +{ + return atomic_read(&cpu_rq(cpu)->nr_iowait); +} + +/* + * IO-wait accounting, and how it's mostly bollocks (on SMP). + * + * The idea behind IO-wait account is to account the idle time that we could + * have spend running if it were not for IO. That is, if we were to improve the + * storage performance, we'd have a proportional reduction in IO-wait time. + * + * This all works nicely on UP, where, when a task blocks on IO, we account + * idle time as IO-wait, because if the storage were faster, it could've been + * running and we'd not be idle. + * + * This has been extended to SMP, by doing the same for each CPU. This however + * is broken. + * + * Imagine for instance the case where two tasks block on one CPU, only the one + * CPU will have IO-wait accounted, while the other has regular idle. Even + * though, if the storage were faster, both could've ran at the same time, + * utilising both CPUs. + * + * This means, that when looking globally, the current IO-wait accounting on + * SMP is a lower bound, by reason of under accounting. + * + * Worse, since the numbers are provided per CPU, they are sometimes + * interpreted per CPU, and that is nonsensical. A blocked task isn't strictly + * associated with any one particular CPU, it can wake to another CPU than it + * blocked on. This means the per CPU IO-wait number is meaningless. + * + * Task CPU affinities can make all that even more 'interesting'. + */ + +unsigned long nr_iowait(void) +{ + unsigned long i, sum = 0; + + for_each_possible_cpu(i) + sum += nr_iowait_cpu(i); + + return sum; +} + +#ifdef CONFIG_SMP + +/* + * sched_exec - execve() is a valuable balancing opportunity, because at + * this point the task has the smallest effective memory and cache + * footprint. + */ +void sched_exec(void) +{ + struct task_struct *p = current; + unsigned long flags; + int dest_cpu; + struct rq *rq; + + raw_spin_lock_irqsave(&p->pi_lock, flags); + rq = this_rq(); + + if (rq != task_rq(p) || rq->nr_running < 2) + goto unlock; + + dest_cpu = select_task_rq(p, task_rq(p)); + if (dest_cpu == smp_processor_id()) + goto unlock; + + if (likely(cpu_active(dest_cpu))) { + struct migration_arg arg = { p, dest_cpu }; + + raw_spin_unlock_irqrestore(&p->pi_lock, flags); + stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg); + return; + } +unlock: + raw_spin_unlock_irqrestore(&p->pi_lock, flags); +} + +#endif + +DEFINE_PER_CPU(struct kernel_stat, kstat); +DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat); + +EXPORT_PER_CPU_SYMBOL(kstat); +EXPORT_PER_CPU_SYMBOL(kernel_cpustat); + +static inline void update_curr(struct rq *rq, struct task_struct *p) +{ + s64 ns = rq->clock_task - p->last_ran; + + p->sched_time += ns; + account_group_exec_runtime(p, ns); + + p->time_slice -= ns; + p->last_ran = rq->clock_task; +} + +/* + * Return accounted runtime for the task. + * Return separately the current's pending runtime that have not been + * accounted yet. + */ +unsigned long long task_sched_runtime(struct task_struct *p) +{ + unsigned long flags; + struct rq *rq; + raw_spinlock_t *lock; + u64 ns; + +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP) + /* + * 64-bit doesn't need locks to atomically read a 64-bit value. + * So we have a optimization chance when the task's delta_exec is 0. + * Reading ->on_cpu is racy, but this is ok. + * + * If we race with it leaving CPU, we'll take a lock. So we're correct. + * If we race with it entering CPU, unaccounted time is 0. This is + * indistinguishable from the read occurring a few cycles earlier. + * If we see ->on_cpu without ->on_rq, the task is leaving, and has + * been accounted, so we're correct here as well. + */ + if (!p->on_cpu || !task_on_rq_queued(p)) + return tsk_seruntime(p); +#endif + + rq = task_access_lock_irqsave(p, &lock, &flags); + /* + * Must be ->curr _and_ ->on_rq. If dequeued, we would + * project cycles that may never be accounted to this + * thread, breaking clock_gettime(). + */ + if (p == rq->curr && task_on_rq_queued(p)) { + update_rq_clock(rq); + update_curr(rq, p); + } + ns = tsk_seruntime(p); + task_access_unlock_irqrestore(p, lock, &flags); + + return ns; +} + +/* This manages tasks that have run out of timeslice during a scheduler_tick */ +static inline void scheduler_task_tick(struct rq *rq) +{ + struct task_struct *p = rq->curr; + + if (is_idle_task(p)) + return; + + update_curr(rq, p); + cpufreq_update_util(rq, 0); + + /* + * Tasks have less than RESCHED_NS of time slice left they will be + * rescheduled. + */ + if (p->time_slice >= RESCHED_NS) + return; + set_tsk_need_resched(p); + set_preempt_need_resched(); +} + +/* + * This function gets called by the timer code, with HZ frequency. + * We call it with interrupts disabled. + */ +void scheduler_tick(void) +{ + int cpu __maybe_unused = smp_processor_id(); + struct rq *rq = cpu_rq(cpu); + + arch_scale_freq_tick(); + sched_clock_tick(); + + raw_spin_lock(&rq->lock); + update_rq_clock(rq); + + scheduler_task_tick(rq); + calc_global_load_tick(rq); + psi_task_tick(rq); + + rq->last_tick = rq->clock; + raw_spin_unlock(&rq->lock); + + perf_event_task_tick(); +} + +#ifdef CONFIG_SCHED_SMT +static inline int active_load_balance_cpu_stop(void *data) +{ + struct rq *rq = this_rq(); + struct task_struct *p = data; + cpumask_t tmp; + unsigned long flags; + + local_irq_save(flags); + + raw_spin_lock(&p->pi_lock); + raw_spin_lock(&rq->lock); + + rq->active_balance = 0; + /* _something_ may have changed the task, double check again */ + if (task_on_rq_queued(p) && task_rq(p) == rq && + cpumask_and(&tmp, p->cpus_ptr, &sched_sg_idle_mask) && + !is_migration_disabled(p)) { + int cpu = cpu_of(rq); + int dcpu = __best_mask_cpu(cpu, &tmp, + per_cpu(sched_cpu_llc_mask, cpu)); + rq = move_queued_task(rq, p, dcpu); + } + + raw_spin_unlock(&rq->lock); + raw_spin_unlock(&p->pi_lock); + + local_irq_restore(flags); + + return 0; +} + +/* sg_balance_trigger - trigger slibing group balance for @cpu */ +static inline int sg_balance_trigger(const int cpu) +{ + struct rq *rq= cpu_rq(cpu); + unsigned long flags; + struct task_struct *curr; + int res; + + if (!raw_spin_trylock_irqsave(&rq->lock, flags)) + return 0; + curr = rq->curr; + res = (!is_idle_task(curr)) && (1 == rq->nr_running) &&\ + cpumask_intersects(curr->cpus_ptr, &sched_sg_idle_mask) &&\ + !is_migration_disabled(curr) && (!rq->active_balance); + + if (res) + rq->active_balance = 1; + + raw_spin_unlock_irqrestore(&rq->lock, flags); + + if (res) + stop_one_cpu_nowait(cpu, active_load_balance_cpu_stop, + curr, &rq->active_balance_work); + return res; +} + +/* + * sg_balance_check - slibing group balance check for run queue @rq + */ +static inline void sg_balance_check(struct rq *rq) +{ + cpumask_t chk; + int cpu; + + /* exit when no sg in idle */ + if (cpumask_empty(&sched_sg_idle_mask)) + return; + + cpu = cpu_of(rq); + /* + * Only cpu in slibing idle group will do the checking and then + * find potential cpus which can migrate the current running task + */ + if (cpumask_test_cpu(cpu, &sched_sg_idle_mask) && + cpumask_andnot(&chk, cpu_online_mask, &sched_rq_pending_mask) && + cpumask_andnot(&chk, &chk, &sched_rq_watermark[IDLE_WM])) { + int i, tried = 0; + + for_each_cpu_wrap(i, &chk, cpu) { + if (cpumask_subset(cpu_smt_mask(i), &chk)) { + if (sg_balance_trigger(i)) + return; + if (tried) + return; + tried++; + } + } + } +} +#endif /* CONFIG_SCHED_SMT */ + +#ifdef CONFIG_NO_HZ_FULL + +struct tick_work { + int cpu; + atomic_t state; + struct delayed_work work; +}; +/* Values for ->state, see diagram below. */ +#define TICK_SCHED_REMOTE_OFFLINE 0 +#define TICK_SCHED_REMOTE_OFFLINING 1 +#define TICK_SCHED_REMOTE_RUNNING 2 + +/* + * State diagram for ->state: + * + * + * TICK_SCHED_REMOTE_OFFLINE + * | ^ + * | | + * | | sched_tick_remote() + * | | + * | | + * +--TICK_SCHED_REMOTE_OFFLINING + * | ^ + * | | + * sched_tick_start() | | sched_tick_stop() + * | | + * V | + * TICK_SCHED_REMOTE_RUNNING + * + * + * Other transitions get WARN_ON_ONCE(), except that sched_tick_remote() + * and sched_tick_start() are happy to leave the state in RUNNING. + */ + +static struct tick_work __percpu *tick_work_cpu; + +static void sched_tick_remote(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct tick_work *twork = container_of(dwork, struct tick_work, work); + int cpu = twork->cpu; + struct rq *rq = cpu_rq(cpu); + struct task_struct *curr; + unsigned long flags; + u64 delta; + int os; + + /* + * Handle the tick only if it appears the remote CPU is running in full + * dynticks mode. The check is racy by nature, but missing a tick or + * having one too much is no big deal because the scheduler tick updates + * statistics and checks timeslices in a time-independent way, regardless + * of when exactly it is running. + */ + if (!tick_nohz_tick_stopped_cpu(cpu)) + goto out_requeue; + + raw_spin_lock_irqsave(&rq->lock, flags); + curr = rq->curr; + if (cpu_is_offline(cpu)) + goto out_unlock; + + update_rq_clock(rq); + if (!is_idle_task(curr)) { + /* + * Make sure the next tick runs within a reasonable + * amount of time. + */ + delta = rq_clock_task(rq) - curr->last_ran; + WARN_ON_ONCE(delta > (u64)NSEC_PER_SEC * 3); + } + scheduler_task_tick(rq); + + calc_load_nohz_remote(rq); +out_unlock: + raw_spin_unlock_irqrestore(&rq->lock, flags); + +out_requeue: + /* + * Run the remote tick once per second (1Hz). This arbitrary + * frequency is large enough to avoid overload but short enough + * to keep scheduler internal stats reasonably up to date. But + * first update state to reflect hotplug activity if required. + */ + os = atomic_fetch_add_unless(&twork->state, -1, TICK_SCHED_REMOTE_RUNNING); + WARN_ON_ONCE(os == TICK_SCHED_REMOTE_OFFLINE); + if (os == TICK_SCHED_REMOTE_RUNNING) + queue_delayed_work(system_unbound_wq, dwork, HZ); +} + +static void sched_tick_start(int cpu) +{ + int os; + struct tick_work *twork; + + if (housekeeping_cpu(cpu, HK_FLAG_TICK)) + return; + + WARN_ON_ONCE(!tick_work_cpu); + + twork = per_cpu_ptr(tick_work_cpu, cpu); + os = atomic_xchg(&twork->state, TICK_SCHED_REMOTE_RUNNING); + WARN_ON_ONCE(os == TICK_SCHED_REMOTE_RUNNING); + if (os == TICK_SCHED_REMOTE_OFFLINE) { + twork->cpu = cpu; + INIT_DELAYED_WORK(&twork->work, sched_tick_remote); + queue_delayed_work(system_unbound_wq, &twork->work, HZ); + } +} + +#ifdef CONFIG_HOTPLUG_CPU +static void sched_tick_stop(int cpu) +{ + struct tick_work *twork; + + if (housekeeping_cpu(cpu, HK_FLAG_TICK)) + return; + + WARN_ON_ONCE(!tick_work_cpu); + + twork = per_cpu_ptr(tick_work_cpu, cpu); + cancel_delayed_work_sync(&twork->work); +} +#endif /* CONFIG_HOTPLUG_CPU */ + +int __init sched_tick_offload_init(void) +{ + tick_work_cpu = alloc_percpu(struct tick_work); + BUG_ON(!tick_work_cpu); + return 0; +} + +#else /* !CONFIG_NO_HZ_FULL */ +static inline void sched_tick_start(int cpu) { } +static inline void sched_tick_stop(int cpu) { } +#endif + +#if defined(CONFIG_PREEMPTION) && (defined(CONFIG_DEBUG_PREEMPT) || \ + defined(CONFIG_PREEMPT_TRACER)) +/* + * If the value passed in is equal to the current preempt count + * then we just disabled preemption. Start timing the latency. + */ +static inline void preempt_latency_start(int val) +{ + if (preempt_count() == val) { + unsigned long ip = get_lock_parent_ip(); +#ifdef CONFIG_DEBUG_PREEMPT + current->preempt_disable_ip = ip; +#endif + trace_preempt_off(CALLER_ADDR0, ip); + } +} + +void preempt_count_add(int val) +{ +#ifdef CONFIG_DEBUG_PREEMPT + /* + * Underflow? + */ + if (DEBUG_LOCKS_WARN_ON((preempt_count() < 0))) + return; +#endif + __preempt_count_add(val); +#ifdef CONFIG_DEBUG_PREEMPT + /* + * Spinlock count overflowing soon? + */ + DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >= + PREEMPT_MASK - 10); +#endif + preempt_latency_start(val); +} +EXPORT_SYMBOL(preempt_count_add); +NOKPROBE_SYMBOL(preempt_count_add); + +/* + * If the value passed in equals to the current preempt count + * then we just enabled preemption. Stop timing the latency. + */ +static inline void preempt_latency_stop(int val) +{ + if (preempt_count() == val) + trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip()); +} + +void preempt_count_sub(int val) +{ +#ifdef CONFIG_DEBUG_PREEMPT + /* + * Underflow? + */ + if (DEBUG_LOCKS_WARN_ON(val > preempt_count())) + return; + /* + * Is the spinlock portion underflowing? + */ + if (DEBUG_LOCKS_WARN_ON((val < PREEMPT_MASK) && + !(preempt_count() & PREEMPT_MASK))) + return; +#endif + + preempt_latency_stop(val); + __preempt_count_sub(val); +} +EXPORT_SYMBOL(preempt_count_sub); +NOKPROBE_SYMBOL(preempt_count_sub); + +#else +static inline void preempt_latency_start(int val) { } +static inline void preempt_latency_stop(int val) { } +#endif + +static inline unsigned long get_preempt_disable_ip(struct task_struct *p) +{ +#ifdef CONFIG_DEBUG_PREEMPT + return p->preempt_disable_ip; +#else + return 0; +#endif +} + +/* + * Print scheduling while atomic bug: + */ +static noinline void __schedule_bug(struct task_struct *prev) +{ + /* Save this before calling printk(), since that will clobber it */ + unsigned long preempt_disable_ip = get_preempt_disable_ip(current); + + if (oops_in_progress) + return; + + printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n", + prev->comm, prev->pid, preempt_count()); + + debug_show_held_locks(prev); + print_modules(); + if (irqs_disabled()) + print_irqtrace_events(prev); + if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) + && in_atomic_preempt_off()) { + pr_err("Preemption disabled at:"); + print_ip_sym(KERN_ERR, preempt_disable_ip); + } + if (panic_on_warn) + panic("scheduling while atomic\n"); + + dump_stack(); + add_taint(TAINT_WARN, LOCKDEP_STILL_OK); +} + +/* + * Various schedule()-time debugging checks and statistics: + */ +static inline void schedule_debug(struct task_struct *prev, bool preempt) +{ +#ifdef CONFIG_SCHED_STACK_END_CHECK + if (task_stack_end_corrupted(prev)) + panic("corrupted stack end detected inside scheduler\n"); + + if (task_scs_end_corrupted(prev)) + panic("corrupted shadow stack detected inside scheduler\n"); +#endif + +#ifdef CONFIG_DEBUG_ATOMIC_SLEEP + if (!preempt && prev->state && prev->non_block_count) { + printk(KERN_ERR "BUG: scheduling in a non-blocking section: %s/%d/%i\n", + prev->comm, prev->pid, prev->non_block_count); + dump_stack(); + add_taint(TAINT_WARN, LOCKDEP_STILL_OK); + } +#endif + + if (unlikely(in_atomic_preempt_off())) { + __schedule_bug(prev); + preempt_count_set(PREEMPT_DISABLED); + } + rcu_sleep_check(); + SCHED_WARN_ON(ct_state() == CONTEXT_USER); + + profile_hit(SCHED_PROFILING, __builtin_return_address(0)); + + schedstat_inc(this_rq()->sched_count); +} + +/* + * Compile time debug macro + * #define ALT_SCHED_DEBUG + */ + +#ifdef ALT_SCHED_DEBUG +void alt_sched_debug(void) +{ + printk(KERN_INFO "sched: pending: 0x%04lx, idle: 0x%04lx, sg_idle: 0x%04lx\n", + sched_rq_pending_mask.bits[0], + sched_rq_watermark[IDLE_WM].bits[0], + sched_sg_idle_mask.bits[0]); +} +#else +inline void alt_sched_debug(void) {} +#endif + +#ifdef CONFIG_SMP + +#define SCHED_RQ_NR_MIGRATION (32U) +/* + * Migrate pending tasks in @rq to @dest_cpu + * Will try to migrate mininal of half of @rq nr_running tasks and + * SCHED_RQ_NR_MIGRATION to @dest_cpu + */ +static inline int +migrate_pending_tasks(struct rq *rq, struct rq *dest_rq, const int dest_cpu) +{ + struct task_struct *p, *skip = rq->curr; + int nr_migrated = 0; + int nr_tries = min(rq->nr_running / 2, SCHED_RQ_NR_MIGRATION); + + while (skip != rq->idle && nr_tries && + (p = sched_rq_next_task(skip, rq)) != rq->idle) { + skip = sched_rq_next_task(p, rq); + if (cpumask_test_cpu(dest_cpu, p->cpus_ptr)) { + __SCHED_DEQUEUE_TASK(p, rq, 0, ); + set_task_cpu(p, dest_cpu); + __SCHED_ENQUEUE_TASK(p, dest_rq, 0); + nr_migrated++; + } + nr_tries--; + } + + return nr_migrated; +} + +static inline int take_other_rq_tasks(struct rq *rq, int cpu) +{ + struct cpumask *affinity_mask, *end_mask; + + if (unlikely(!rq->online)) + return 0; + + if (cpumask_empty(&sched_rq_pending_mask)) + return 0; + + affinity_mask = per_cpu(sched_cpu_affinity_masks, cpu) + 1; + end_mask = per_cpu(sched_cpu_affinity_end_mask, cpu); + do { + int i; + for_each_cpu_and(i, &sched_rq_pending_mask, affinity_mask) { + int nr_migrated; + struct rq *src_rq; + + src_rq = cpu_rq(i); + if (!do_raw_spin_trylock(&src_rq->lock)) + continue; + spin_acquire(&src_rq->lock.dep_map, + SINGLE_DEPTH_NESTING, 1, _RET_IP_); + + if ((nr_migrated = migrate_pending_tasks(src_rq, rq, cpu))) { + src_rq->nr_running -= nr_migrated; +#ifdef CONFIG_SMP + if (src_rq->nr_running < 2) + cpumask_clear_cpu(i, &sched_rq_pending_mask); +#endif + rq->nr_running += nr_migrated; +#ifdef CONFIG_SMP + if (rq->nr_running > 1) + cpumask_set_cpu(cpu, &sched_rq_pending_mask); +#endif + update_sched_rq_watermark(rq); + cpufreq_update_util(rq, 0); + + spin_release(&src_rq->lock.dep_map, _RET_IP_); + do_raw_spin_unlock(&src_rq->lock); + + return 1; + } + + spin_release(&src_rq->lock.dep_map, _RET_IP_); + do_raw_spin_unlock(&src_rq->lock); + } + } while (++affinity_mask < end_mask); + + return 0; +} +#endif + +/* + * Timeslices below RESCHED_NS are considered as good as expired as there's no + * point rescheduling when there's so little time left. + */ +static inline void check_curr(struct task_struct *p, struct rq *rq) +{ + if (unlikely(rq->idle == p)) + return; + + update_curr(rq, p); + + if (p->time_slice < RESCHED_NS) + time_slice_expired(p, rq); +} + +static inline struct task_struct * +choose_next_task(struct rq *rq, int cpu, struct task_struct *prev) +{ + struct task_struct *next; + + if (unlikely(rq->skip)) { + next = rq_runnable_task(rq); + if (next == rq->idle) { +#ifdef CONFIG_SMP + if (!take_other_rq_tasks(rq, cpu)) { +#endif + rq->skip = NULL; + schedstat_inc(rq->sched_goidle); + return next; +#ifdef CONFIG_SMP + } + next = rq_runnable_task(rq); +#endif + } + rq->skip = NULL; +#ifdef CONFIG_HIGH_RES_TIMERS + hrtick_start(rq, next->time_slice); +#endif + return next; + } + + next = sched_rq_first_task(rq); + if (next == rq->idle) { +#ifdef CONFIG_SMP + if (!take_other_rq_tasks(rq, cpu)) { +#endif + schedstat_inc(rq->sched_goidle); + /*printk(KERN_INFO "sched: choose_next_task(%d) idle %px\n", cpu, next);*/ + return next; +#ifdef CONFIG_SMP + } + next = sched_rq_first_task(rq); +#endif + } +#ifdef CONFIG_HIGH_RES_TIMERS + hrtick_start(rq, next->time_slice); +#endif + /*printk(KERN_INFO "sched: choose_next_task(%d) next %px\n", cpu, + * next);*/ + return next; +} + +/* + * schedule() is the main scheduler function. + * + * The main means of driving the scheduler and thus entering this function are: + * + * 1. Explicit blocking: mutex, semaphore, waitqueue, etc. + * + * 2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return + * paths. For example, see arch/x86/entry_64.S. + * + * To drive preemption between tasks, the scheduler sets the flag in timer + * interrupt handler scheduler_tick(). + * + * 3. Wakeups don't really cause entry into schedule(). They add a + * task to the run-queue and that's it. + * + * Now, if the new task added to the run-queue preempts the current + * task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets + * called on the nearest possible occasion: + * + * - If the kernel is preemptible (CONFIG_PREEMPTION=y): + * + * - in syscall or exception context, at the next outmost + * preempt_enable(). (this might be as soon as the wake_up()'s + * spin_unlock()!) + * + * - in IRQ context, return from interrupt-handler to + * preemptible context + * + * - If the kernel is not preemptible (CONFIG_PREEMPTION is not set) + * then at the next: + * + * - cond_resched() call + * - explicit schedule() call + * - return from syscall or exception to user-space + * - return from interrupt-handler to user-space + * + * WARNING: must be called with preemption disabled! + */ +static void __sched notrace __schedule(bool preempt) +{ + struct task_struct *prev, *next; + unsigned long *switch_count; + unsigned long prev_state; + struct rq *rq; + int cpu; + + cpu = smp_processor_id(); + rq = cpu_rq(cpu); + prev = rq->curr; + + schedule_debug(prev, preempt); + + /* by passing sched_feat(HRTICK) checking which Alt schedule FW doesn't support */ + hrtick_clear(rq); + + local_irq_disable(); + rcu_note_context_switch(preempt); + + /* + * Make sure that signal_pending_state()->signal_pending() below + * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE) + * done by the caller to avoid the race with signal_wake_up(): + * + * __set_current_state(@state) signal_wake_up() + * schedule() set_tsk_thread_flag(p, TIF_SIGPENDING) + * wake_up_state(p, state) + * LOCK rq->lock LOCK p->pi_state + * smp_mb__after_spinlock() smp_mb__after_spinlock() + * if (signal_pending_state()) if (p->state & @state) + * + * Also, the membarrier system call requires a full memory barrier + * after coming from user-space, before storing to rq->curr. + */ + raw_spin_lock(&rq->lock); + smp_mb__after_spinlock(); + + update_rq_clock(rq); + + switch_count = &prev->nivcsw; + /* + * We must load prev->state once (task_struct::state is volatile), such + * that: + * + * - we form a control dependency vs deactivate_task() below. + * - ptrace_{,un}freeze_traced() can change ->state underneath us. + */ + prev_state = prev->state; + if (!preempt && prev_state && prev_state == prev->state) { + if (signal_pending_state(prev_state, prev)) { + prev->state = TASK_RUNNING; + } else { + prev->sched_contributes_to_load = + (prev_state & TASK_UNINTERRUPTIBLE) && + !(prev_state & TASK_NOLOAD) && + !(prev->flags & PF_FROZEN); + + if (prev->sched_contributes_to_load) + rq->nr_uninterruptible++; + + /* + * __schedule() ttwu() + * prev_state = prev->state; if (p->on_rq && ...) + * if (prev_state) goto out; + * p->on_rq = 0; smp_acquire__after_ctrl_dep(); + * p->state = TASK_WAKING + * + * Where __schedule() and ttwu() have matching control dependencies. + * + * After this, schedule() must not care about p->state any more. + */ + sched_task_deactivate(prev, rq); + deactivate_task(prev, rq); + + if (prev->in_iowait) { + atomic_inc(&rq->nr_iowait); + delayacct_blkio_start(); + } + } + switch_count = &prev->nvcsw; + } + + check_curr(prev, rq); + + next = choose_next_task(rq, cpu, prev); + clear_tsk_need_resched(prev); + clear_preempt_need_resched(); + + + if (likely(prev != next)) { + next->last_ran = rq->clock_task; + rq->last_ts_switch = rq->clock; + + rq->nr_switches++; + /* + * RCU users of rcu_dereference(rq->curr) may not see + * changes to task_struct made by pick_next_task(). + */ + RCU_INIT_POINTER(rq->curr, next); + /* + * The membarrier system call requires each architecture + * to have a full memory barrier after updating + * rq->curr, before returning to user-space. + * + * Here are the schemes providing that barrier on the + * various architectures: + * - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC. + * switch_mm() rely on membarrier_arch_switch_mm() on PowerPC. + * - finish_lock_switch() for weakly-ordered + * architectures where spin_unlock is a full barrier, + * - switch_to() for arm64 (weakly-ordered, spin_unlock + * is a RELEASE barrier), + */ + ++*switch_count; + + psi_sched_switch(prev, next, !task_on_rq_queued(prev)); + + trace_sched_switch(preempt, prev, next); + + /* Also unlocks the rq: */ + rq = context_switch(rq, prev, next); + } else { + __balance_callbacks(rq); + raw_spin_unlock_irq(&rq->lock); + } + +#ifdef CONFIG_SCHED_SMT + sg_balance_check(rq); +#endif +} + +void __noreturn do_task_dead(void) +{ + /* Causes final put_task_struct in finish_task_switch(): */ + set_special_state(TASK_DEAD); + + /* Tell freezer to ignore us: */ + current->flags |= PF_NOFREEZE; + + __schedule(false); + BUG(); + + /* Avoid "noreturn function does return" - but don't continue if BUG() is a NOP: */ + for (;;) + cpu_relax(); +} + +static inline void sched_submit_work(struct task_struct *tsk) +{ + unsigned int task_flags; + + if (!tsk->state) + return; + + task_flags = tsk->flags; + /* + * If a worker went to sleep, notify and ask workqueue whether + * it wants to wake up a task to maintain concurrency. + * As this function is called inside the schedule() context, + * we disable preemption to avoid it calling schedule() again + * in the possible wakeup of a kworker and because wq_worker_sleeping() + * requires it. + */ + if (task_flags & (PF_WQ_WORKER | PF_IO_WORKER)) { + preempt_disable(); + if (task_flags & PF_WQ_WORKER) + wq_worker_sleeping(tsk); + else + io_wq_worker_sleeping(tsk); + preempt_enable_no_resched(); + } + + if (tsk_is_pi_blocked(tsk)) + return; + + /* + * If we are going to sleep and we have plugged IO queued, + * make sure to submit it to avoid deadlocks. + */ + if (blk_needs_flush_plug(tsk)) + blk_schedule_flush_plug(tsk); +} + +static void sched_update_worker(struct task_struct *tsk) +{ + if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) { + if (tsk->flags & PF_WQ_WORKER) + wq_worker_running(tsk); + else + io_wq_worker_running(tsk); + } +} + +asmlinkage __visible void __sched schedule(void) +{ + struct task_struct *tsk = current; + + sched_submit_work(tsk); + do { + preempt_disable(); + __schedule(false); + sched_preempt_enable_no_resched(); + } while (need_resched()); + sched_update_worker(tsk); +} +EXPORT_SYMBOL(schedule); + +/* + * synchronize_rcu_tasks() makes sure that no task is stuck in preempted + * state (have scheduled out non-voluntarily) by making sure that all + * tasks have either left the run queue or have gone into user space. + * As idle tasks do not do either, they must not ever be preempted + * (schedule out non-voluntarily). + * + * schedule_idle() is similar to schedule_preempt_disable() except that it + * never enables preemption because it does not call sched_submit_work(). + */ +void __sched schedule_idle(void) +{ + /* + * As this skips calling sched_submit_work(), which the idle task does + * regardless because that function is a nop when the task is in a + * TASK_RUNNING state, make sure this isn't used someplace that the + * current task can be in any other state. Note, idle is always in the + * TASK_RUNNING state. + */ + WARN_ON_ONCE(current->state); + do { + __schedule(false); + } while (need_resched()); +} + +#if defined(CONFIG_CONTEXT_TRACKING) && !defined(CONFIG_HAVE_CONTEXT_TRACKING_OFFSTACK) +asmlinkage __visible void __sched schedule_user(void) +{ + /* + * If we come here after a random call to set_need_resched(), + * or we have been woken up remotely but the IPI has not yet arrived, + * we haven't yet exited the RCU idle mode. Do it here manually until + * we find a better solution. + * + * NB: There are buggy callers of this function. Ideally we + * should warn if prev_state != CONTEXT_USER, but that will trigger + * too frequently to make sense yet. + */ + enum ctx_state prev_state = exception_enter(); + schedule(); + exception_exit(prev_state); +} +#endif + +/** + * schedule_preempt_disabled - called with preemption disabled + * + * Returns with preemption disabled. Note: preempt_count must be 1 + */ +void __sched schedule_preempt_disabled(void) +{ + sched_preempt_enable_no_resched(); + schedule(); + preempt_disable(); +} + +static void __sched notrace preempt_schedule_common(void) +{ + do { + /* + * Because the function tracer can trace preempt_count_sub() + * and it also uses preempt_enable/disable_notrace(), if + * NEED_RESCHED is set, the preempt_enable_notrace() called + * by the function tracer will call this function again and + * cause infinite recursion. + * + * Preemption must be disabled here before the function + * tracer can trace. Break up preempt_disable() into two + * calls. One to disable preemption without fear of being + * traced. The other to still record the preemption latency, + * which can also be traced by the function tracer. + */ + preempt_disable_notrace(); + preempt_latency_start(1); + __schedule(true); + preempt_latency_stop(1); + preempt_enable_no_resched_notrace(); + + /* + * Check again in case we missed a preemption opportunity + * between schedule and now. + */ + } while (need_resched()); +} + +#ifdef CONFIG_PREEMPTION +/* + * This is the entry point to schedule() from in-kernel preemption + * off of preempt_enable. + */ +asmlinkage __visible void __sched notrace preempt_schedule(void) +{ + /* + * If there is a non-zero preempt_count or interrupts are disabled, + * we do not want to preempt the current task. Just return.. + */ + if (likely(!preemptible())) + return; + + preempt_schedule_common(); +} +NOKPROBE_SYMBOL(preempt_schedule); +EXPORT_SYMBOL(preempt_schedule); + +/** + * preempt_schedule_notrace - preempt_schedule called by tracing + * + * The tracing infrastructure uses preempt_enable_notrace to prevent + * recursion and tracing preempt enabling caused by the tracing + * infrastructure itself. But as tracing can happen in areas coming + * from userspace or just about to enter userspace, a preempt enable + * can occur before user_exit() is called. This will cause the scheduler + * to be called when the system is still in usermode. + * + * To prevent this, the preempt_enable_notrace will use this function + * instead of preempt_schedule() to exit user context if needed before + * calling the scheduler. + */ +asmlinkage __visible void __sched notrace preempt_schedule_notrace(void) +{ + enum ctx_state prev_ctx; + + if (likely(!preemptible())) + return; + + do { + /* + * Because the function tracer can trace preempt_count_sub() + * and it also uses preempt_enable/disable_notrace(), if + * NEED_RESCHED is set, the preempt_enable_notrace() called + * by the function tracer will call this function again and + * cause infinite recursion. + * + * Preemption must be disabled here before the function + * tracer can trace. Break up preempt_disable() into two + * calls. One to disable preemption without fear of being + * traced. The other to still record the preemption latency, + * which can also be traced by the function tracer. + */ + preempt_disable_notrace(); + preempt_latency_start(1); + /* + * Needs preempt disabled in case user_exit() is traced + * and the tracer calls preempt_enable_notrace() causing + * an infinite recursion. + */ + prev_ctx = exception_enter(); + __schedule(true); + exception_exit(prev_ctx); + + preempt_latency_stop(1); + preempt_enable_no_resched_notrace(); + } while (need_resched()); +} +EXPORT_SYMBOL_GPL(preempt_schedule_notrace); + +#endif /* CONFIG_PREEMPTION */ + +/* + * This is the entry point to schedule() from kernel preemption + * off of irq context. + * Note, that this is called and return with irqs disabled. This will + * protect us against recursive calling from irq. + */ +asmlinkage __visible void __sched preempt_schedule_irq(void) +{ + enum ctx_state prev_state; + + /* Catch callers which need to be fixed */ + BUG_ON(preempt_count() || !irqs_disabled()); + + prev_state = exception_enter(); + + do { + preempt_disable(); + local_irq_enable(); + __schedule(true); + local_irq_disable(); + sched_preempt_enable_no_resched(); + } while (need_resched()); + + exception_exit(prev_state); +} + +int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags, + void *key) +{ + WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~WF_SYNC); + return try_to_wake_up(curr->private, mode, wake_flags); +} +EXPORT_SYMBOL(default_wake_function); + +static inline void check_task_changed(struct rq *rq, struct task_struct *p) +{ + /* Trigger resched if task sched_prio has been modified. */ + if (task_on_rq_queued(p) && sched_task_need_requeue(p, rq)) { + requeue_task(p, rq); + check_preempt_curr(rq); + } +} + +#ifdef CONFIG_RT_MUTEXES + +static inline int __rt_effective_prio(struct task_struct *pi_task, int prio) +{ + if (pi_task) + prio = min(prio, pi_task->prio); + + return prio; +} + +static inline int rt_effective_prio(struct task_struct *p, int prio) +{ + struct task_struct *pi_task = rt_mutex_get_top_task(p); + + return __rt_effective_prio(pi_task, prio); +} + +/* + * rt_mutex_setprio - set the current priority of a task + * @p: task to boost + * @pi_task: donor task + * + * This function changes the 'effective' priority of a task. It does + * not touch ->normal_prio like __setscheduler(). + * + * Used by the rt_mutex code to implement priority inheritance + * logic. Call site only calls if the priority of the task changed. + */ +void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task) +{ + int prio; + struct rq *rq; + raw_spinlock_t *lock; + + /* XXX used to be waiter->prio, not waiter->task->prio */ + prio = __rt_effective_prio(pi_task, p->normal_prio); + + /* + * If nothing changed; bail early. + */ + if (p->pi_top_task == pi_task && prio == p->prio) + return; + + rq = __task_access_lock(p, &lock); + /* + * Set under pi_lock && rq->lock, such that the value can be used under + * either lock. + * + * Note that there is loads of tricky to make this pointer cache work + * right. rt_mutex_slowunlock()+rt_mutex_postunlock() work together to + * ensure a task is de-boosted (pi_task is set to NULL) before the + * task is allowed to run again (and can exit). This ensures the pointer + * points to a blocked task -- which guarantees the task is present. + */ + p->pi_top_task = pi_task; + + /* + * For FIFO/RR we only need to set prio, if that matches we're done. + */ + if (prio == p->prio) + goto out_unlock; + + /* + * Idle task boosting is a nono in general. There is one + * exception, when PREEMPT_RT and NOHZ is active: + * + * The idle task calls get_next_timer_interrupt() and holds + * the timer wheel base->lock on the CPU and another CPU wants + * to access the timer (probably to cancel it). We can safely + * ignore the boosting request, as the idle CPU runs this code + * with interrupts disabled and will complete the lock + * protected section without being interrupted. So there is no + * real need to boost. + */ + if (unlikely(p == rq->idle)) { + WARN_ON(p != rq->curr); + WARN_ON(p->pi_blocked_on); + goto out_unlock; + } + + trace_sched_pi_setprio(p, pi_task); + p->prio = prio; + update_task_priodl(p); + + check_task_changed(rq, p); +out_unlock: + /* Avoid rq from going away on us: */ + preempt_disable(); + + __balance_callbacks(rq); + __task_access_unlock(p, lock); + + preempt_enable(); +} +#else +static inline int rt_effective_prio(struct task_struct *p, int prio) +{ + return prio; +} +#endif + +void set_user_nice(struct task_struct *p, long nice) +{ + unsigned long flags; + struct rq *rq; + raw_spinlock_t *lock; + + if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE) + return; + /* + * We have to be careful, if called from sys_setpriority(), + * the task might be in the middle of scheduling on another CPU. + */ + raw_spin_lock_irqsave(&p->pi_lock, flags); + rq = __task_access_lock(p, &lock); + + p->static_prio = NICE_TO_PRIO(nice); + /* + * The RT priorities are set via sched_setscheduler(), but we still + * allow the 'normal' nice value to be set - but as expected + * it won't have any effect on scheduling until the task is + * not SCHED_NORMAL/SCHED_BATCH: + */ + if (task_has_rt_policy(p)) + goto out_unlock; + + p->prio = effective_prio(p); + update_task_priodl(p); + + check_task_changed(rq, p); +out_unlock: + __task_access_unlock(p, lock); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); +} +EXPORT_SYMBOL(set_user_nice); + +/* + * can_nice - check if a task can reduce its nice value + * @p: task + * @nice: nice value + */ +int can_nice(const struct task_struct *p, const int nice) +{ + /* Convert nice value [19,-20] to rlimit style value [1,40] */ + int nice_rlim = nice_to_rlimit(nice); + + return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) || + capable(CAP_SYS_NICE)); +} + +#ifdef __ARCH_WANT_SYS_NICE + +/* + * sys_nice - change the priority of the current process. + * @increment: priority increment + * + * sys_setpriority is a more generic, but much slower function that + * does similar things. + */ +SYSCALL_DEFINE1(nice, int, increment) +{ + long nice, retval; + + /* + * Setpriority might change our priority at the same moment. + * We don't have to worry. Conceptually one call occurs first + * and we have a single winner. + */ + + increment = clamp(increment, -NICE_WIDTH, NICE_WIDTH); + nice = task_nice(current) + increment; + + nice = clamp_val(nice, MIN_NICE, MAX_NICE); + if (increment < 0 && !can_nice(current, nice)) + return -EPERM; + + retval = security_task_setnice(current, nice); + if (retval) + return retval; + + set_user_nice(current, nice); + return 0; +} + +#endif + +/** + * idle_cpu - is a given CPU idle currently? + * @cpu: the processor in question. + * + * Return: 1 if the CPU is currently idle. 0 otherwise. + */ +int idle_cpu(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + if (rq->curr != rq->idle) + return 0; + + if (rq->nr_running) + return 0; + +#ifdef CONFIG_SMP + if (rq->ttwu_pending) + return 0; +#endif + + return 1; +} + +/** + * idle_task - return the idle task for a given CPU. + * @cpu: the processor in question. + * + * Return: The idle task for the cpu @cpu. + */ +struct task_struct *idle_task(int cpu) +{ + return cpu_rq(cpu)->idle; +} + +/** + * find_process_by_pid - find a process with a matching PID value. + * @pid: the pid in question. + * + * The task of @pid, if found. %NULL otherwise. + */ +static inline struct task_struct *find_process_by_pid(pid_t pid) +{ + return pid ? find_task_by_vpid(pid) : current; +} + +/* + * sched_setparam() passes in -1 for its policy, to let the functions + * it calls know not to change it. + */ +#define SETPARAM_POLICY -1 + +static void __setscheduler_params(struct task_struct *p, + const struct sched_attr *attr) +{ + int policy = attr->sched_policy; + + if (policy == SETPARAM_POLICY) + policy = p->policy; + + p->policy = policy; + + /* + * allow normal nice value to be set, but will not have any + * effect on scheduling until the task not SCHED_NORMAL/ + * SCHED_BATCH + */ + p->static_prio = NICE_TO_PRIO(attr->sched_nice); + + /* + * __sched_setscheduler() ensures attr->sched_priority == 0 when + * !rt_policy. Always setting this ensures that things like + * getparam()/getattr() don't report silly values for !rt tasks. + */ + p->rt_priority = attr->sched_priority; + p->normal_prio = normal_prio(p); +} + +/* Actually do priority change: must hold rq lock. */ +static void __setscheduler(struct rq *rq, struct task_struct *p, + const struct sched_attr *attr, bool keep_boost) +{ + __setscheduler_params(p, attr); + + /* + * Keep a potential priority boosting if called from + * sched_setscheduler(). + */ + p->prio = normal_prio(p); + if (keep_boost) + p->prio = rt_effective_prio(p, p->prio); + update_task_priodl(p); +} + +/* + * check the target process has a UID that matches the current process's + */ +static bool check_same_owner(struct task_struct *p) +{ + const struct cred *cred = current_cred(), *pcred; + bool match; + + rcu_read_lock(); + pcred = __task_cred(p); + match = (uid_eq(cred->euid, pcred->euid) || + uid_eq(cred->euid, pcred->uid)); + rcu_read_unlock(); + return match; +} + +static int __sched_setscheduler(struct task_struct *p, + const struct sched_attr *attr, + bool user, bool pi) +{ + const struct sched_attr dl_squash_attr = { + .size = sizeof(struct sched_attr), + .sched_policy = SCHED_FIFO, + .sched_nice = 0, + .sched_priority = 99, + }; + int newprio = MAX_RT_PRIO - 1 - attr->sched_priority; + int retval, oldpolicy = -1; + int policy = attr->sched_policy; + struct callback_head *head; + unsigned long flags; + struct rq *rq; + int reset_on_fork; + raw_spinlock_t *lock; + + /* The pi code expects interrupts enabled */ + BUG_ON(pi && in_interrupt()); + + /* + * Alt schedule FW supports SCHED_DEADLINE by squash it as prio 0 SCHED_FIFO + */ + if (unlikely(SCHED_DEADLINE == policy)) { + attr = &dl_squash_attr; + policy = attr->sched_policy; + newprio = MAX_RT_PRIO - 1 - attr->sched_priority; + } +recheck: + /* Double check policy once rq lock held */ + if (policy < 0) { + reset_on_fork = p->sched_reset_on_fork; + policy = oldpolicy = p->policy; + } else { + reset_on_fork = !!(attr->sched_flags & SCHED_RESET_ON_FORK); + + if (policy > SCHED_IDLE) + return -EINVAL; + } + + if (attr->sched_flags & ~(SCHED_FLAG_ALL)) + return -EINVAL; + + /* + * Valid priorities for SCHED_FIFO and SCHED_RR are + * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL and + * SCHED_BATCH and SCHED_IDLE is 0. + */ + if (attr->sched_priority < 0 || + (p->mm && attr->sched_priority > MAX_USER_RT_PRIO - 1) || + (!p->mm && attr->sched_priority > MAX_RT_PRIO - 1)) + return -EINVAL; + if ((SCHED_RR == policy || SCHED_FIFO == policy) != + (attr->sched_priority != 0)) + return -EINVAL; + + /* + * Allow unprivileged RT tasks to decrease priority: + */ + if (user && !capable(CAP_SYS_NICE)) { + if (SCHED_FIFO == policy || SCHED_RR == policy) { + unsigned long rlim_rtprio = + task_rlimit(p, RLIMIT_RTPRIO); + + /* Can't set/change the rt policy */ + if (policy != p->policy && !rlim_rtprio) + return -EPERM; + + /* Can't increase priority */ + if (attr->sched_priority > p->rt_priority && + attr->sched_priority > rlim_rtprio) + return -EPERM; + } + + /* Can't change other user's priorities */ + if (!check_same_owner(p)) + return -EPERM; + + /* Normal users shall not reset the sched_reset_on_fork flag */ + if (p->sched_reset_on_fork && !reset_on_fork) + return -EPERM; + } + + if (user) { + retval = security_task_setscheduler(p); + if (retval) + return retval; + } + + if (pi) + cpuset_read_lock(); + + /* + * Make sure no PI-waiters arrive (or leave) while we are + * changing the priority of the task: + */ + raw_spin_lock_irqsave(&p->pi_lock, flags); + + /* + * To be able to change p->policy safely, task_access_lock() + * must be called. + * IF use task_access_lock() here: + * For the task p which is not running, reading rq->stop is + * racy but acceptable as ->stop doesn't change much. + * An enhancemnet can be made to read rq->stop saftly. + */ + rq = __task_access_lock(p, &lock); + + /* + * Changing the policy of the stop threads its a very bad idea + */ + if (p == rq->stop) { + retval = -EINVAL; + goto unlock; + } + + /* + * If not changing anything there's no need to proceed further: + */ + if (unlikely(policy == p->policy)) { + if (rt_policy(policy) && attr->sched_priority != p->rt_priority) + goto change; + if (!rt_policy(policy) && + NICE_TO_PRIO(attr->sched_nice) != p->static_prio) + goto change; + + p->sched_reset_on_fork = reset_on_fork; + retval = 0; + goto unlock; + } +change: + + /* Re-check policy now with rq lock held */ + if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) { + policy = oldpolicy = -1; + __task_access_unlock(p, lock); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); + if (pi) + cpuset_read_unlock(); + goto recheck; + } + + p->sched_reset_on_fork = reset_on_fork; + + if (pi) { + /* + * Take priority boosted tasks into account. If the new + * effective priority is unchanged, we just store the new + * normal parameters and do not touch the scheduler class and + * the runqueue. This will be done when the task deboost + * itself. + */ + if (rt_effective_prio(p, newprio) == p->prio) { + __setscheduler_params(p, attr); + retval = 0; + goto unlock; + } + } + + __setscheduler(rq, p, attr, pi); + + check_task_changed(rq, p); + + /* Avoid rq from going away on us: */ + preempt_disable(); + head = splice_balance_callbacks(rq); + __task_access_unlock(p, lock); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); + + if (pi) { + cpuset_read_unlock(); + rt_mutex_adjust_pi(p); + } + + /* Run balance callbacks after we've adjusted the PI chain: */ + balance_callbacks(rq, head); + preempt_enable(); + + return 0; + +unlock: + __task_access_unlock(p, lock); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); + if (pi) + cpuset_read_unlock(); + return retval; +} + +static int _sched_setscheduler(struct task_struct *p, int policy, + const struct sched_param *param, bool check) +{ + struct sched_attr attr = { + .sched_policy = policy, + .sched_priority = param->sched_priority, + .sched_nice = PRIO_TO_NICE(p->static_prio), + }; + + /* Fixup the legacy SCHED_RESET_ON_FORK hack. */ + if ((policy != SETPARAM_POLICY) && (policy & SCHED_RESET_ON_FORK)) { + attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK; + policy &= ~SCHED_RESET_ON_FORK; + attr.sched_policy = policy; + } + + return __sched_setscheduler(p, &attr, check, true); +} + +/** + * sched_setscheduler - change the scheduling policy and/or RT priority of a thread. + * @p: the task in question. + * @policy: new policy. + * @param: structure containing the new RT priority. + * + * Use sched_set_fifo(), read its comment. + * + * Return: 0 on success. An error code otherwise. + * + * NOTE that the task may be already dead. + */ +int sched_setscheduler(struct task_struct *p, int policy, + const struct sched_param *param) +{ + return _sched_setscheduler(p, policy, param, true); +} + +int sched_setattr(struct task_struct *p, const struct sched_attr *attr) +{ + return __sched_setscheduler(p, attr, true, true); +} + +int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr) +{ + return __sched_setscheduler(p, attr, false, true); +} + +/** + * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace. + * @p: the task in question. + * @policy: new policy. + * @param: structure containing the new RT priority. + * + * Just like sched_setscheduler, only don't bother checking if the + * current context has permission. For example, this is needed in + * stop_machine(): we create temporary high priority worker threads, + * but our caller might not have that capability. + * + * Return: 0 on success. An error code otherwise. + */ +int sched_setscheduler_nocheck(struct task_struct *p, int policy, + const struct sched_param *param) +{ + return _sched_setscheduler(p, policy, param, false); +} + +/* + * SCHED_FIFO is a broken scheduler model; that is, it is fundamentally + * incapable of resource management, which is the one thing an OS really should + * be doing. + * + * This is of course the reason it is limited to privileged users only. + * + * Worse still; it is fundamentally impossible to compose static priority + * workloads. You cannot take two correctly working static prio workloads + * and smash them together and still expect them to work. + * + * For this reason 'all' FIFO tasks the kernel creates are basically at: + * + * MAX_RT_PRIO / 2 + * + * The administrator _MUST_ configure the system, the kernel simply doesn't + * know enough information to make a sensible choice. + */ +void sched_set_fifo(struct task_struct *p) +{ + struct sched_param sp = { .sched_priority = MAX_RT_PRIO / 2 }; + WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0); +} +EXPORT_SYMBOL_GPL(sched_set_fifo); + +/* + * For when you don't much care about FIFO, but want to be above SCHED_NORMAL. + */ +void sched_set_fifo_low(struct task_struct *p) +{ + struct sched_param sp = { .sched_priority = 1 }; + WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0); +} +EXPORT_SYMBOL_GPL(sched_set_fifo_low); + +void sched_set_normal(struct task_struct *p, int nice) +{ + struct sched_attr attr = { + .sched_policy = SCHED_NORMAL, + .sched_nice = nice, + }; + WARN_ON_ONCE(sched_setattr_nocheck(p, &attr) != 0); +} +EXPORT_SYMBOL_GPL(sched_set_normal); + +static int +do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) +{ + struct sched_param lparam; + struct task_struct *p; + int retval; + + if (!param || pid < 0) + return -EINVAL; + if (copy_from_user(&lparam, param, sizeof(struct sched_param))) + return -EFAULT; + + rcu_read_lock(); + retval = -ESRCH; + p = find_process_by_pid(pid); + if (likely(p)) + get_task_struct(p); + rcu_read_unlock(); + + if (likely(p)) { + retval = sched_setscheduler(p, policy, &lparam); + put_task_struct(p); + } + + return retval; +} + +/* + * Mimics kernel/events/core.c perf_copy_attr(). + */ +static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *attr) +{ + u32 size; + int ret; + + /* Zero the full structure, so that a short copy will be nice: */ + memset(attr, 0, sizeof(*attr)); + + ret = get_user(size, &uattr->size); + if (ret) + return ret; + + /* ABI compatibility quirk: */ + if (!size) + size = SCHED_ATTR_SIZE_VER0; + + if (size < SCHED_ATTR_SIZE_VER0 || size > PAGE_SIZE) + goto err_size; + + ret = copy_struct_from_user(attr, sizeof(*attr), uattr, size); + if (ret) { + if (ret == -E2BIG) + goto err_size; + return ret; + } + + /* + * XXX: Do we want to be lenient like existing syscalls; or do we want + * to be strict and return an error on out-of-bounds values? + */ + attr->sched_nice = clamp(attr->sched_nice, -20, 19); + + /* sched/core.c uses zero here but we already know ret is zero */ + return 0; + +err_size: + put_user(sizeof(*attr), &uattr->size); + return -E2BIG; +} + +/** + * sys_sched_setscheduler - set/change the scheduler policy and RT priority + * @pid: the pid in question. + * @policy: new policy. + * + * Return: 0 on success. An error code otherwise. + * @param: structure containing the new RT priority. + */ +SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param) +{ + if (policy < 0) + return -EINVAL; + + return do_sched_setscheduler(pid, policy, param); +} + +/** + * sys_sched_setparam - set/change the RT priority of a thread + * @pid: the pid in question. + * @param: structure containing the new RT priority. + * + * Return: 0 on success. An error code otherwise. + */ +SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param) +{ + return do_sched_setscheduler(pid, SETPARAM_POLICY, param); +} + +/** + * sys_sched_setattr - same as above, but with extended sched_attr + * @pid: the pid in question. + * @uattr: structure containing the extended parameters. + */ +SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr, + unsigned int, flags) +{ + struct sched_attr attr; + struct task_struct *p; + int retval; + + if (!uattr || pid < 0 || flags) + return -EINVAL; + + retval = sched_copy_attr(uattr, &attr); + if (retval) + return retval; + + if ((int)attr.sched_policy < 0) + return -EINVAL; + + rcu_read_lock(); + retval = -ESRCH; + p = find_process_by_pid(pid); + if (likely(p)) + get_task_struct(p); + rcu_read_unlock(); + + if (likely(p)) { + retval = sched_setattr(p, &attr); + put_task_struct(p); + } + + return retval; +} + +/** + * sys_sched_getscheduler - get the policy (scheduling class) of a thread + * @pid: the pid in question. + * + * Return: On success, the policy of the thread. Otherwise, a negative error + * code. + */ +SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid) +{ + struct task_struct *p; + int retval = -EINVAL; + + if (pid < 0) + goto out_nounlock; + + retval = -ESRCH; + rcu_read_lock(); + p = find_process_by_pid(pid); + if (p) { + retval = security_task_getscheduler(p); + if (!retval) + retval = p->policy; + } + rcu_read_unlock(); + +out_nounlock: + return retval; +} + +/** + * sys_sched_getscheduler - get the RT priority of a thread + * @pid: the pid in question. + * @param: structure containing the RT priority. + * + * Return: On success, 0 and the RT priority is in @param. Otherwise, an error + * code. + */ +SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) +{ + struct sched_param lp = { .sched_priority = 0 }; + struct task_struct *p; + int retval = -EINVAL; + + if (!param || pid < 0) + goto out_nounlock; + + rcu_read_lock(); + p = find_process_by_pid(pid); + retval = -ESRCH; + if (!p) + goto out_unlock; + + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; + + if (task_has_rt_policy(p)) + lp.sched_priority = p->rt_priority; + rcu_read_unlock(); + + /* + * This one might sleep, we cannot do it with a spinlock held ... + */ + retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0; + +out_nounlock: + return retval; + +out_unlock: + rcu_read_unlock(); + return retval; +} + +/* + * Copy the kernel size attribute structure (which might be larger + * than what user-space knows about) to user-space. + * + * Note that all cases are valid: user-space buffer can be larger or + * smaller than the kernel-space buffer. The usual case is that both + * have the same size. + */ +static int +sched_attr_copy_to_user(struct sched_attr __user *uattr, + struct sched_attr *kattr, + unsigned int usize) +{ + unsigned int ksize = sizeof(*kattr); + + if (!access_ok(uattr, usize)) + return -EFAULT; + + /* + * sched_getattr() ABI forwards and backwards compatibility: + * + * If usize == ksize then we just copy everything to user-space and all is good. + * + * If usize < ksize then we only copy as much as user-space has space for, + * this keeps ABI compatibility as well. We skip the rest. + * + * If usize > ksize then user-space is using a newer version of the ABI, + * which part the kernel doesn't know about. Just ignore it - tooling can + * detect the kernel's knowledge of attributes from the attr->size value + * which is set to ksize in this case. + */ + kattr->size = min(usize, ksize); + + if (copy_to_user(uattr, kattr, kattr->size)) + return -EFAULT; + + return 0; +} + +/** + * sys_sched_getattr - similar to sched_getparam, but with sched_attr + * @pid: the pid in question. + * @uattr: structure containing the extended parameters. + * @usize: sizeof(attr) for fwd/bwd comp. + * @flags: for future extension. + */ +SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, + unsigned int, usize, unsigned int, flags) +{ + struct sched_attr kattr = { }; + struct task_struct *p; + int retval; + + if (!uattr || pid < 0 || usize > PAGE_SIZE || + usize < SCHED_ATTR_SIZE_VER0 || flags) + return -EINVAL; + + rcu_read_lock(); + p = find_process_by_pid(pid); + retval = -ESRCH; + if (!p) + goto out_unlock; + + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; + + kattr.sched_policy = p->policy; + if (p->sched_reset_on_fork) + kattr.sched_flags |= SCHED_FLAG_RESET_ON_FORK; + if (task_has_rt_policy(p)) + kattr.sched_priority = p->rt_priority; + else + kattr.sched_nice = task_nice(p); + +#ifdef CONFIG_UCLAMP_TASK + kattr.sched_util_min = p->uclamp_req[UCLAMP_MIN].value; + kattr.sched_util_max = p->uclamp_req[UCLAMP_MAX].value; +#endif + + rcu_read_unlock(); + + return sched_attr_copy_to_user(uattr, &kattr, usize); + +out_unlock: + rcu_read_unlock(); + return retval; +} + +long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) +{ + cpumask_var_t cpus_allowed, new_mask; + struct task_struct *p; + int retval; + + rcu_read_lock(); + + p = find_process_by_pid(pid); + if (!p) { + rcu_read_unlock(); + return -ESRCH; + } + + /* Prevent p going away */ + get_task_struct(p); + rcu_read_unlock(); + + if (p->flags & PF_NO_SETAFFINITY) { + retval = -EINVAL; + goto out_put_task; + } + if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) { + retval = -ENOMEM; + goto out_put_task; + } + if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) { + retval = -ENOMEM; + goto out_free_cpus_allowed; + } + retval = -EPERM; + if (!check_same_owner(p)) { + rcu_read_lock(); + if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { + rcu_read_unlock(); + goto out_free_new_mask; + } + rcu_read_unlock(); + } + + retval = security_task_setscheduler(p); + if (retval) + goto out_free_new_mask; + + cpuset_cpus_allowed(p, cpus_allowed); + cpumask_and(new_mask, in_mask, cpus_allowed); + +again: + retval = __set_cpus_allowed_ptr(p, new_mask, SCA_CHECK); + + if (!retval) { + cpuset_cpus_allowed(p, cpus_allowed); + if (!cpumask_subset(new_mask, cpus_allowed)) { + /* + * We must have raced with a concurrent cpuset + * update. Just reset the cpus_allowed to the + * cpuset's cpus_allowed + */ + cpumask_copy(new_mask, cpus_allowed); + goto again; + } + } +out_free_new_mask: + free_cpumask_var(new_mask); +out_free_cpus_allowed: + free_cpumask_var(cpus_allowed); +out_put_task: + put_task_struct(p); + return retval; +} + +static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len, + struct cpumask *new_mask) +{ + if (len < cpumask_size()) + cpumask_clear(new_mask); + else if (len > cpumask_size()) + len = cpumask_size(); + + return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0; +} + +/** + * sys_sched_setaffinity - set the CPU affinity of a process + * @pid: pid of the process + * @len: length in bytes of the bitmask pointed to by user_mask_ptr + * @user_mask_ptr: user-space pointer to the new CPU mask + * + * Return: 0 on success. An error code otherwise. + */ +SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len, + unsigned long __user *, user_mask_ptr) +{ + cpumask_var_t new_mask; + int retval; + + if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) + return -ENOMEM; + + retval = get_user_cpu_mask(user_mask_ptr, len, new_mask); + if (retval == 0) + retval = sched_setaffinity(pid, new_mask); + free_cpumask_var(new_mask); + return retval; +} + +long sched_getaffinity(pid_t pid, cpumask_t *mask) +{ + struct task_struct *p; + raw_spinlock_t *lock; + unsigned long flags; + int retval; + + rcu_read_lock(); + + retval = -ESRCH; + p = find_process_by_pid(pid); + if (!p) + goto out_unlock; + + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; + + task_access_lock_irqsave(p, &lock, &flags); + cpumask_and(mask, &p->cpus_mask, cpu_active_mask); + task_access_unlock_irqrestore(p, lock, &flags); + +out_unlock: + rcu_read_unlock(); + + return retval; +} + +/** + * sys_sched_getaffinity - get the CPU affinity of a process + * @pid: pid of the process + * @len: length in bytes of the bitmask pointed to by user_mask_ptr + * @user_mask_ptr: user-space pointer to hold the current CPU mask + * + * Return: size of CPU mask copied to user_mask_ptr on success. An + * error code otherwise. + */ +SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, + unsigned long __user *, user_mask_ptr) +{ + int ret; + cpumask_var_t mask; + + if ((len * BITS_PER_BYTE) < nr_cpu_ids) + return -EINVAL; + if (len & (sizeof(unsigned long)-1)) + return -EINVAL; + + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) + return -ENOMEM; + + ret = sched_getaffinity(pid, mask); + if (ret == 0) { + unsigned int retlen = min_t(size_t, len, cpumask_size()); + + if (copy_to_user(user_mask_ptr, mask, retlen)) + ret = -EFAULT; + else + ret = retlen; + } + free_cpumask_var(mask); + + return ret; +} + +static void do_sched_yield(void) +{ + struct rq *rq; + struct rq_flags rf; + + if (!sched_yield_type) + return; + + rq = this_rq_lock_irq(&rf); + + schedstat_inc(rq->yld_count); + + if (1 == sched_yield_type) { + if (!rt_task(current)) + do_sched_yield_type_1(current, rq); + } else if (2 == sched_yield_type) { + if (rq->nr_running > 1) + rq->skip = current; + } + + preempt_disable(); + raw_spin_unlock_irq(&rq->lock); + sched_preempt_enable_no_resched(); + + schedule(); +} + +/** + * sys_sched_yield - yield the current processor to other threads. + * + * This function yields the current CPU to other tasks. If there are no + * other threads running on this CPU then this function will return. + * + * Return: 0. + */ +SYSCALL_DEFINE0(sched_yield) +{ + do_sched_yield(); + return 0; +} + +#ifndef CONFIG_PREEMPTION +int __sched _cond_resched(void) +{ + if (should_resched(0)) { + preempt_schedule_common(); + return 1; + } + rcu_all_qs(); + return 0; +} +EXPORT_SYMBOL(_cond_resched); +#endif + +/* + * __cond_resched_lock() - if a reschedule is pending, drop the given lock, + * call schedule, and on return reacquire the lock. + * + * This works OK both with and without CONFIG_PREEMPTION. We do strange low-level + * operations here to prevent schedule() from being called twice (once via + * spin_unlock(), once by hand). + */ +int __cond_resched_lock(spinlock_t *lock) +{ + int resched = should_resched(PREEMPT_LOCK_OFFSET); + int ret = 0; + + lockdep_assert_held(lock); + + if (spin_needbreak(lock) || resched) { + spin_unlock(lock); + if (resched) + preempt_schedule_common(); + else + cpu_relax(); + ret = 1; + spin_lock(lock); + } + return ret; +} +EXPORT_SYMBOL(__cond_resched_lock); + +/** + * yield - yield the current processor to other threads. + * + * Do not ever use this function, there's a 99% chance you're doing it wrong. + * + * The scheduler is at all times free to pick the calling task as the most + * eligible task to run, if removing the yield() call from your code breaks + * it, it's already broken. + * + * Typical broken usage is: + * + * while (!event) + * yield(); + * + * where one assumes that yield() will let 'the other' process run that will + * make event true. If the current task is a SCHED_FIFO task that will never + * happen. Never use yield() as a progress guarantee!! + * + * If you want to use yield() to wait for something, use wait_event(). + * If you want to use yield() to be 'nice' for others, use cond_resched(). + * If you still want to use yield(), do not! + */ +void __sched yield(void) +{ + set_current_state(TASK_RUNNING); + do_sched_yield(); +} +EXPORT_SYMBOL(yield); + +/** + * yield_to - yield the current processor to another thread in + * your thread group, or accelerate that thread toward the + * processor it's on. + * @p: target task + * @preempt: whether task preemption is allowed or not + * + * It's the caller's job to ensure that the target task struct + * can't go away on us before we can do any checks. + * + * In Alt schedule FW, yield_to is not supported. + * + * Return: + * true (>0) if we indeed boosted the target task. + * false (0) if we failed to boost the target. + * -ESRCH if there's no task to yield to. + */ +int __sched yield_to(struct task_struct *p, bool preempt) +{ + return 0; +} +EXPORT_SYMBOL_GPL(yield_to); + +int io_schedule_prepare(void) +{ + int old_iowait = current->in_iowait; + + current->in_iowait = 1; + blk_schedule_flush_plug(current); + + return old_iowait; +} + +void io_schedule_finish(int token) +{ + current->in_iowait = token; +} + +/* + * This task is about to go to sleep on IO. Increment rq->nr_iowait so + * that process accounting knows that this is a task in IO wait state. + * + * But don't do that if it is a deliberate, throttling IO wait (this task + * has set its backing_dev_info: the queue against which it should throttle) + */ + +long __sched io_schedule_timeout(long timeout) +{ + int token; + long ret; + + token = io_schedule_prepare(); + ret = schedule_timeout(timeout); + io_schedule_finish(token); + + return ret; +} +EXPORT_SYMBOL(io_schedule_timeout); + +void __sched io_schedule(void) +{ + int token; + + token = io_schedule_prepare(); + schedule(); + io_schedule_finish(token); +} +EXPORT_SYMBOL(io_schedule); + +/** + * sys_sched_get_priority_max - return maximum RT priority. + * @policy: scheduling class. + * + * Return: On success, this syscall returns the maximum + * rt_priority that can be used by a given scheduling class. + * On failure, a negative error code is returned. + */ +SYSCALL_DEFINE1(sched_get_priority_max, int, policy) +{ + int ret = -EINVAL; + + switch (policy) { + case SCHED_FIFO: + case SCHED_RR: + ret = MAX_USER_RT_PRIO-1; + break; + case SCHED_NORMAL: + case SCHED_BATCH: + case SCHED_IDLE: + ret = 0; + break; + } + return ret; +} + +/** + * sys_sched_get_priority_min - return minimum RT priority. + * @policy: scheduling class. + * + * Return: On success, this syscall returns the minimum + * rt_priority that can be used by a given scheduling class. + * On failure, a negative error code is returned. + */ +SYSCALL_DEFINE1(sched_get_priority_min, int, policy) +{ + int ret = -EINVAL; + + switch (policy) { + case SCHED_FIFO: + case SCHED_RR: + ret = 1; + break; + case SCHED_NORMAL: + case SCHED_BATCH: + case SCHED_IDLE: + ret = 0; + break; + } + return ret; +} + +static int sched_rr_get_interval(pid_t pid, struct timespec64 *t) +{ + struct task_struct *p; + int retval; + + alt_sched_debug(); + + if (pid < 0) + return -EINVAL; + + retval = -ESRCH; + rcu_read_lock(); + p = find_process_by_pid(pid); + if (!p) + goto out_unlock; + + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; + rcu_read_unlock(); + + *t = ns_to_timespec64(sched_timeslice_ns); + return 0; + +out_unlock: + rcu_read_unlock(); + return retval; +} + +/** + * sys_sched_rr_get_interval - return the default timeslice of a process. + * @pid: pid of the process. + * @interval: userspace pointer to the timeslice value. + * + * + * Return: On success, 0 and the timeslice is in @interval. Otherwise, + * an error code. + */ +SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, + struct __kernel_timespec __user *, interval) +{ + struct timespec64 t; + int retval = sched_rr_get_interval(pid, &t); + + if (retval == 0) + retval = put_timespec64(&t, interval); + + return retval; +} + +#ifdef CONFIG_COMPAT_32BIT_TIME +SYSCALL_DEFINE2(sched_rr_get_interval_time32, pid_t, pid, + struct old_timespec32 __user *, interval) +{ + struct timespec64 t; + int retval = sched_rr_get_interval(pid, &t); + + if (retval == 0) + retval = put_old_timespec32(&t, interval); + return retval; +} +#endif + +void sched_show_task(struct task_struct *p) +{ + unsigned long free = 0; + int ppid; + + if (!try_get_task_stack(p)) + return; + + pr_info("task:%-15.15s state:%c", p->comm, task_state_to_char(p)); + + if (p->state == TASK_RUNNING) + pr_cont(" running task "); +#ifdef CONFIG_DEBUG_STACK_USAGE + free = stack_not_used(p); +#endif + ppid = 0; + rcu_read_lock(); + if (pid_alive(p)) + ppid = task_pid_nr(rcu_dereference(p->real_parent)); + rcu_read_unlock(); + pr_cont(" stack:%5lu pid:%5d ppid:%6d flags:0x%08lx\n", + free, task_pid_nr(p), ppid, + (unsigned long)task_thread_info(p)->flags); + + print_worker_info(KERN_INFO, p); + print_stop_info(KERN_INFO, p); + show_stack(p, NULL, KERN_INFO); + put_task_stack(p); +} +EXPORT_SYMBOL_GPL(sched_show_task); + +static inline bool +state_filter_match(unsigned long state_filter, struct task_struct *p) +{ + /* no filter, everything matches */ + if (!state_filter) + return true; + + /* filter, but doesn't match */ + if (!(p->state & state_filter)) + return false; + + /* + * When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows + * TASK_KILLABLE). + */ + if (state_filter == TASK_UNINTERRUPTIBLE && p->state == TASK_IDLE) + return false; + + return true; +} + + +void show_state_filter(unsigned long state_filter) +{ + struct task_struct *g, *p; + + rcu_read_lock(); + for_each_process_thread(g, p) { + /* + * reset the NMI-timeout, listing all files on a slow + * console might take a lot of time: + * Also, reset softlockup watchdogs on all CPUs, because + * another CPU might be blocked waiting for us to process + * an IPI. + */ + touch_nmi_watchdog(); + touch_all_softlockup_watchdogs(); + if (state_filter_match(state_filter, p)) + sched_show_task(p); + } + +#ifdef CONFIG_SCHED_DEBUG + /* TODO: Alt schedule FW should support this + if (!state_filter) + sysrq_sched_debug_show(); + */ +#endif + rcu_read_unlock(); + /* + * Only show locks if all tasks are dumped: + */ + if (!state_filter) + debug_show_all_locks(); +} + +void dump_cpu_task(int cpu) +{ + pr_info("Task dump for CPU %d:\n", cpu); + sched_show_task(cpu_curr(cpu)); +} + +/** + * init_idle - set up an idle thread for a given CPU + * @idle: task in question + * @cpu: CPU the idle task belongs to + * + * NOTE: this function does not set the idle thread's NEED_RESCHED + * flag, to make booting more robust. + */ +void init_idle(struct task_struct *idle, int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + __sched_fork(0, idle); + + raw_spin_lock_irqsave(&idle->pi_lock, flags); + raw_spin_lock(&rq->lock); + update_rq_clock(rq); + + idle->last_ran = rq->clock_task; + idle->state = TASK_RUNNING; + idle->flags |= PF_IDLE; + sched_queue_init_idle(rq, idle); + + scs_task_reset(idle); + kasan_unpoison_task_stack(idle); + +#ifdef CONFIG_SMP + /* + * It's possible that init_idle() gets called multiple times on a task, + * in that case do_set_cpus_allowed() will not do the right thing. + * + * And since this is boot we can forgo the serialisation. + */ + set_cpus_allowed_common(idle, cpumask_of(cpu), 0); +#endif + + /* Silence PROVE_RCU */ + rcu_read_lock(); + __set_task_cpu(idle, cpu); + rcu_read_unlock(); + + rq->idle = idle; + rcu_assign_pointer(rq->curr, idle); + idle->on_cpu = 1; + + raw_spin_unlock(&rq->lock); + raw_spin_unlock_irqrestore(&idle->pi_lock, flags); + + /* Set the preempt count _outside_ the spinlocks! */ + init_idle_preempt_count(idle, cpu); + + ftrace_graph_init_idle_task(idle, cpu); + vtime_init_idle(idle, cpu); +#ifdef CONFIG_SMP + sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu); +#endif +} + +#ifdef CONFIG_SMP + +int cpuset_cpumask_can_shrink(const struct cpumask __maybe_unused *cur, + const struct cpumask __maybe_unused *trial) +{ + return 1; +} + +int task_can_attach(struct task_struct *p, + const struct cpumask *cs_cpus_allowed) +{ + int ret = 0; + + /* + * Kthreads which disallow setaffinity shouldn't be moved + * to a new cpuset; we don't want to change their CPU + * affinity and isolating such threads by their set of + * allowed nodes is unnecessary. Thus, cpusets are not + * applicable for such threads. This prevents checking for + * success of set_cpus_allowed_ptr() on all attached tasks + * before cpus_mask may be changed. + */ + if (p->flags & PF_NO_SETAFFINITY) + ret = -EINVAL; + + return ret; +} + +bool sched_smp_initialized __read_mostly; + +#ifdef CONFIG_HOTPLUG_CPU +/* + * Ensures that the idle task is using init_mm right before its CPU goes + * offline. + */ +void idle_task_exit(void) +{ + struct mm_struct *mm = current->active_mm; + + BUG_ON(current != this_rq()->idle); + + if (mm != &init_mm) { + switch_mm(mm, &init_mm, current); + finish_arch_post_lock_switch(); + } + + /* finish_cpu(), as ran on the BP, will clean up the active_mm state */ +} + +static int __balance_push_cpu_stop(void *arg) +{ + struct task_struct *p = arg; + struct rq *rq = this_rq(); + struct rq_flags rf; + int cpu; + + raw_spin_lock_irq(&p->pi_lock); + rq_lock(rq, &rf); + + update_rq_clock(rq); + + if (task_rq(p) == rq && task_on_rq_queued(p)) { + cpu = select_fallback_rq(rq->cpu, p); + rq = __migrate_task(rq, p, cpu); + } + + rq_unlock(rq, &rf); + raw_spin_unlock_irq(&p->pi_lock); + + put_task_struct(p); + + return 0; +} + +static DEFINE_PER_CPU(struct cpu_stop_work, push_work); + +/* + * Ensure we only run per-cpu kthreads once the CPU goes !active. + */ +static void balance_push(struct rq *rq) +{ + struct task_struct *push_task = rq->curr; + + lockdep_assert_held(&rq->lock); + SCHED_WARN_ON(rq->cpu != smp_processor_id()); + /* + * Ensure the thing is persistent until balance_push_set(.on = false); + */ + rq->balance_callback = &balance_push_callback; + + /* + * Both the cpu-hotplug and stop task are in this case and are + * required to complete the hotplug process. + * + * XXX: the idle task does not match kthread_is_per_cpu() due to + * histerical raisins. + */ + if (rq->idle == push_task || + ((push_task->flags & PF_KTHREAD) && kthread_is_per_cpu(push_task)) || + is_migration_disabled(push_task)) { + + /* + * If this is the idle task on the outgoing CPU try to wake + * up the hotplug control thread which might wait for the + * last task to vanish. The rcuwait_active() check is + * accurate here because the waiter is pinned on this CPU + * and can't obviously be running in parallel. + * + * On RT kernels this also has to check whether there are + * pinned and scheduled out tasks on the runqueue. They + * need to leave the migrate disabled section first. + */ + if (!rq->nr_running && !rq_has_pinned_tasks(rq) && + rcuwait_active(&rq->hotplug_wait)) { + raw_spin_unlock(&rq->lock); + rcuwait_wake_up(&rq->hotplug_wait); + raw_spin_lock(&rq->lock); + } + return; + } + + get_task_struct(push_task); + /* + * Temporarily drop rq->lock such that we can wake-up the stop task. + * Both preemption and IRQs are still disabled. + */ + raw_spin_unlock(&rq->lock); + stop_one_cpu_nowait(rq->cpu, __balance_push_cpu_stop, push_task, + this_cpu_ptr(&push_work)); + /* + * At this point need_resched() is true and we'll take the loop in + * schedule(). The next pick is obviously going to be the stop task + * which kthread_is_per_cpu() and will push this task away. + */ + raw_spin_lock(&rq->lock); +} + +static void balance_push_set(int cpu, bool on) +{ + struct rq *rq = cpu_rq(cpu); + struct rq_flags rf; + + rq_lock_irqsave(rq, &rf); + rq->balance_push = on; + if (on) { + WARN_ON_ONCE(rq->balance_callback); + rq->balance_callback = &balance_push_callback; + } else if (rq->balance_callback == &balance_push_callback) { + rq->balance_callback = NULL; + } + rq_unlock_irqrestore(rq, &rf); +} + +/* + * Invoked from a CPUs hotplug control thread after the CPU has been marked + * inactive. All tasks which are not per CPU kernel threads are either + * pushed off this CPU now via balance_push() or placed on a different CPU + * during wakeup. Wait until the CPU is quiescent. + */ +static void balance_hotplug_wait(void) +{ + struct rq *rq = this_rq(); + + rcuwait_wait_event(&rq->hotplug_wait, + rq->nr_running == 1 && !rq_has_pinned_tasks(rq), + TASK_UNINTERRUPTIBLE); +} + +#else + +static void balance_push(struct rq *rq) +{ +} + +static void balance_push_set(int cpu, bool on) +{ +} + +static inline void balance_hotplug_wait(void) +{ +} +#endif /* CONFIG_HOTPLUG_CPU */ + +static void set_rq_offline(struct rq *rq) +{ + if (rq->online) + rq->online = false; +} + +static void set_rq_online(struct rq *rq) +{ + if (!rq->online) + rq->online = true; +} + +/* + * used to mark begin/end of suspend/resume: + */ +static int num_cpus_frozen; + +/* + * Update cpusets according to cpu_active mask. If cpusets are + * disabled, cpuset_update_active_cpus() becomes a simple wrapper + * around partition_sched_domains(). + * + * If we come here as part of a suspend/resume, don't touch cpusets because we + * want to restore it back to its original state upon resume anyway. + */ +static void cpuset_cpu_active(void) +{ + if (cpuhp_tasks_frozen) { + /* + * num_cpus_frozen tracks how many CPUs are involved in suspend + * resume sequence. As long as this is not the last online + * operation in the resume sequence, just build a single sched + * domain, ignoring cpusets. + */ + partition_sched_domains(1, NULL, NULL); + if (--num_cpus_frozen) + return; + /* + * This is the last CPU online operation. So fall through and + * restore the original sched domains by considering the + * cpuset configurations. + */ + cpuset_force_rebuild(); + } + + cpuset_update_active_cpus(); +} + +static int cpuset_cpu_inactive(unsigned int cpu) +{ + if (!cpuhp_tasks_frozen) { + cpuset_update_active_cpus(); + } else { + num_cpus_frozen++; + partition_sched_domains(1, NULL, NULL); + } + return 0; +} + +int sched_cpu_activate(unsigned int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + /* + * Make sure that when the hotplug state machine does a roll-back + * we clear balance_push. Ideally that would happen earlier... + */ + balance_push_set(cpu, false); + +#ifdef CONFIG_SCHED_SMT + /* + * When going up, increment the number of cores with SMT present. + */ + if (cpumask_weight(cpu_smt_mask(cpu)) == 2) + static_branch_inc_cpuslocked(&sched_smt_present); +#endif + set_cpu_active(cpu, true); + + if (sched_smp_initialized) + cpuset_cpu_active(); + + /* + * Put the rq online, if not already. This happens: + * + * 1) In the early boot process, because we build the real domains + * after all cpus have been brought up. + * + * 2) At runtime, if cpuset_cpu_active() fails to rebuild the + * domains. + */ + raw_spin_lock_irqsave(&rq->lock, flags); + set_rq_online(rq); + raw_spin_unlock_irqrestore(&rq->lock, flags); + + return 0; +} + +int sched_cpu_deactivate(unsigned int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + int ret; + + set_cpu_active(cpu, false); + + /* + * From this point forward, this CPU will refuse to run any task that + * is not: migrate_disable() or KTHREAD_IS_PER_CPU, and will actively + * push those tasks away until this gets cleared, see + * sched_cpu_dying(). + */ + balance_push_set(cpu, true); + + /* + * We've cleared cpu_active_mask, wait for all preempt-disabled and RCU + * users of this state to go away such that all new such users will + * observe it. + * + * Do sync before park smpboot threads to take care the rcu boost case. + */ + synchronize_rcu(); + + raw_spin_lock_irqsave(&rq->lock, flags); + update_rq_clock(rq); + set_rq_offline(rq); + raw_spin_unlock_irqrestore(&rq->lock, flags); + +#ifdef CONFIG_SCHED_SMT + /* + * When going down, decrement the number of cores with SMT present. + */ + if (cpumask_weight(cpu_smt_mask(cpu)) == 2) { + static_branch_dec_cpuslocked(&sched_smt_present); + if (!static_branch_likely(&sched_smt_present)) + cpumask_clear(&sched_sg_idle_mask); + } +#endif + + if (!sched_smp_initialized) + return 0; + + ret = cpuset_cpu_inactive(cpu); + if (ret) { + balance_push_set(cpu, false); + set_cpu_active(cpu, true); + return ret; + } + + return 0; +} + +static void sched_rq_cpu_starting(unsigned int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + rq->calc_load_update = calc_load_update; +} + +int sched_cpu_starting(unsigned int cpu) +{ + sched_rq_cpu_starting(cpu); + sched_tick_start(cpu); + return 0; +} + +#ifdef CONFIG_HOTPLUG_CPU + +/* + * Invoked immediately before the stopper thread is invoked to bring the + * CPU down completely. At this point all per CPU kthreads except the + * hotplug thread (current) and the stopper thread (inactive) have been + * either parked or have been unbound from the outgoing CPU. Ensure that + * any of those which might be on the way out are gone. + * + * If after this point a bound task is being woken on this CPU then the + * responsible hotplug callback has failed to do it's job. + * sched_cpu_dying() will catch it with the appropriate fireworks. + */ +int sched_cpu_wait_empty(unsigned int cpu) +{ + balance_hotplug_wait(); + return 0; +} + +/* + * Since this CPU is going 'away' for a while, fold any nr_active delta we + * might have. Called from the CPU stopper task after ensuring that the + * stopper is the last running task on the CPU, so nr_active count is + * stable. We need to take the teardown thread which is calling this into + * account, so we hand in adjust = 1 to the load calculation. + * + * Also see the comment "Global load-average calculations". + */ +static void calc_load_migrate(struct rq *rq) +{ + long delta = calc_load_fold_active(rq, 1); + + if (delta) + atomic_long_add(delta, &calc_load_tasks); +} + +static void dump_rq_tasks(struct rq *rq, const char *loglvl) +{ + struct task_struct *g, *p; + int cpu = cpu_of(rq); + + lockdep_assert_held(&rq->lock); + + printk("%sCPU%d enqueued tasks (%u total):\n", loglvl, cpu, rq->nr_running); + for_each_process_thread(g, p) { + if (task_cpu(p) != cpu) + continue; + + if (!task_on_rq_queued(p)) + continue; + + printk("%s\tpid: %d, name: %s\n", loglvl, p->pid, p->comm); + } +} + +int sched_cpu_dying(unsigned int cpu) +{ + struct rq *rq = cpu_rq(cpu); + unsigned long flags; + + /* Handle pending wakeups and then migrate everything off */ + sched_tick_stop(cpu); + + raw_spin_lock_irqsave(&rq->lock, flags); + if (rq->nr_running != 1 || rq_has_pinned_tasks(rq)) { + WARN(true, "Dying CPU not properly vacated!"); + dump_rq_tasks(rq, KERN_WARNING); + } + raw_spin_unlock_irqrestore(&rq->lock, flags); + + /* + * Now that the CPU is offline, make sure we're welcome + * to new tasks once we come back up. + */ + balance_push_set(cpu, false); + + calc_load_migrate(rq); + hrtick_clear(rq); + return 0; +} +#endif + +#ifdef CONFIG_SMP +static void sched_init_topology_cpumask_early(void) +{ + int cpu; + cpumask_t *tmp; + + for_each_possible_cpu(cpu) { + /* init affinity masks */ + tmp = per_cpu(sched_cpu_affinity_masks, cpu); + + cpumask_copy(tmp, cpumask_of(cpu)); + tmp++; + cpumask_copy(tmp, cpu_possible_mask); + cpumask_clear_cpu(cpu, tmp); + per_cpu(sched_cpu_affinity_end_mask, cpu) = ++tmp; + /* init topo masks */ + tmp = per_cpu(sched_cpu_topo_masks, cpu); + + cpumask_copy(tmp, cpumask_of(cpu)); + tmp++; + cpumask_copy(tmp, cpu_possible_mask); + per_cpu(sched_cpu_llc_mask, cpu) = tmp; + /*per_cpu(sd_llc_id, cpu) = cpu;*/ + } +} + +#define TOPOLOGY_CPUMASK(name, mask, last) \ + if (cpumask_and(chk, chk, mask)) { \ + cpumask_copy(topo, mask); \ + printk(KERN_INFO "sched: cpu#%02d affinity: 0x%08lx topo: 0x%08lx - "#name,\ + cpu, (chk++)->bits[0], (topo++)->bits[0]); \ + } \ + if (!last) \ + cpumask_complement(chk, mask) + +static void sched_init_topology_cpumask(void) +{ + int cpu; + cpumask_t *chk, *topo; + + for_each_online_cpu(cpu) { + /* take chance to reset time slice for idle tasks */ + cpu_rq(cpu)->idle->time_slice = sched_timeslice_ns; + + chk = per_cpu(sched_cpu_affinity_masks, cpu) + 1; + topo = per_cpu(sched_cpu_topo_masks, cpu) + 1; + + cpumask_complement(chk, cpumask_of(cpu)); +#ifdef CONFIG_SCHED_SMT + TOPOLOGY_CPUMASK(smt, topology_sibling_cpumask(cpu), false); +#endif + per_cpu(sd_llc_id, cpu) = cpumask_first(cpu_coregroup_mask(cpu)); + per_cpu(sched_cpu_llc_mask, cpu) = topo; + TOPOLOGY_CPUMASK(coregroup, cpu_coregroup_mask(cpu), false); + + TOPOLOGY_CPUMASK(core, topology_core_cpumask(cpu), false); + + TOPOLOGY_CPUMASK(others, cpu_online_mask, true); + + per_cpu(sched_cpu_affinity_end_mask, cpu) = chk; + printk(KERN_INFO "sched: cpu#%02d llc_id = %d, llc_mask idx = %d\n", + cpu, per_cpu(sd_llc_id, cpu), + (int) (per_cpu(sched_cpu_llc_mask, cpu) - + per_cpu(sched_cpu_topo_masks, cpu))); + } +} +#endif + +void __init sched_init_smp(void) +{ + /* Move init over to a non-isolated CPU */ + if (set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_FLAG_DOMAIN)) < 0) + BUG(); + + sched_init_topology_cpumask(); + + sched_smp_initialized = true; +} +#else +void __init sched_init_smp(void) +{ + cpu_rq(0)->idle->time_slice = sched_timeslice_ns; +} +#endif /* CONFIG_SMP */ + +int in_sched_functions(unsigned long addr) +{ + return in_lock_functions(addr) || + (addr >= (unsigned long)__sched_text_start + && addr < (unsigned long)__sched_text_end); +} + +#ifdef CONFIG_CGROUP_SCHED +/* task group related information */ +struct task_group { + struct cgroup_subsys_state css; + + struct rcu_head rcu; + struct list_head list; + + struct task_group *parent; + struct list_head siblings; + struct list_head children; +#ifdef CONFIG_FAIR_GROUP_SCHED + unsigned long shares; +#endif +}; + +/* + * Default task group. + * Every task in system belongs to this group at bootup. + */ +struct task_group root_task_group; +LIST_HEAD(task_groups); + +/* Cacheline aligned slab cache for task_group */ +static struct kmem_cache *task_group_cache __read_mostly; +#endif /* CONFIG_CGROUP_SCHED */ + +void __init sched_init(void) +{ + int i; + struct rq *rq; + + printk(KERN_INFO ALT_SCHED_VERSION_MSG); + + wait_bit_init(); + +#ifdef CONFIG_SMP + for (i = 0; i < SCHED_BITS; i++) + cpumask_copy(&sched_rq_watermark[i], cpu_present_mask); +#endif + +#ifdef CONFIG_CGROUP_SCHED + task_group_cache = KMEM_CACHE(task_group, 0); + + list_add(&root_task_group.list, &task_groups); + INIT_LIST_HEAD(&root_task_group.children); + INIT_LIST_HEAD(&root_task_group.siblings); +#endif /* CONFIG_CGROUP_SCHED */ + for_each_possible_cpu(i) { + rq = cpu_rq(i); + + sched_queue_init(rq); + rq->watermark = IDLE_WM; + rq->skip = NULL; + + raw_spin_lock_init(&rq->lock); + rq->nr_running = rq->nr_uninterruptible = 0; + rq->calc_load_active = 0; + rq->calc_load_update = jiffies + LOAD_FREQ; +#ifdef CONFIG_SMP + rq->online = false; + rq->cpu = i; + +#ifdef CONFIG_SCHED_SMT + rq->active_balance = 0; +#endif + +#ifdef CONFIG_NO_HZ_COMMON + INIT_CSD(&rq->nohz_csd, nohz_csd_func, rq); +#endif + rq->balance_callback = NULL; +#ifdef CONFIG_HOTPLUG_CPU + rcuwait_init(&rq->hotplug_wait); +#endif +#endif /* CONFIG_SMP */ + rq->nr_switches = 0; + + hrtick_rq_init(rq); + atomic_set(&rq->nr_iowait, 0); + } +#ifdef CONFIG_SMP + /* Set rq->online for cpu 0 */ + cpu_rq(0)->online = true; +#endif + /* + * The boot idle thread does lazy MMU switching as well: + */ + mmgrab(&init_mm); + enter_lazy_tlb(&init_mm, current); + + /* + * Make us the idle thread. Technically, schedule() should not be + * called from this thread, however somewhere below it might be, + * but because we are the idle thread, we just pick up running again + * when this runqueue becomes "idle". + */ + init_idle(current, smp_processor_id()); + + calc_load_update = jiffies + LOAD_FREQ; + +#ifdef CONFIG_SMP + idle_thread_set_boot_cpu(); + + sched_init_topology_cpumask_early(); +#endif /* SMP */ + + init_schedstats(); + + psi_init(); +} + +#ifdef CONFIG_DEBUG_ATOMIC_SLEEP +static inline int preempt_count_equals(int preempt_offset) +{ + int nested = preempt_count() + rcu_preempt_depth(); + + return (nested == preempt_offset); +} + +void __might_sleep(const char *file, int line, int preempt_offset) +{ + /* + * Blocking primitives will set (and therefore destroy) current->state, + * since we will exit with TASK_RUNNING make sure we enter with it, + * otherwise we will destroy state. + */ + WARN_ONCE(current->state != TASK_RUNNING && current->task_state_change, + "do not call blocking ops when !TASK_RUNNING; " + "state=%lx set at [<%p>] %pS\n", + current->state, + (void *)current->task_state_change, + (void *)current->task_state_change); + + ___might_sleep(file, line, preempt_offset); +} +EXPORT_SYMBOL(__might_sleep); + +void ___might_sleep(const char *file, int line, int preempt_offset) +{ + /* Ratelimiting timestamp: */ + static unsigned long prev_jiffy; + + unsigned long preempt_disable_ip; + + /* WARN_ON_ONCE() by default, no rate limit required: */ + rcu_sleep_check(); + + if ((preempt_count_equals(preempt_offset) && !irqs_disabled() && + !is_idle_task(current) && !current->non_block_count) || + system_state == SYSTEM_BOOTING || system_state > SYSTEM_RUNNING || + oops_in_progress) + return; + if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) + return; + prev_jiffy = jiffies; + + /* Save this before calling printk(), since that will clobber it: */ + preempt_disable_ip = get_preempt_disable_ip(current); + + printk(KERN_ERR + "BUG: sleeping function called from invalid context at %s:%d\n", + file, line); + printk(KERN_ERR + "in_atomic(): %d, irqs_disabled(): %d, non_block: %d, pid: %d, name: %s\n", + in_atomic(), irqs_disabled(), current->non_block_count, + current->pid, current->comm); + + if (task_stack_end_corrupted(current)) + printk(KERN_EMERG "Thread overran stack, or stack corrupted\n"); + + debug_show_held_locks(current); + if (irqs_disabled()) + print_irqtrace_events(current); +#ifdef CONFIG_DEBUG_PREEMPT + if (!preempt_count_equals(preempt_offset)) { + pr_err("Preemption disabled at:"); + print_ip_sym(KERN_ERR, preempt_disable_ip); + } +#endif + dump_stack(); + add_taint(TAINT_WARN, LOCKDEP_STILL_OK); +} +EXPORT_SYMBOL(___might_sleep); + +void __cant_sleep(const char *file, int line, int preempt_offset) +{ + static unsigned long prev_jiffy; + + if (irqs_disabled()) + return; + + if (!IS_ENABLED(CONFIG_PREEMPT_COUNT)) + return; + + if (preempt_count() > preempt_offset) + return; + + if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) + return; + prev_jiffy = jiffies; + + printk(KERN_ERR "BUG: assuming atomic context at %s:%d\n", file, line); + printk(KERN_ERR "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n", + in_atomic(), irqs_disabled(), + current->pid, current->comm); + + debug_show_held_locks(current); + dump_stack(); + add_taint(TAINT_WARN, LOCKDEP_STILL_OK); +} +EXPORT_SYMBOL_GPL(__cant_sleep); + +#ifdef CONFIG_SMP +void __cant_migrate(const char *file, int line) +{ + static unsigned long prev_jiffy; + + if (irqs_disabled()) + return; + + if (is_migration_disabled(current)) + return; + + if (!IS_ENABLED(CONFIG_PREEMPT_COUNT)) + return; + + if (preempt_count() > 0) + return; + + if (current->migration_flags & MDF_FORCE_ENABLED) + return; + + if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) + return; + prev_jiffy = jiffies; + + pr_err("BUG: assuming non migratable context at %s:%d\n", file, line); + pr_err("in_atomic(): %d, irqs_disabled(): %d, migration_disabled() %u pid: %d, name: %s\n", + in_atomic(), irqs_disabled(), is_migration_disabled(current), + current->pid, current->comm); + + debug_show_held_locks(current); + dump_stack(); + add_taint(TAINT_WARN, LOCKDEP_STILL_OK); +} +EXPORT_SYMBOL_GPL(__cant_migrate); +#endif +#endif + +#ifdef CONFIG_MAGIC_SYSRQ +void normalize_rt_tasks(void) +{ + struct task_struct *g, *p; + struct sched_attr attr = { + .sched_policy = SCHED_NORMAL, + }; + + read_lock(&tasklist_lock); + for_each_process_thread(g, p) { + /* + * Only normalize user tasks: + */ + if (p->flags & PF_KTHREAD) + continue; + + if (!rt_task(p)) { + /* + * Renice negative nice level userspace + * tasks back to 0: + */ + if (task_nice(p) < 0) + set_user_nice(p, 0); + continue; + } + + __sched_setscheduler(p, &attr, false, false); + } + read_unlock(&tasklist_lock); +} +#endif /* CONFIG_MAGIC_SYSRQ */ + +#if defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) +/* + * These functions are only useful for the IA64 MCA handling, or kdb. + * + * They can only be called when the whole system has been + * stopped - every CPU needs to be quiescent, and no scheduling + * activity can take place. Using them for anything else would + * be a serious bug, and as a result, they aren't even visible + * under any other configuration. + */ + +/** + * curr_task - return the current task for a given CPU. + * @cpu: the processor in question. + * + * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! + * + * Return: The current task for @cpu. + */ +struct task_struct *curr_task(int cpu) +{ + return cpu_curr(cpu); +} + +#endif /* defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) */ + +#ifdef CONFIG_IA64 +/** + * ia64_set_curr_task - set the current task for a given CPU. + * @cpu: the processor in question. + * @p: the task pointer to set. + * + * Description: This function must only be used when non-maskable interrupts + * are serviced on a separate stack. It allows the architecture to switch the + * notion of the current task on a CPU in a non-blocking manner. This function + * must be called with all CPU's synchronised, and interrupts disabled, the + * and caller must save the original value of the current task (see + * curr_task() above) and restore that value before reenabling interrupts and + * re-starting the system. + * + * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! + */ +void ia64_set_curr_task(int cpu, struct task_struct *p) +{ + cpu_curr(cpu) = p; +} + +#endif + +#ifdef CONFIG_CGROUP_SCHED +static void sched_free_group(struct task_group *tg) +{ + kmem_cache_free(task_group_cache, tg); +} + +/* allocate runqueue etc for a new task group */ +struct task_group *sched_create_group(struct task_group *parent) +{ + struct task_group *tg; + + tg = kmem_cache_alloc(task_group_cache, GFP_KERNEL | __GFP_ZERO); + if (!tg) + return ERR_PTR(-ENOMEM); + + return tg; +} + +void sched_online_group(struct task_group *tg, struct task_group *parent) +{ +} + +/* rcu callback to free various structures associated with a task group */ +static void sched_free_group_rcu(struct rcu_head *rhp) +{ + /* Now it should be safe to free those cfs_rqs */ + sched_free_group(container_of(rhp, struct task_group, rcu)); +} + +void sched_destroy_group(struct task_group *tg) +{ + /* Wait for possible concurrent references to cfs_rqs complete */ + call_rcu(&tg->rcu, sched_free_group_rcu); +} + +void sched_offline_group(struct task_group *tg) +{ +} + +static inline struct task_group *css_tg(struct cgroup_subsys_state *css) +{ + return css ? container_of(css, struct task_group, css) : NULL; +} + +static struct cgroup_subsys_state * +cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) +{ + struct task_group *parent = css_tg(parent_css); + struct task_group *tg; + + if (!parent) { + /* This is early initialization for the top cgroup */ + return &root_task_group.css; + } + + tg = sched_create_group(parent); + if (IS_ERR(tg)) + return ERR_PTR(-ENOMEM); + return &tg->css; +} + +/* Expose task group only after completing cgroup initialization */ +static int cpu_cgroup_css_online(struct cgroup_subsys_state *css) +{ + struct task_group *tg = css_tg(css); + struct task_group *parent = css_tg(css->parent); + + if (parent) + sched_online_group(tg, parent); + return 0; +} + +static void cpu_cgroup_css_released(struct cgroup_subsys_state *css) +{ + struct task_group *tg = css_tg(css); + + sched_offline_group(tg); +} + +static void cpu_cgroup_css_free(struct cgroup_subsys_state *css) +{ + struct task_group *tg = css_tg(css); + + /* + * Relies on the RCU grace period between css_released() and this. + */ + sched_free_group(tg); +} + +static void cpu_cgroup_fork(struct task_struct *task) +{ +} + +static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) +{ + return 0; +} + +static void cpu_cgroup_attach(struct cgroup_taskset *tset) +{ +} + +#ifdef CONFIG_FAIR_GROUP_SCHED +static DEFINE_MUTEX(shares_mutex); + +int sched_group_set_shares(struct task_group *tg, unsigned long shares) +{ + /* + * We can't change the weight of the root cgroup. + */ + if (&root_task_group == tg) + return -EINVAL; + + shares = clamp(shares, scale_load(MIN_SHARES), scale_load(MAX_SHARES)); + + mutex_lock(&shares_mutex); + if (tg->shares == shares) + goto done; + + tg->shares = shares; +done: + mutex_unlock(&shares_mutex); + return 0; +} + +static int cpu_shares_write_u64(struct cgroup_subsys_state *css, + struct cftype *cftype, u64 shareval) +{ + if (shareval > scale_load_down(ULONG_MAX)) + shareval = MAX_SHARES; + return sched_group_set_shares(css_tg(css), scale_load(shareval)); +} + +static u64 cpu_shares_read_u64(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct task_group *tg = css_tg(css); + + return (u64) scale_load_down(tg->shares); +} +#endif + +static struct cftype cpu_legacy_files[] = { +#ifdef CONFIG_FAIR_GROUP_SCHED + { + .name = "shares", + .read_u64 = cpu_shares_read_u64, + .write_u64 = cpu_shares_write_u64, + }, +#endif + { } /* Terminate */ +}; + + +static struct cftype cpu_files[] = { + { } /* terminate */ +}; + +static int cpu_extra_stat_show(struct seq_file *sf, + struct cgroup_subsys_state *css) +{ + return 0; +} + +struct cgroup_subsys cpu_cgrp_subsys = { + .css_alloc = cpu_cgroup_css_alloc, + .css_online = cpu_cgroup_css_online, + .css_released = cpu_cgroup_css_released, + .css_free = cpu_cgroup_css_free, + .css_extra_stat_show = cpu_extra_stat_show, + .fork = cpu_cgroup_fork, + .can_attach = cpu_cgroup_can_attach, + .attach = cpu_cgroup_attach, + .legacy_cftypes = cpu_files, + .legacy_cftypes = cpu_legacy_files, + .dfl_cftypes = cpu_files, + .early_init = true, + .threaded = true, +}; +#endif /* CONFIG_CGROUP_SCHED */ + +#undef CREATE_TRACE_POINTS diff --git a/kernel/sched/alt_debug.c b/kernel/sched/alt_debug.c new file mode 100644 index 000000000000..1212a031700e --- /dev/null +++ b/kernel/sched/alt_debug.c @@ -0,0 +1,31 @@ +/* + * kernel/sched/alt_debug.c + * + * Print the alt scheduler debugging details + * + * Author: Alfred Chen + * Date : 2020 + */ +#include "sched.h" + +/* + * This allows printing both to /proc/sched_debug and + * to the console + */ +#define SEQ_printf(m, x...) \ + do { \ + if (m) \ + seq_printf(m, x); \ + else \ + pr_cont(x); \ + } while (0) + +void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns, + struct seq_file *m) +{ + SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, task_pid_nr_ns(p, ns), + get_nr_threads(p)); +} + +void proc_sched_set_task(struct task_struct *p) +{} diff --git a/kernel/sched/alt_sched.h b/kernel/sched/alt_sched.h new file mode 100644 index 000000000000..7bcd96cc6bed --- /dev/null +++ b/kernel/sched/alt_sched.h @@ -0,0 +1,684 @@ +#ifndef ALT_SCHED_H +#define ALT_SCHED_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_PARAVIRT +# include +#endif + +#include "cpupri.h" + +#include + +#ifdef CONFIG_SCHED_BMQ +#include "bmq.h" +#endif +#ifdef CONFIG_SCHED_PDS +#include "pds.h" +#endif + +#ifdef CONFIG_SCHED_DEBUG +# define SCHED_WARN_ON(x) WARN_ONCE(x, #x) +#else +# define SCHED_WARN_ON(x) ({ (void)(x), 0; }) +#endif + +/* + * Increase resolution of nice-level calculations for 64-bit architectures. + * The extra resolution improves shares distribution and load balancing of + * low-weight task groups (eg. nice +19 on an autogroup), deeper taskgroup + * hierarchies, especially on larger systems. This is not a user-visible change + * and does not change the user-interface for setting shares/weights. + * + * We increase resolution only if we have enough bits to allow this increased + * resolution (i.e. 64-bit). The costs for increasing resolution when 32-bit + * are pretty high and the returns do not justify the increased costs. + * + * Really only required when CONFIG_FAIR_GROUP_SCHED=y is also set, but to + * increase coverage and consistency always enable it on 64-bit platforms. + */ +#ifdef CONFIG_64BIT +# define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT + SCHED_FIXEDPOINT_SHIFT) +# define scale_load(w) ((w) << SCHED_FIXEDPOINT_SHIFT) +# define scale_load_down(w) \ +({ \ + unsigned long __w = (w); \ + if (__w) \ + __w = max(2UL, __w >> SCHED_FIXEDPOINT_SHIFT); \ + __w; \ +}) +#else +# define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT) +# define scale_load(w) (w) +# define scale_load_down(w) (w) +#endif + +#ifdef CONFIG_FAIR_GROUP_SCHED +#define ROOT_TASK_GROUP_LOAD NICE_0_LOAD + +/* + * A weight of 0 or 1 can cause arithmetics problems. + * A weight of a cfs_rq is the sum of weights of which entities + * are queued on this cfs_rq, so a weight of a entity should not be + * too large, so as the shares value of a task group. + * (The default weight is 1024 - so there's no practical + * limitation from this.) + */ +#define MIN_SHARES (1UL << 1) +#define MAX_SHARES (1UL << 18) +#endif + +/* task_struct::on_rq states: */ +#define TASK_ON_RQ_QUEUED 1 +#define TASK_ON_RQ_MIGRATING 2 + +static inline int task_on_rq_queued(struct task_struct *p) +{ + return p->on_rq == TASK_ON_RQ_QUEUED; +} + +static inline int task_on_rq_migrating(struct task_struct *p) +{ + return READ_ONCE(p->on_rq) == TASK_ON_RQ_MIGRATING; +} + +/* + * wake flags + */ +#define WF_SYNC 0x01 /* waker goes to sleep after wakeup */ +#define WF_FORK 0x02 /* child wakeup after fork */ +#define WF_MIGRATED 0x04 /* internal use, task got migrated */ +#define WF_ON_CPU 0x08 /* Wakee is on_rq */ + +/* + * This is the main, per-CPU runqueue data structure. + * This data should only be modified by the local cpu. + */ +struct rq { + /* runqueue lock: */ + raw_spinlock_t lock; + + struct task_struct __rcu *curr; + struct task_struct *idle, *stop, *skip; + struct mm_struct *prev_mm; + +#ifdef CONFIG_SCHED_BMQ + struct bmq queue; +#endif +#ifdef CONFIG_SCHED_PDS + struct skiplist_node sl_header; +#endif + unsigned long watermark; + + /* switch count */ + u64 nr_switches; + + atomic_t nr_iowait; + +#ifdef CONFIG_MEMBARRIER + int membarrier_state; +#endif + +#ifdef CONFIG_SMP + int cpu; /* cpu of this runqueue */ + bool online; + + unsigned int ttwu_pending; + unsigned char nohz_idle_balance; + unsigned char idle_balance; + +#ifdef CONFIG_HAVE_SCHED_AVG_IRQ + struct sched_avg avg_irq; +#endif + +#ifdef CONFIG_SCHED_SMT + int active_balance; + struct cpu_stop_work active_balance_work; +#endif + struct callback_head *balance_callback; + unsigned char balance_push; +#ifdef CONFIG_HOTPLUG_CPU + struct rcuwait hotplug_wait; +#endif + unsigned int nr_pinned; +#endif /* CONFIG_SMP */ +#ifdef CONFIG_IRQ_TIME_ACCOUNTING + u64 prev_irq_time; +#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ +#ifdef CONFIG_PARAVIRT + u64 prev_steal_time; +#endif /* CONFIG_PARAVIRT */ +#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING + u64 prev_steal_time_rq; +#endif /* CONFIG_PARAVIRT_TIME_ACCOUNTING */ + + /* calc_load related fields */ + unsigned long calc_load_update; + long calc_load_active; + + u64 clock, last_tick; + u64 last_ts_switch; + u64 clock_task; + + unsigned int nr_running; + unsigned long nr_uninterruptible; + +#ifdef CONFIG_SCHED_HRTICK +#ifdef CONFIG_SMP + call_single_data_t hrtick_csd; +#endif + struct hrtimer hrtick_timer; +#endif + +#ifdef CONFIG_SCHEDSTATS + + /* latency stats */ + struct sched_info rq_sched_info; + unsigned long long rq_cpu_time; + /* could above be rq->cfs_rq.exec_clock + rq->rt_rq.rt_runtime ? */ + + /* sys_sched_yield() stats */ + unsigned int yld_count; + + /* schedule() stats */ + unsigned int sched_switch; + unsigned int sched_count; + unsigned int sched_goidle; + + /* try_to_wake_up() stats */ + unsigned int ttwu_count; + unsigned int ttwu_local; +#endif /* CONFIG_SCHEDSTATS */ + +#ifdef CONFIG_CPU_IDLE + /* Must be inspected within a rcu lock section */ + struct cpuidle_state *idle_state; +#endif + +#ifdef CONFIG_NO_HZ_COMMON +#ifdef CONFIG_SMP + call_single_data_t nohz_csd; +#endif + atomic_t nohz_flags; +#endif /* CONFIG_NO_HZ_COMMON */ +}; + +extern unsigned long calc_load_update; +extern atomic_long_t calc_load_tasks; + +extern void calc_global_load_tick(struct rq *this_rq); +extern long calc_load_fold_active(struct rq *this_rq, long adjust); + +DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); +#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu))) +#define this_rq() this_cpu_ptr(&runqueues) +#define task_rq(p) cpu_rq(task_cpu(p)) +#define cpu_curr(cpu) (cpu_rq(cpu)->curr) +#define raw_rq() raw_cpu_ptr(&runqueues) + +#ifdef CONFIG_SMP +#if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_SYSCTL) +void register_sched_domain_sysctl(void); +void unregister_sched_domain_sysctl(void); +#else +static inline void register_sched_domain_sysctl(void) +{ +} +static inline void unregister_sched_domain_sysctl(void) +{ +} +#endif + +extern bool sched_smp_initialized; + +enum { + ITSELF_LEVEL_SPACE_HOLDER, +#ifdef CONFIG_SCHED_SMT + SMT_LEVEL_SPACE_HOLDER, +#endif + COREGROUP_LEVEL_SPACE_HOLDER, + CORE_LEVEL_SPACE_HOLDER, + OTHER_LEVEL_SPACE_HOLDER, + NR_CPU_AFFINITY_LEVELS +}; + +DECLARE_PER_CPU(cpumask_t [NR_CPU_AFFINITY_LEVELS], sched_cpu_topo_masks); +DECLARE_PER_CPU(cpumask_t *, sched_cpu_llc_mask); + +static inline int __best_mask_cpu(int cpu, const cpumask_t *cpumask, + const cpumask_t *mask) +{ +#if NR_CPUS <= 64 + unsigned long t; + + while ((t = cpumask->bits[0] & mask->bits[0]) == 0UL) + mask++; + + return __ffs(t); +#else + while ((cpu = cpumask_any_and(cpumask, mask)) >= nr_cpu_ids) + mask++; + return cpu; +#endif +} + +static inline int best_mask_cpu(int cpu, const cpumask_t *mask) +{ +#if NR_CPUS <= 64 + unsigned long llc_match; + cpumask_t *chk = per_cpu(sched_cpu_llc_mask, cpu); + + if ((llc_match = mask->bits[0] & chk->bits[0])) { + unsigned long match; + + chk = per_cpu(sched_cpu_topo_masks, cpu); + if (mask->bits[0] & chk->bits[0]) + return cpu; + +#ifdef CONFIG_SCHED_SMT + chk++; + if ((match = mask->bits[0] & chk->bits[0])) + return __ffs(match); +#endif + + return __ffs(llc_match); + } + + return __best_mask_cpu(cpu, mask, chk + 1); +#else + cpumask_t llc_match; + cpumask_t *chk = per_cpu(sched_cpu_llc_mask, cpu); + + if (cpumask_and(&llc_match, mask, chk)) { + cpumask_t tmp; + + chk = per_cpu(sched_cpu_topo_masks, cpu); + if (cpumask_test_cpu(cpu, mask)) + return cpu; + +#ifdef CONFIG_SCHED_SMT + chk++; + if (cpumask_and(&tmp, mask, chk)) + return cpumask_any(&tmp); +#endif + + return cpumask_any(&llc_match); + } + + return __best_mask_cpu(cpu, mask, chk + 1); +#endif +} + +extern void flush_smp_call_function_from_idle(void); + +#else /* !CONFIG_SMP */ +static inline void flush_smp_call_function_from_idle(void) { } +#endif + +#ifndef arch_scale_freq_tick +static __always_inline +void arch_scale_freq_tick(void) +{ +} +#endif + +#ifndef arch_scale_freq_capacity +static __always_inline +unsigned long arch_scale_freq_capacity(int cpu) +{ + return SCHED_CAPACITY_SCALE; +} +#endif + +static inline u64 __rq_clock_broken(struct rq *rq) +{ + return READ_ONCE(rq->clock); +} + +static inline u64 rq_clock(struct rq *rq) +{ + /* + * Relax lockdep_assert_held() checking as in VRQ, call to + * sched_info_xxxx() may not held rq->lock + * lockdep_assert_held(&rq->lock); + */ + return rq->clock; +} + +static inline u64 rq_clock_task(struct rq *rq) +{ + /* + * Relax lockdep_assert_held() checking as in VRQ, call to + * sched_info_xxxx() may not held rq->lock + * lockdep_assert_held(&rq->lock); + */ + return rq->clock_task; +} + +/* + * {de,en}queue flags: + * + * DEQUEUE_SLEEP - task is no longer runnable + * ENQUEUE_WAKEUP - task just became runnable + * + */ + +#define DEQUEUE_SLEEP 0x01 + +#define ENQUEUE_WAKEUP 0x01 + + +/* + * Below are scheduler API which using in other kernel code + * It use the dummy rq_flags + * ToDo : BMQ need to support these APIs for compatibility with mainline + * scheduler code. + */ +struct rq_flags { + unsigned long flags; +}; + +struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf) + __acquires(rq->lock); + +struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf) + __acquires(p->pi_lock) + __acquires(rq->lock); + +static inline void __task_rq_unlock(struct rq *rq, struct rq_flags *rf) + __releases(rq->lock) +{ + raw_spin_unlock(&rq->lock); +} + +static inline void +task_rq_unlock(struct rq *rq, struct task_struct *p, struct rq_flags *rf) + __releases(rq->lock) + __releases(p->pi_lock) +{ + raw_spin_unlock(&rq->lock); + raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags); +} + +static inline void +rq_lock(struct rq *rq, struct rq_flags *rf) + __acquires(rq->lock) +{ + raw_spin_lock(&rq->lock); +} + +static inline void +rq_unlock_irq(struct rq *rq, struct rq_flags *rf) + __releases(rq->lock) +{ + raw_spin_unlock_irq(&rq->lock); +} + +static inline void +rq_unlock(struct rq *rq, struct rq_flags *rf) + __releases(rq->lock) +{ + raw_spin_unlock(&rq->lock); +} + +static inline struct rq * +this_rq_lock_irq(struct rq_flags *rf) + __acquires(rq->lock) +{ + struct rq *rq; + + local_irq_disable(); + rq = this_rq(); + raw_spin_lock(&rq->lock); + + return rq; +} + +static inline int task_current(struct rq *rq, struct task_struct *p) +{ + return rq->curr == p; +} + +static inline bool task_running(struct task_struct *p) +{ + return p->on_cpu; +} + +extern int task_running_nice(struct task_struct *p); + +extern struct static_key_false sched_schedstats; + +#ifdef CONFIG_CPU_IDLE +static inline void idle_set_state(struct rq *rq, + struct cpuidle_state *idle_state) +{ + rq->idle_state = idle_state; +} + +static inline struct cpuidle_state *idle_get_state(struct rq *rq) +{ + WARN_ON(!rcu_read_lock_held()); + return rq->idle_state; +} +#else +static inline void idle_set_state(struct rq *rq, + struct cpuidle_state *idle_state) +{ +} + +static inline struct cpuidle_state *idle_get_state(struct rq *rq) +{ + return NULL; +} +#endif + +static inline int cpu_of(const struct rq *rq) +{ +#ifdef CONFIG_SMP + return rq->cpu; +#else + return 0; +#endif +} + +#include "stats.h" + +#ifdef CONFIG_NO_HZ_COMMON +#define NOHZ_BALANCE_KICK_BIT 0 +#define NOHZ_STATS_KICK_BIT 1 + +#define NOHZ_BALANCE_KICK BIT(NOHZ_BALANCE_KICK_BIT) +#define NOHZ_STATS_KICK BIT(NOHZ_STATS_KICK_BIT) + +#define NOHZ_KICK_MASK (NOHZ_BALANCE_KICK | NOHZ_STATS_KICK) + +#define nohz_flags(cpu) (&cpu_rq(cpu)->nohz_flags) + +/* TODO: needed? +extern void nohz_balance_exit_idle(struct rq *rq); +#else +static inline void nohz_balance_exit_idle(struct rq *rq) { } +*/ +#endif + +#ifdef CONFIG_IRQ_TIME_ACCOUNTING +struct irqtime { + u64 total; + u64 tick_delta; + u64 irq_start_time; + struct u64_stats_sync sync; +}; + +DECLARE_PER_CPU(struct irqtime, cpu_irqtime); + +/* + * Returns the irqtime minus the softirq time computed by ksoftirqd. + * Otherwise ksoftirqd's sum_exec_runtime is substracted its own runtime + * and never move forward. + */ +static inline u64 irq_time_read(int cpu) +{ + struct irqtime *irqtime = &per_cpu(cpu_irqtime, cpu); + unsigned int seq; + u64 total; + + do { + seq = __u64_stats_fetch_begin(&irqtime->sync); + total = irqtime->total; + } while (__u64_stats_fetch_retry(&irqtime->sync, seq)); + + return total; +} +#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ + +#ifdef CONFIG_CPU_FREQ +DECLARE_PER_CPU(struct update_util_data __rcu *, cpufreq_update_util_data); + +/** + * cpufreq_update_util - Take a note about CPU utilization changes. + * @rq: Runqueue to carry out the update for. + * @flags: Update reason flags. + * + * This function is called by the scheduler on the CPU whose utilization is + * being updated. + * + * It can only be called from RCU-sched read-side critical sections. + * + * The way cpufreq is currently arranged requires it to evaluate the CPU + * performance state (frequency/voltage) on a regular basis to prevent it from + * being stuck in a completely inadequate performance level for too long. + * That is not guaranteed to happen if the updates are only triggered from CFS + * and DL, though, because they may not be coming in if only RT tasks are + * active all the time (or there are RT tasks only). + * + * As a workaround for that issue, this function is called periodically by the + * RT sched class to trigger extra cpufreq updates to prevent it from stalling, + * but that really is a band-aid. Going forward it should be replaced with + * solutions targeted more specifically at RT tasks. + */ +static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) +{ + struct update_util_data *data; + + data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data, + cpu_of(rq))); + if (data) + data->func(data, rq_clock(rq), flags); +} +#else +static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} +#endif /* CONFIG_CPU_FREQ */ + +#ifdef CONFIG_NO_HZ_FULL +extern int __init sched_tick_offload_init(void); +#else +static inline int sched_tick_offload_init(void) { return 0; } +#endif + +#ifdef arch_scale_freq_capacity +#ifndef arch_scale_freq_invariant +#define arch_scale_freq_invariant() (true) +#endif +#else /* arch_scale_freq_capacity */ +#define arch_scale_freq_invariant() (false) +#endif + +extern void schedule_idle(void); + +#define cap_scale(v, s) ((v)*(s) >> SCHED_CAPACITY_SHIFT) + +/* + * !! For sched_setattr_nocheck() (kernel) only !! + * + * This is actually gross. :( + * + * It is used to make schedutil kworker(s) higher priority than SCHED_DEADLINE + * tasks, but still be able to sleep. We need this on platforms that cannot + * atomically change clock frequency. Remove once fast switching will be + * available on such platforms. + * + * SUGOV stands for SchedUtil GOVernor. + */ +#define SCHED_FLAG_SUGOV 0x10000000 + +#ifdef CONFIG_MEMBARRIER +/* + * The scheduler provides memory barriers required by membarrier between: + * - prior user-space memory accesses and store to rq->membarrier_state, + * - store to rq->membarrier_state and following user-space memory accesses. + * In the same way it provides those guarantees around store to rq->curr. + */ +static inline void membarrier_switch_mm(struct rq *rq, + struct mm_struct *prev_mm, + struct mm_struct *next_mm) +{ + int membarrier_state; + + if (prev_mm == next_mm) + return; + + membarrier_state = atomic_read(&next_mm->membarrier_state); + if (READ_ONCE(rq->membarrier_state) == membarrier_state) + return; + + WRITE_ONCE(rq->membarrier_state, membarrier_state); +} +#else +static inline void membarrier_switch_mm(struct rq *rq, + struct mm_struct *prev_mm, + struct mm_struct *next_mm) +{ +} +#endif + +#ifdef CONFIG_NUMA +extern int sched_numa_find_closest(const struct cpumask *cpus, int cpu); +#else +static inline int sched_numa_find_closest(const struct cpumask *cpus, int cpu) +{ + return nr_cpu_ids; +} +#endif + +void swake_up_all_locked(struct swait_queue_head *q); +void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait); + +#endif /* ALT_SCHED_H */ diff --git a/kernel/sched/bmq.h b/kernel/sched/bmq.h new file mode 100644 index 000000000000..aba3c98759f8 --- /dev/null +++ b/kernel/sched/bmq.h @@ -0,0 +1,14 @@ +#ifndef BMQ_H +#define BMQ_H + +/* bits: + * RT(0-99), (Low prio adj range, nice width, high prio adj range) / 2, cpu idle task */ +#define SCHED_BITS (MAX_RT_PRIO + NICE_WIDTH / 2 + MAX_PRIORITY_ADJ + 1) +#define IDLE_TASK_SCHED_PRIO (SCHED_BITS - 1) + +struct bmq { + DECLARE_BITMAP(bitmap, SCHED_BITS); + struct list_head heads[SCHED_BITS]; +}; + +#endif diff --git a/kernel/sched/bmq_imp.h b/kernel/sched/bmq_imp.h new file mode 100644 index 000000000000..13eda4b26b6a --- /dev/null +++ b/kernel/sched/bmq_imp.h @@ -0,0 +1,200 @@ +#define ALT_SCHED_VERSION_MSG "sched/bmq: BMQ CPU Scheduler "ALT_SCHED_VERSION" by Alfred Chen.\n" + +/* + * BMQ only routines + */ +#define rq_switch_time(rq) ((rq)->clock - (rq)->last_ts_switch) +#define boost_threshold(p) (sched_timeslice_ns >>\ + (15 - MAX_PRIORITY_ADJ - (p)->boost_prio)) + +static inline void boost_task(struct task_struct *p) +{ + int limit; + + switch (p->policy) { + case SCHED_NORMAL: + limit = -MAX_PRIORITY_ADJ; + break; + case SCHED_BATCH: + case SCHED_IDLE: + limit = 0; + break; + default: + return; + } + + if (p->boost_prio > limit) + p->boost_prio--; +} + +static inline void deboost_task(struct task_struct *p) +{ + if (p->boost_prio < MAX_PRIORITY_ADJ) + p->boost_prio++; +} + +/* + * Common interfaces + */ +static inline int normal_prio(struct task_struct *p) +{ + if (task_has_rt_policy(p)) + return MAX_RT_PRIO - 1 - p->rt_priority; + + return p->static_prio + MAX_PRIORITY_ADJ; +} + +static inline int task_sched_prio(struct task_struct *p, struct rq *rq) +{ + return (p->prio < MAX_RT_PRIO)? p->prio : MAX_RT_PRIO / 2 + (p->prio + p->boost_prio) / 2; +} + +static inline void requeue_task(struct task_struct *p, struct rq *rq); + +static inline void time_slice_expired(struct task_struct *p, struct rq *rq) +{ + p->time_slice = sched_timeslice_ns; + + if (SCHED_FIFO != p->policy && task_on_rq_queued(p)) { + if (SCHED_RR != p->policy) + deboost_task(p); + requeue_task(p, rq); + } +} + +inline int task_running_nice(struct task_struct *p) +{ + return (p->prio + p->boost_prio > DEFAULT_PRIO + MAX_PRIORITY_ADJ); +} + +static inline void update_task_priodl(struct task_struct *p) {} + +static inline unsigned long sched_queue_watermark(struct rq *rq) +{ + return find_first_bit(rq->queue.bitmap, SCHED_BITS); +} + +static inline void sched_queue_init(struct rq *rq) +{ + struct bmq *q = &rq->queue; + int i; + + bitmap_zero(q->bitmap, SCHED_BITS); + for(i = 0; i < SCHED_BITS; i++) + INIT_LIST_HEAD(&q->heads[i]); +} + +static inline void sched_queue_init_idle(struct rq *rq, struct task_struct *idle) +{ + struct bmq *q = &rq->queue; + + idle->bmq_idx = IDLE_TASK_SCHED_PRIO; + INIT_LIST_HEAD(&q->heads[idle->bmq_idx]); + list_add(&idle->bmq_node, &q->heads[idle->bmq_idx]); + set_bit(idle->bmq_idx, q->bitmap); +} + +/* + * This routine used in bmq scheduler only which assume the idle task in the bmq + */ +static inline struct task_struct *sched_rq_first_task(struct rq *rq) +{ + unsigned long idx = find_first_bit(rq->queue.bitmap, SCHED_BITS); + const struct list_head *head = &rq->queue.heads[idx]; + + return list_first_entry(head, struct task_struct, bmq_node); +} + +static inline struct task_struct * +sched_rq_next_task(struct task_struct *p, struct rq *rq) +{ + unsigned long idx = p->bmq_idx; + struct list_head *head = &rq->queue.heads[idx]; + + if (list_is_last(&p->bmq_node, head)) { + idx = find_next_bit(rq->queue.bitmap, SCHED_BITS, idx + 1); + head = &rq->queue.heads[idx]; + + return list_first_entry(head, struct task_struct, bmq_node); + } + + return list_next_entry(p, bmq_node); +} + +#define __SCHED_DEQUEUE_TASK(p, rq, flags, func) \ + psi_dequeue(p, flags & DEQUEUE_SLEEP); \ + sched_info_dequeued(rq, p); \ + \ + list_del(&p->bmq_node); \ + if (list_empty(&rq->queue.heads[p->bmq_idx])) { \ + clear_bit(p->bmq_idx, rq->queue.bitmap);\ + func; \ + } + +#define __SCHED_ENQUEUE_TASK(p, rq, flags) \ + sched_info_queued(rq, p); \ + psi_enqueue(p, flags); \ + \ + p->bmq_idx = task_sched_prio(p, rq); \ + list_add_tail(&p->bmq_node, &rq->queue.heads[p->bmq_idx]); \ + set_bit(p->bmq_idx, rq->queue.bitmap) + +#define __SCHED_REQUEUE_TASK(p, rq, func) \ +{ \ + int idx = task_sched_prio(p, rq); \ +\ + list_del(&p->bmq_node); \ + list_add_tail(&p->bmq_node, &rq->queue.heads[idx]); \ + if (idx != p->bmq_idx) { \ + if (list_empty(&rq->queue.heads[p->bmq_idx])) \ + clear_bit(p->bmq_idx, rq->queue.bitmap); \ + p->bmq_idx = idx; \ + set_bit(p->bmq_idx, rq->queue.bitmap); \ + func; \ + } \ +} + +static inline bool sched_task_need_requeue(struct task_struct *p, struct rq *rq) +{ + return (task_sched_prio(p, rq) != p->bmq_idx); +} + +static void sched_task_fork(struct task_struct *p, struct rq *rq) +{ + p->boost_prio = (p->boost_prio < 0) ? + p->boost_prio + MAX_PRIORITY_ADJ : MAX_PRIORITY_ADJ; +} + +/** + * task_prio - return the priority value of a given task. + * @p: the task in question. + * + * Return: The priority value as seen by users in /proc. + * RT tasks are offset by -100. Normal tasks are centered around 1, value goes + * from 0(SCHED_ISO) up to 82 (nice +19 SCHED_IDLE). + */ +int task_prio(const struct task_struct *p) +{ + if (p->prio < MAX_RT_PRIO) + return (p->prio - MAX_RT_PRIO); + return (p->prio - MAX_RT_PRIO + p->boost_prio); +} + +static void do_sched_yield_type_1(struct task_struct *p, struct rq *rq) +{ + p->boost_prio = MAX_PRIORITY_ADJ; +} + +#ifdef CONFIG_SMP +static void sched_task_ttwu(struct task_struct *p) +{ + if(this_rq()->clock_task - p->last_ran > sched_timeslice_ns) + boost_task(p); +} +#endif + +static void sched_task_deactivate(struct task_struct *p, struct rq *rq) +{ + if (rq_switch_time(rq) < boost_threshold(p)) + boost_task(p); +} diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 6931f0cdeb80..c5e3d3839650 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -171,6 +171,7 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, return cpufreq_driver_resolve_freq(policy, freq); } +#ifndef CONFIG_SCHED_ALT /* * This function computes an effective utilization for the given CPU, to be * used for frequency selection given the linear relation: f = u * f_max. @@ -288,6 +289,18 @@ static void sugov_get_util(struct sugov_cpu *sg_cpu) FREQUENCY_UTIL, NULL); } +#else /* CONFIG_SCHED_ALT */ + +static void sugov_get_util(struct sugov_cpu *sg_cpu) +{ + unsigned long max = arch_scale_cpu_capacity(sg_cpu->cpu); + + sg_cpu->max = max; + sg_cpu->bw_dl = 0; + sg_cpu->util = cpu_rq(sg_cpu->cpu)->nr_running ? max:0UL; +} +#endif + /** * sugov_iowait_reset() - Reset the IO boost status of a CPU. * @sg_cpu: the sugov data for the CPU to boost @@ -428,8 +441,10 @@ static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; } */ static inline void ignore_dl_rate_limit(struct sugov_cpu *sg_cpu, struct sugov_policy *sg_policy) { +#ifndef CONFIG_SCHED_ALT if (cpu_bw_dl(cpu_rq(sg_cpu->cpu)) > sg_cpu->bw_dl) sg_policy->limits_changed = true; +#endif } static inline bool sugov_update_single_common(struct sugov_cpu *sg_cpu, @@ -711,6 +726,7 @@ static int sugov_kthread_create(struct sugov_policy *sg_policy) } ret = sched_setattr_nocheck(thread, &attr); + if (ret) { kthread_stop(thread); pr_warn("%s: failed to set SCHED_DEADLINE\n", __func__); @@ -943,6 +959,7 @@ struct cpufreq_governor *cpufreq_default_governor(void) cpufreq_governor_init(schedutil_gov); #ifdef CONFIG_ENERGY_MODEL +#ifndef CONFIG_SCHED_ALT static void rebuild_sd_workfn(struct work_struct *work) { rebuild_sched_domains_energy(); @@ -966,4 +983,10 @@ void sched_cpufreq_governor_change(struct cpufreq_policy *policy, } } +#else /* CONFIG_SCHED_ALT */ +void sched_cpufreq_governor_change(struct cpufreq_policy *policy, + struct cpufreq_governor *old_gov) +{ +} +#endif #endif diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 5f611658eeab..631276f56ba0 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -123,7 +123,7 @@ void account_user_time(struct task_struct *p, u64 cputime) p->utime += cputime; account_group_user_time(p, cputime); - index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER; + index = task_running_nice(p) ? CPUTIME_NICE : CPUTIME_USER; /* Add user time to cpustat. */ task_group_account_field(p, index, cputime); @@ -147,7 +147,7 @@ void account_guest_time(struct task_struct *p, u64 cputime) p->gtime += cputime; /* Add guest time to cpustat. */ - if (task_nice(p) > 0) { + if (task_running_nice(p)) { cpustat[CPUTIME_NICE] += cputime; cpustat[CPUTIME_GUEST_NICE] += cputime; } else { @@ -270,7 +270,7 @@ static inline u64 account_other_time(u64 max) #ifdef CONFIG_64BIT static inline u64 read_sum_exec_runtime(struct task_struct *t) { - return t->se.sum_exec_runtime; + return tsk_seruntime(t); } #else static u64 read_sum_exec_runtime(struct task_struct *t) @@ -280,7 +280,7 @@ static u64 read_sum_exec_runtime(struct task_struct *t) struct rq *rq; rq = task_rq_lock(t, &rf); - ns = t->se.sum_exec_runtime; + ns = tsk_seruntime(t); task_rq_unlock(rq, t, &rf); return ns; @@ -612,7 +612,7 @@ void cputime_adjust(struct task_cputime *curr, struct prev_cputime *prev, void task_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st) { struct task_cputime cputime = { - .sum_exec_runtime = p->se.sum_exec_runtime, + .sum_exec_runtime = tsk_seruntime(p), }; task_cputime(p, &cputime.utime, &cputime.stime); diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 305727ea0677..e4544de37050 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -396,6 +396,7 @@ void cpu_startup_entry(enum cpuhp_state state) do_idle(); } +#ifndef CONFIG_SCHED_ALT /* * idle-task scheduling class. */ @@ -509,3 +510,4 @@ DEFINE_SCHED_CLASS(idle) = { .switched_to = switched_to_idle, .update_curr = update_curr_idle, }; +#endif diff --git a/kernel/sched/pds.h b/kernel/sched/pds.h new file mode 100644 index 000000000000..623908cf4380 --- /dev/null +++ b/kernel/sched/pds.h @@ -0,0 +1,9 @@ +#ifndef PDS_H +#define PDS_H + +/* bits: + * RT(0-99), (Low prio adj range, nice width, high prio adj range) / 2, cpu idle task */ +#define SCHED_BITS (MAX_RT_PRIO + NICE_WIDTH / 2 + 1) +#define IDLE_TASK_SCHED_PRIO (SCHED_BITS - 1) + +#endif diff --git a/kernel/sched/pds_imp.h b/kernel/sched/pds_imp.h new file mode 100644 index 000000000000..b1ad3d0b0430 --- /dev/null +++ b/kernel/sched/pds_imp.h @@ -0,0 +1,274 @@ +#define ALT_SCHED_VERSION_MSG "sched/pds: PDS CPU Scheduler "ALT_SCHED_VERSION" by Alfred Chen.\n" + +static const u64 user_prio2deadline[NICE_WIDTH] = { +/* -20 */ 4194304, 4613734, 5075107, 5582617, 6140878, +/* -15 */ 6754965, 7430461, 8173507, 8990857, 9889942, +/* -10 */ 10878936, 11966829, 13163511, 14479862, 15927848, +/* -5 */ 17520632, 19272695, 21199964, 23319960, 25651956, +/* 0 */ 28217151, 31038866, 34142752, 37557027, 41312729, +/* 5 */ 45444001, 49988401, 54987241, 60485965, 66534561, +/* 10 */ 73188017, 80506818, 88557499, 97413248, 107154572, +/* 15 */ 117870029, 129657031, 142622734, 156885007, 172573507 +}; + +static const unsigned char dl_level_map[] = { +/* 0 4 8 12 */ + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, +/* 16 20 24 28 */ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, +/* 32 36 40 44 */ + 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, +/* 48 52 56 60 */ + 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, +/* 64 68 72 76 */ + 12, 11, 11, 11, 10, 10, 10, 9, 9, 8, 7, 6, 5, 4, 3, 2, +/* 80 84 88 92 */ + 1, 0 +}; + +/* DEFAULT_SCHED_PRIO: + * dl_level_map[(user_prio2deadline[39] - user_prio2deadline[0]) >> 21] = + * dl_level_map[68] = + * 10 + */ +#define DEFAULT_SCHED_PRIO (MAX_RT_PRIO + 10) + +static inline int normal_prio(struct task_struct *p) +{ + if (task_has_rt_policy(p)) + return MAX_RT_PRIO - 1 - p->rt_priority; + + return MAX_USER_RT_PRIO; +} + +static inline int +task_sched_prio(const struct task_struct *p, const struct rq *rq) +{ + size_t delta; + + if (p == rq->idle) + return IDLE_TASK_SCHED_PRIO; + + if (p->prio < MAX_RT_PRIO) + return p->prio; + + delta = (rq->clock + user_prio2deadline[39] - p->deadline) >> 21; + delta = min((size_t)delta, ARRAY_SIZE(dl_level_map) - 1); + + return MAX_RT_PRIO + dl_level_map[delta]; +} + +int task_running_nice(struct task_struct *p) +{ + return task_sched_prio(p, task_rq(p)) > DEFAULT_SCHED_PRIO; +} + +static inline void update_task_priodl(struct task_struct *p) +{ + p->priodl = (((u64) (p->prio))<<56) | ((p->deadline)>>8); +} + +static inline void requeue_task(struct task_struct *p, struct rq *rq); + +static inline void time_slice_expired(struct task_struct *p, struct rq *rq) +{ + /*printk(KERN_INFO "sched: time_slice_expired(%d) - %px\n", cpu_of(rq), p);*/ + p->time_slice = sched_timeslice_ns; + + if (p->prio >= MAX_RT_PRIO) + p->deadline = rq->clock + user_prio2deadline[TASK_USER_PRIO(p)]; + update_task_priodl(p); + + if (SCHED_FIFO != p->policy && task_on_rq_queued(p)) + requeue_task(p, rq); +} + +/* + * pds_skiplist_task_search -- search function used in PDS run queue skip list + * node insert operation. + * @it: iterator pointer to the node in the skip list + * @node: pointer to the skiplist_node to be inserted + * + * Returns true if key of @it is less or equal to key value of @node, otherwise + * false. + */ +static inline bool +pds_skiplist_task_search(struct skiplist_node *it, struct skiplist_node *node) +{ + return (skiplist_entry(it, struct task_struct, sl_node)->priodl <= + skiplist_entry(node, struct task_struct, sl_node)->priodl); +} + +/* + * Define the skip list insert function for PDS + */ +DEFINE_SKIPLIST_INSERT_FUNC(pds_skiplist_insert, pds_skiplist_task_search); + +/* + * Init the queue structure in rq + */ +static inline void sched_queue_init(struct rq *rq) +{ + INIT_SKIPLIST_NODE(&rq->sl_header); +} + +/* + * Init idle task and put into queue structure of rq + * IMPORTANT: may be called multiple times for a single cpu + */ +static inline void sched_queue_init_idle(struct rq *rq, struct task_struct *idle) +{ + /*printk(KERN_INFO "sched: init(%d) - %px\n", cpu_of(rq), idle);*/ + int default_prio = idle->prio; + + idle->prio = MAX_PRIO; + idle->deadline = 0ULL; + update_task_priodl(idle); + + INIT_SKIPLIST_NODE(&rq->sl_header); + + idle->sl_node.level = idle->sl_level; + pds_skiplist_insert(&rq->sl_header, &idle->sl_node); + + idle->prio = default_prio; +} + +/* + * This routine assume that the idle task always in queue + */ +static inline struct task_struct *sched_rq_first_task(struct rq *rq) +{ + struct skiplist_node *node = rq->sl_header.next[0]; + + BUG_ON(node == &rq->sl_header); + return skiplist_entry(node, struct task_struct, sl_node); +} + +static inline struct task_struct * +sched_rq_next_task(struct task_struct *p, struct rq *rq) +{ + struct skiplist_node *next = p->sl_node.next[0]; + + BUG_ON(next == &rq->sl_header); + return skiplist_entry(next, struct task_struct, sl_node); +} + +static inline unsigned long sched_queue_watermark(struct rq *rq) +{ + return task_sched_prio(sched_rq_first_task(rq), rq); +} + +#define __SCHED_DEQUEUE_TASK(p, rq, flags, func) \ + psi_dequeue(p, flags & DEQUEUE_SLEEP); \ + sched_info_dequeued(rq, p); \ + \ + if (skiplist_del_init(&rq->sl_header, &p->sl_node)) { \ + func; \ + } + +#define __SCHED_ENQUEUE_TASK(p, rq, flags) \ + sched_info_queued(rq, p); \ + psi_enqueue(p, flags); \ + \ + p->sl_node.level = p->sl_level; \ + pds_skiplist_insert(&rq->sl_header, &p->sl_node) + +/* + * Requeue a task @p to @rq + */ +#define __SCHED_REQUEUE_TASK(p, rq, func) \ +{\ + bool b_first = skiplist_del_init(&rq->sl_header, &p->sl_node); \ +\ + p->sl_node.level = p->sl_level; \ + if (pds_skiplist_insert(&rq->sl_header, &p->sl_node) || b_first) { \ + func; \ + } \ +} + +static inline bool sched_task_need_requeue(struct task_struct *p, struct rq *rq) +{ + struct skiplist_node *node; + + node = p->sl_node.prev[0]; + if (node != &rq->sl_header && + skiplist_entry(node, struct task_struct, sl_node)->priodl > p->priodl) + return true; + + node = p->sl_node.next[0]; + if (node != &rq->sl_header && + skiplist_entry(node, struct task_struct, sl_node)->priodl < p->priodl) + return true; + + return false; +} + +/* + * pds_skiplist_random_level -- Returns a pseudo-random level number for skip + * list node which is used in PDS run queue. + * + * __ffs() is used to satisfy p = 0.5 between each levels, and there should be + * platform instruction(known as ctz/clz) for acceleration. + * + * The skiplist level for a task is populated when task is created and doesn't + * change in task's life time. When task is being inserted into run queue, this + * skiplist level is set to task's sl_node->level, the skiplist insert function + * may change it based on current level of the skip lsit. + */ +static inline int pds_skiplist_random_level(const struct task_struct *p) +{ + /* + * 1. Some architectures don't have better than microsecond resolution + * so mask out ~microseconds as a factor of the random seed for skiplist + * insertion. + * 2. Use address of task structure pointer as another factor of the + * random seed for task burst forking scenario. + */ + unsigned long randseed = (task_rq(p)->clock ^ (unsigned long)p) >> 10; + + randseed &= __GENMASK(NUM_SKIPLIST_LEVEL - 1, 0); + if (randseed) + return __ffs(randseed); + + return (NUM_SKIPLIST_LEVEL - 1); +} + +static void sched_task_fork(struct task_struct *p, struct rq *rq) +{ + p->sl_level = pds_skiplist_random_level(p); + if (p->prio >= MAX_RT_PRIO) + p->deadline = rq->clock + user_prio2deadline[TASK_USER_PRIO(p)]; + update_task_priodl(p); +} + +/** + * task_prio - return the priority value of a given task. + * @p: the task in question. + * + * Return: The priority value as seen by users in /proc. + * RT tasks are offset by -100. Normal tasks are centered around 1, value goes + * from 0(SCHED_ISO) up to 82 (nice +19 SCHED_IDLE). + */ +int task_prio(const struct task_struct *p) +{ + int ret; + + if (p->prio < MAX_RT_PRIO) + return (p->prio - MAX_RT_PRIO); + + preempt_disable(); + ret = task_sched_prio(p, this_rq()) - MAX_RT_PRIO; + preempt_enable(); + + return ret; +} + +static void do_sched_yield_type_1(struct task_struct *p, struct rq *rq) +{ + time_slice_expired(p, rq); +} + +#ifdef CONFIG_SMP +static void sched_task_ttwu(struct task_struct *p) {} +#endif +static void sched_task_deactivate(struct task_struct *p, struct rq *rq) {} diff --git a/kernel/sched/pelt.c b/kernel/sched/pelt.c index 2c613e1cff3a..0103b2a7201d 100644 --- a/kernel/sched/pelt.c +++ b/kernel/sched/pelt.c @@ -270,6 +270,7 @@ ___update_load_avg(struct sched_avg *sa, unsigned long load) WRITE_ONCE(sa->util_avg, sa->util_sum / divider); } +#ifndef CONFIG_SCHED_ALT /* * sched_entity: * @@ -387,8 +388,9 @@ int update_dl_rq_load_avg(u64 now, struct rq *rq, int running) return 0; } +#endif -#ifdef CONFIG_SCHED_THERMAL_PRESSURE +#if defined(CONFIG_SCHED_THERMAL_PRESSURE) && !defined(CONFIG_SCHED_ALT) /* * thermal: * diff --git a/kernel/sched/pelt.h b/kernel/sched/pelt.h index 795e43e02afc..856163dac896 100644 --- a/kernel/sched/pelt.h +++ b/kernel/sched/pelt.h @@ -1,13 +1,15 @@ #ifdef CONFIG_SMP #include "sched-pelt.h" +#ifndef CONFIG_SCHED_ALT int __update_load_avg_blocked_se(u64 now, struct sched_entity *se); int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se); int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq); int update_rt_rq_load_avg(u64 now, struct rq *rq, int running); int update_dl_rq_load_avg(u64 now, struct rq *rq, int running); +#endif -#ifdef CONFIG_SCHED_THERMAL_PRESSURE +#if defined(CONFIG_SCHED_THERMAL_PRESSURE) && !defined(CONFIG_SCHED_ALT) int update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity); static inline u64 thermal_load_avg(struct rq *rq) @@ -42,6 +44,7 @@ static inline u32 get_pelt_divider(struct sched_avg *avg) return LOAD_AVG_MAX - 1024 + avg->period_contrib; } +#ifndef CONFIG_SCHED_ALT /* * When a task is dequeued, its estimated utilization should not be update if * its util_avg has not been updated at least once. @@ -162,9 +165,11 @@ static inline u64 cfs_rq_clock_pelt(struct cfs_rq *cfs_rq) return rq_clock_pelt(rq_of(cfs_rq)); } #endif +#endif /* CONFIG_SCHED_ALT */ #else +#ifndef CONFIG_SCHED_ALT static inline int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq) { @@ -182,6 +187,7 @@ update_dl_rq_load_avg(u64 now, struct rq *rq, int running) { return 0; } +#endif static inline int update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index bb09988451a0..24ac0fd03f5d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2,6 +2,10 @@ /* * Scheduler internal types and methods: */ +#ifdef CONFIG_SCHED_ALT +#include "alt_sched.h" +#else + #include #include @@ -2707,3 +2711,9 @@ static inline bool is_per_cpu_kthread(struct task_struct *p) void swake_up_all_locked(struct swait_queue_head *q); void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait); + +static inline int task_running_nice(struct task_struct *p) +{ + return (task_nice(p) > 0); +} +#endif /* !CONFIG_SCHED_ALT */ diff --git a/kernel/sched/stats.c b/kernel/sched/stats.c index 750fb3c67eed..108422ebc7bf 100644 --- a/kernel/sched/stats.c +++ b/kernel/sched/stats.c @@ -22,8 +22,10 @@ static int show_schedstat(struct seq_file *seq, void *v) } else { struct rq *rq; #ifdef CONFIG_SMP +#ifndef CONFIG_SCHED_ALT struct sched_domain *sd; int dcount = 0; +#endif #endif cpu = (unsigned long)(v - 2); rq = cpu_rq(cpu); @@ -40,6 +42,7 @@ static int show_schedstat(struct seq_file *seq, void *v) seq_printf(seq, "\n"); #ifdef CONFIG_SMP +#ifndef CONFIG_SCHED_ALT /* domain-specific stats */ rcu_read_lock(); for_each_domain(cpu, sd) { @@ -68,6 +71,7 @@ static int show_schedstat(struct seq_file *seq, void *v) sd->ttwu_move_balance); } rcu_read_unlock(); +#endif #endif } return 0; diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 5d3675c7a76b..0f6564555540 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -4,6 +4,7 @@ */ #include "sched.h" +#ifndef CONFIG_SCHED_ALT DEFINE_MUTEX(sched_domains_mutex); /* Protected by sched_domains_mutex: */ @@ -1241,8 +1242,10 @@ static void init_sched_groups_capacity(int cpu, struct sched_domain *sd) */ static int default_relax_domain_level = -1; +#endif /* CONFIG_SCHED_ALT */ int sched_domain_level_max; +#ifndef CONFIG_SCHED_ALT static int __init setup_relax_domain_level(char *str) { if (kstrtoint(str, 0, &default_relax_domain_level)) @@ -1472,6 +1475,7 @@ sd_init(struct sched_domain_topology_level *tl, return sd; } +#endif /* CONFIG_SCHED_ALT */ /* * Topology list, bottom-up. @@ -1501,6 +1505,7 @@ void set_sched_topology(struct sched_domain_topology_level *tl) sched_domain_topology = tl; } +#ifndef CONFIG_SCHED_ALT #ifdef CONFIG_NUMA static const struct cpumask *sd_numa_mask(int cpu) @@ -2374,3 +2379,17 @@ void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], partition_sched_domains_locked(ndoms_new, doms_new, dattr_new); mutex_unlock(&sched_domains_mutex); } +#else /* CONFIG_SCHED_ALT */ +void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], + struct sched_domain_attr *dattr_new) +{} + +#ifdef CONFIG_NUMA +int __read_mostly node_reclaim_distance = RECLAIM_DISTANCE; + +int sched_numa_find_closest(const struct cpumask *cpus, int cpu) +{ + return best_mask_cpu(cpu, cpus); +} +#endif /* CONFIG_NUMA */ +#endif diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c9fbdd848138..421c0105a7bc 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -120,6 +120,10 @@ static unsigned long long_max = LONG_MAX; static int one_hundred = 100; static int two_hundred = 200; static int one_thousand = 1000; +#ifdef CONFIG_SCHED_ALT +static int __maybe_unused zero = 0; +extern int sched_yield_type; +#endif #ifdef CONFIG_PRINTK static int ten_thousand = 10000; #endif @@ -184,7 +188,7 @@ static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT; int sysctl_legacy_va_layout; #endif -#ifdef CONFIG_SCHED_DEBUG +#if defined(CONFIG_SCHED_DEBUG) && !defined(CONFIG_SCHED_ALT) static int min_sched_granularity_ns = 100000; /* 100 usecs */ static int max_sched_granularity_ns = NSEC_PER_SEC; /* 1 second */ static int min_wakeup_granularity_ns; /* 0 usecs */ @@ -1652,6 +1656,24 @@ int proc_do_static_key(struct ctl_table *table, int write, } static struct ctl_table kern_table[] = { +#ifdef CONFIG_SCHED_ALT +/* In ALT, only supported "sched_schedstats" */ +#ifdef CONFIG_SCHED_DEBUG +#ifdef CONFIG_SMP +#ifdef CONFIG_SCHEDSTATS + { + .procname = "sched_schedstats", + .data = NULL, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sysctl_schedstats, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, +#endif /* CONFIG_SCHEDSTATS */ +#endif /* CONFIG_SMP */ +#endif /* CONFIG_SCHED_DEBUG */ +#else /* !CONFIG_SCHED_ALT */ { .procname = "sched_child_runs_first", .data = &sysctl_sched_child_runs_first, @@ -1854,6 +1876,7 @@ static struct ctl_table kern_table[] = { .extra2 = SYSCTL_ONE, }, #endif +#endif /* !CONFIG_SCHED_ALT */ #ifdef CONFIG_PROVE_LOCKING { .procname = "prove_locking", @@ -2430,6 +2453,17 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, #endif +#ifdef CONFIG_SCHED_ALT + { + .procname = "yield_type", + .data = &sched_yield_type, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two, + }, +#endif #if defined(CONFIG_S390) && defined(CONFIG_SMP) { .procname = "spin_retry", diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 743c852e10f2..45d284625255 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1922,8 +1922,10 @@ long hrtimer_nanosleep(ktime_t rqtp, const enum hrtimer_mode mode, int ret = 0; u64 slack; +#ifndef CONFIG_SCHED_ALT slack = current->timer_slack_ns; if (dl_task(current) || rt_task(current)) +#endif slack = 0; hrtimer_init_sleeper_on_stack(&t, clockid, mode); diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index a71758e34e45..d20c347df861 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -216,7 +216,7 @@ static void task_sample_cputime(struct task_struct *p, u64 *samples) u64 stime, utime; task_cputime(p, &utime, &stime); - store_samples(samples, stime, utime, p->se.sum_exec_runtime); + store_samples(samples, stime, utime, tsk_seruntime(p)); } static void proc_sample_cputime_atomic(struct task_cputime_atomic *at, @@ -801,6 +801,7 @@ static void collect_posix_cputimers(struct posix_cputimers *pct, u64 *samples, } } +#ifndef CONFIG_SCHED_ALT static inline void check_dl_overrun(struct task_struct *tsk) { if (tsk->dl.dl_overrun) { @@ -808,6 +809,7 @@ static inline void check_dl_overrun(struct task_struct *tsk) __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk); } } +#endif static bool check_rlimit(u64 time, u64 limit, int signo, bool rt, bool hard) { @@ -835,8 +837,10 @@ static void check_thread_timers(struct task_struct *tsk, u64 samples[CPUCLOCK_MAX]; unsigned long soft; +#ifndef CONFIG_SCHED_ALT if (dl_task(tsk)) check_dl_overrun(tsk); +#endif if (expiry_cache_is_inactive(pct)) return; @@ -850,7 +854,7 @@ static void check_thread_timers(struct task_struct *tsk, soft = task_rlimit(tsk, RLIMIT_RTTIME); if (soft != RLIM_INFINITY) { /* Task RT timeout is accounted in jiffies. RTTIME is usec */ - unsigned long rttime = tsk->rt.timeout * (USEC_PER_SEC / HZ); + unsigned long rttime = tsk_rttimeout(tsk) * (USEC_PER_SEC / HZ); unsigned long hard = task_rlimit_max(tsk, RLIMIT_RTTIME); /* At the hard limit, send SIGKILL. No further action. */ @@ -1086,8 +1090,10 @@ static inline bool fastpath_timer_check(struct task_struct *tsk) return true; } +#ifndef CONFIG_SCHED_ALT if (dl_task(tsk) && tsk->dl.dl_overrun) return true; +#endif return false; } diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 73ef12092250..24bf8ef1249a 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -1052,10 +1052,15 @@ static int trace_wakeup_test_thread(void *data) { /* Make this a -deadline thread */ static const struct sched_attr attr = { +#ifdef CONFIG_SCHED_ALT + /* No deadline on BMQ/PDS, use RR */ + .sched_policy = SCHED_RR, +#else .sched_policy = SCHED_DEADLINE, .sched_runtime = 100000ULL, .sched_deadline = 10000000ULL, .sched_period = 10000000ULL +#endif }; struct wakeup_test_data *x = data;