linux sched init简介
调度器的初始化,前面的android 开机流程讲过,uboot(bootloader)执行完一些初始化动作后,会将kernel加载到内存,然后跳到kernel。
kernel在执行完一段汇编代码,准备好c的运行环境后,跳到 start_kernel()。
linux-4.10/init/main.c
linux-4.10/init/main.c
482 asmlinkage __visible void __init start_kernel(void)
483 {
...
542 /*
543 * Set up the scheduler prior starting any interrupts (such as the
544 * timer interrupt). Full topology setup happens at smp_init()
545 * time - but meanwhile we still have a functioning scheduler.
546 */
547 sched_init(); //调度器的初始化
...
672 /* Do the rest non-__init'ed, we're now alive */
673 rest_init();
674 }
sched_init() 初始化了很多调度相关的数据结构,下面只会把它们简单列出来
linux-4.10/kernel/sched/core.c
linux-4.10/kernel/sched/core.c
7543 void __init sched_init(void)
7544 {
7545 int i, j;
7546 unsigned long alloc_size = 0, ptr;
7547
/** linux-4.10/include/linux/types.h* struct list_head { //双向链表* struct list_head *next, *prev;* };* linux-4.10/include/linux/wait.h* struct __wait_queue_head { //所以__wait_queue_head 是一个双向链表,用于保存 spinlock_t (自旋锁)* spinlock_t lock;* struct list_head task_list;* };typedef struct __wait_queue_head wait_queue_head_t;
*/
7548 for (i = 0; i < WAIT_TABLE_SIZE; i++) // #define WAIT_TABLE_BITS 8 #define WAIT_TABLE_SIZE (1 << WAIT_TABLE_BITS) 所以WAIT_TABLE_SIZE 等于 256
7549 init_waitqueue_head(bit_wait_table + i); //static wait_queue_head_t bit_wait_table[WAIT_TABLE_SIZE] __cacheline_aligned;
7550
7551 #ifdef CONFIG_FAIR_GROUP_SCHED //普通进程调度
7552 alloc_size += 2 * nr_cpu_ids * sizeof(void **); //nr_cpu_ids 为支持的cpu核个数,也就是常说的几核,64位系统上 sizeof(void **) = 8
7553 #endif
7554 #ifdef CONFIG_RT_GROUP_SCHED //实时进程调度
7555 alloc_size += 2 * nr_cpu_ids * sizeof(void **);
7556 #endif
7557 if (alloc_size) {
7558 ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT); //申请内存
7559
7560 #ifdef CONFIG_FAIR_GROUP_SCHED
7561 root_task_group.se = (struct sched_entity **)ptr; //指向调度实体
7562 ptr += nr_cpu_ids * sizeof(void **);//ptr指针移动nr_cpu_ids * sizeof(void **) nr_cpu_ids, 为支持的cpu核个数,64位系统上 sizeof(void **) = 8
7563
7564 root_task_group.cfs_rq = (struct cfs_rq **)ptr; //指向调度队列指针,每个核有一个调度队列
7565 ptr += nr_cpu_ids * sizeof(void **);//ptr指针移动nr_cpu_ids * sizeof(void **) nr_cpu_ids,为支持的cpu核个数,64位系统上 sizeof(void **) = 8
7566
7567 #endif /* CONFIG_FAIR_GROUP_SCHED */
7568 #ifdef CONFIG_RT_GROUP_SCHED
7569 root_task_group.rt_se = (struct sched_rt_entity **)ptr; //
7570 ptr += nr_cpu_ids * sizeof(void **); //ptr指针移动nr_cpu_ids * sizeof(void **) nr_cpu_ids, 为支持的cpu核个数,64位系统上 sizeof(void **) = 8
7571
7572 root_task_group.rt_rq = (struct rt_rq **)ptr; //
7573 ptr += nr_cpu_ids * sizeof(void **);
7574
7575 #endif /* CONFIG_RT_GROUP_SCHED */
7576 }
7577 #ifdef CONFIG_CPUMASK_OFFSTACK
7578 for_each_possible_cpu(i) { // (1)...
7579 per_cpu(load_balance_mask, i) = (cpumask_var_t)kzalloc_node(
7580 cpumask_size(), GFP_KERNEL, cpu_to_node(i));
7581 per_cpu(select_idle_mask, i) = (cpumask_var_t)kzalloc_node(
7582 cpumask_size(), GFP_KERNEL, cpu_to_node(i));
7583 }
7584 #endif /* CONFIG_CPUMASK_OFFSTACK */
7585 // (2)...
7586 init_rt_bandwidth(&def_rt_bandwidth, //初始化实时进程对cpu的占有率 ,超过会有一定的惩罚机制(rt throttled)
7587 global_rt_period(), global_rt_runtime());
7588 init_dl_bandwidth(&def_dl_bandwidth,
7589 global_rt_period(), global_rt_runtime());
7590
7591 #ifdef CONFIG_SMP
7592 init_defrootdomain(); // (3)...
7593 #endif
7594
7595 #ifdef CONFIG_RT_GROUP_SCHED
7596 init_rt_bandwidth(&root_task_group.rt_bandwidth,/初始化root_task_group进程组实时进程对cpu的占有率
7597 global_rt_period(), global_rt_runtime());
7598 #endif /* CONFIG_RT_GROUP_SCHED */
7599
7600 #ifdef CONFIG_CGROUP_SCHED //如果支持进程组,可以理解为多用户,每个用户下面的所有进程为一个进程组
7601 task_group_cache = KMEM_CACHE(task_group, 0);
7602
7603 list_add(&root_task_group.list, &task_groups); //将root_task_group添加到task_groups队列中
7604 INIT_LIST_HEAD(&root_task_group.children);
7605 INIT_LIST_HEAD(&root_task_group.siblings);
7606 autogroup_init(&init_task);
7607 #endif /* CONFIG_CGROUP_SCHED */
7608
7609 for_each_possible_cpu(i) {
7610 struct rq *rq;
/** linux-4.10/kernel/sched/sched.h* struct rq {* /* runqueue lock: */* raw_spinlock_t lock; //自旋锁* ...* 604 unsigned int nr_running; //此CPU上总共就绪的进程数* ...* u64 nr_switches; // 进行上下文切换次数* * struct cfs_rq cfs; // cfs调度运行队列* struct rt_rq rt; //实时调度运行队列* struct dl_rq dl; //dl调度运行队列* ...* struct task_struct *curr, *idle, *stop; //curr: 当前正在此CPU上运行的进程, idle: 当前CPU上idle进程的指针,* ...* int cpu; //该运行队列所属CPU ID* int online; //online状态* ...* };
*/
7612 rq = cpu_rq(i); //获取对应cpu上的运行队列 // (4)...
7613 raw_spin_lock_init(&rq->lock); //初始化自旋锁
7614 rq->nr_running = 0;
7615 rq->calc_load_active = 0;
7616 rq->calc_load_update = jiffies + LOAD_FREQ;
7617 init_cfs_rq(&rq->cfs); //初始化cfs调度运行队列 其实就是赋初始值
7618 init_rt_rq(&rq->rt);
7619 init_dl_rq(&rq->dl);
7620 #ifdef CONFIG_FAIR_GROUP_SCHED
7621 root_task_group.shares = ROOT_TASK_GROUP_LOAD;
7622 INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
7623 rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
7624 /*
7625 * How much cpu bandwidth does root_task_group get?
7626 *
7627 * In case of task-groups formed thr' the cgroup filesystem, it
7628 * gets 100% of the cpu resources in the system. This overall
7629 * system cpu resource is divided among the tasks of
7630 * root_task_group and its child task-groups in a fair manner,
7631 * based on each entity's (task or task-group's) weight
7632 * (se->load.weight).
7633 *
7634 * In other words, if root_task_group has 10 tasks of weight
7635 * 1024) and two child groups A0 and A1 (of weight 1024 each),
7636 * then A0's share of the cpu resource is:
7637 *
7638 * A0's bandwidth = 1024 / (10*1024 + 1024 + 1024) = 8.33%
7639 *
7640 * We achieve this by letting root_task_group's tasks sit
7641 * directly in rq->cfs (i.e root_task_group->se[] = NULL).
7642 */
7643 init_cfs_bandwidth(&root_task_group.cfs_bandwidth); //设置root_task_group进程组普通进程在CPU中所占用比的
7644 init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL); //
7645 #endif /* CONFIG_FAIR_GROUP_SCHED */
7646
7647 rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
7648 #ifdef CONFIG_RT_GROUP_SCHED
7649 init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
7650 #endif
7651
7652 for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
7653 rq->cpu_load[j] = 0;
7654
7655 #ifdef CONFIG_SMP
7656 rq->sd = NULL;
7657 rq->rd = NULL;
7658 rq->cpu_capacity = rq->cpu_capacity_orig = SCHED_CAPACITY_SCALE;
7659 rq->balance_callback = NULL;
7660 rq->active_balance = 0;
7661 rq->next_balance = jiffies;
7662 rq->push_cpu = 0;
7663 rq->cpu = i;
7664 rq->online = 0;
7665 rq->idle_stamp = 0;
7666 rq->avg_idle = 2*sysctl_sched_migration_cost;
7667 rq->max_idle_balance_cost = sysctl_sched_migration_cost;
7668
7669 INIT_LIST_HEAD(&rq->cfs_tasks);
7670
7671 rq_attach_root(rq, &def_root_domain); //将CPU运行队列加入到默认调度域中
7672 #ifdef CONFIG_NO_HZ_COMMON
7673 rq->last_load_update_tick = jiffies;
7674 rq->nohz_flags = 0;
7675 #endif
7676 #ifdef CONFIG_NO_HZ_FULL
7677 rq->last_sched_tick = 0;
7678 #endif
7679 #endif /* CONFIG_SMP */
7680 init_rq_hrtick(rq);
7681 atomic_set(&rq->nr_iowait, 0);
7682 }
7683
7684 set_load_weight(&init_task); //负载均衡设置
7685
7686 /*
7687 * The boot idle thread does lazy MMU switching as well:
7688 */
7689 atomic_inc(&init_mm.mm_count);
7690 enter_lazy_tlb(&init_mm, current);
7691
7692 /*
7693 * Make us the idle thread. Technically, schedule() should not be
7694 * called from this thread, however somewhere below it might be,
7695 * but because we are the idle thread, we just pick up running again
7696 * when this runqueue becomes "idle".
7697 */
7698 init_idle(current, smp_processor_id()); // (5)...
7699
7700 calc_load_update = jiffies + LOAD_FREQ;
7701
7702 #ifdef CONFIG_SMP
7703 zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT);
7704 /* May be allocated at isolcpus cmdline parse time */
7705 if (cpu_isolated_map == NULL)
7706 zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
7707 idle_thread_set_boot_cpu(); // (6)...
7708 set_cpu_rq_start_time(smp_processor_id());
7709 #endif
7710 init_sched_fair_class(); //初始化公平调度器 // (7)...
7711
7712 init_schedstats();
7713
7714 scheduler_running = 1;
7715 }
(1) for_each_possible_cpu()
/* 网上的解释,暂时没有理解* CPU mask机制被用于表示系统中多个处理器的各种组合,但是随着处理器数量的增长将消耗堆栈上大量的空间。* 新设计的API可以将CPU masks从堆栈上移出来.
*/
7577 #ifdef CONFIG_CPUMASK_OFFSTACK
7578 for_each_possible_cpu(i) { //相当于一个for循环
7579 per_cpu(load_balance_mask, i) = (cpumask_var_t)kzalloc_node( //可以认为load_balance_mask 定义在某个属性(__attribute__)中
7580 cpumask_size(), GFP_KERNEL, cpu_to_node(i)); //kzalloc_node()用于申请内存,暂不深入研究
7581 per_cpu(select_idle_mask, i) = (cpumask_var_t)kzalloc_node( //可以认为select_idle_mask 定义在某个属性(__attribute__)中
7582 cpumask_size(), GFP_KERNEL, cpu_to_node(i));
7583 }
7584 #endif /* CONFIG_CPUMASK_OFFSTACK */
上面是sched_init()里面的部分,因为上面代码已经足够多了,不好再贴出相关定义,所以放在这里在单独分析。
linux-4.10/include/linux/cpumask.h
222 #define for_each_cpu(cpu, mask) \
223 for ((cpu) = -1; \
224 (cpu) = cpumask_next((cpu), (mask)), \
225 (cpu) < nr_cpu_ids;)
226
extern struct cpumask __cpu_possible_mask;
#define cpu_possible_mask ((const struct cpumask *)&__cpu_possible_mask)
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
linux-4.10/include/linux/percpu-defs.h
204 #define __verify_pcpu_ptr(ptr) \
205 do { \
206 const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \
207 (void)__vpp_verify; \
208 } while (0)
209
220 #define per_cpu_ptr(ptr, cpu) \
221 ({ \
222 __verify_pcpu_ptr(ptr); \
223 SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu))); \
224 })256 #define per_cpu(var, cpu) (*per_cpu_ptr(&(var), cpu))
根据相关定义,可知 for_each_possible_cpu(i) 相当于 for ((i) = -1;(i = cpumask_next((i), (mask)), (i) < nr_cpu_ids;) 也就是一个for 循环
per_cpu(load_balance_mask, i) 可以先理解为 load_balance_mask[i] load_balance_mask 定义的时候写的不是很直观,这里把它当作对应的结构体变量就可以了,只不过是放在某个特殊的section里面而已。
(2) init_rt_bandwidth()和init_dl_bandwidth()
7586 init_rt_bandwidth(&def_rt_bandwidth, //初始化实时进程对cpu的占有率 ,超过会有一定的惩罚机制(throttled)
7587 global_rt_period(), global_rt_runtime());
7588 init_dl_bandwidth(&def_dl_bandwidth,
7589 global_rt_period(), global_rt_runtime());
linux-4.10/kernel/sched/rt.c
41 void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime)
42 {
43 rt_b->rt_period = ns_to_ktime(period); //时长
44 rt_b->rt_runtime = runtime; // 总时长
45
46 raw_spin_lock_init(&rt_b->rt_runtime_lock);
47
48 hrtimer_init(&rt_b->rt_period_timer,
49 CLOCK_MONOTONIC, HRTIMER_MODE_REL);
50 rt_b->rt_period_timer.function = sched_rt_period_timer; //sched_rt_period_timer 定时器超时回调函数
51 }
linux-4.10/kernel/sched/deadline.c
53 void init_dl_bandwidth(struct dl_bandwidth *dl_b, u64 period, u64 runtime)
54 {
55 raw_spin_lock_init(&dl_b->dl_runtime_lock);
56 dl_b->dl_period = period;
57 dl_b->dl_runtime = runtime;
58 }
(3)init_defrootdomain()
7591 #ifdef CONFIG_SMP
7592 init_defrootdomain();
7593 #endif
linux-4.10/kernel/sched/core.c
5902 /*
5903 * By default the system creates a single root-domain with all cpus as
5904 * members (mimicking the global state we have today).
5905 */
5906 struct root_domain def_root_domain;
5907
5908 static void init_defrootdomain(void)
5909 {
5910 init_rootdomain(&def_root_domain); //rootdomain 指示rq可运行的cpu集合
5911
5912 atomic_set(&def_root_domain.refcount, 1);
5913 }5869 static int init_rootdomain(struct root_domain *rd)
5870 {
5871 memset(rd, 0, sizeof(*rd));
5872
5873 if (!zalloc_cpumask_var(&rd->span, GFP_KERNEL)) //申请内存
5874 goto out;
5875 if (!zalloc_cpumask_var(&rd->online, GFP_KERNEL)) //申请内存
5876 goto free_span;
5877 if (!zalloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL)) //申请内存
5878 goto free_online;
5879 if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL)) //申请内存
5880 goto free_dlo_mask;
5881
5882 init_dl_bw(&rd->dl_bw); //deadline 值越小优先级越高
5883 if (cpudl_init(&rd->cpudl) != 0) //initialize the cpudl structure
5884 goto free_dlo_mask;
5885
5886 if (cpupri_init(&rd->cpupri) != 0) //initialize the cpupri structure
5887 goto free_rto_mask;
5888 return 0;
5889
5890 free_rto_mask:
5891 free_cpumask_var(rd->rto_mask);
5892 free_dlo_mask:
5893 free_cpumask_var(rd->dlo_mask);
5894 free_online:
5895 free_cpumask_var(rd->online);
5896 free_span:
5897 free_cpumask_var(rd->span);
5898 out:
5899 return -ENOMEM;
5900 }
又是分配了一堆的数据结构体,暂时先这样了解吧
(4) cpu_rq()
linux-4.10/kernel/sched/sched.h
758 DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
759
760 #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
cpu_rq(cpu) 函数会返回指定cpu 上的运行队列,又是一串宏定义,可以边不纠结它的具体实现,这里我们知道runqueues 这个变量指向了已经分别好的 struct rq成员。
linux-4.10/include/linux/percpu-defs.h
139 #define DECLARE_PER_CPU_SHARED_ALIGNED(type, name) \
140 DECLARE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \
141 ____cacheline_aligned_in_smp212 /*
213 * Add an offset to a pointer but keep the pointer as-is. Use RELOC_HIDE()
214 * to prevent the compiler from making incorrect assumptions about the
215 * pointer value. The weird cast keeps both GCC and sparse happy.
216 */
217 #define SHIFT_PERCPU_PTR(__p, __offset) \
218 RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset))
219
220 #define per_cpu_ptr(ptr, cpu) \
221 ({ \
222 __verify_pcpu_ptr(ptr); \
223 SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu))); \
224 })
linux-4.10 / include / linux / compiler.h
linux-4.10/include/linux/compiler.h
209 # define RELOC_HIDE(ptr, off) \
210 ({ unsigned long __ptr; \
211 __ptr = (unsigned long) (ptr); \
212 (typeof(ptr)) (__ptr + (off)); })
213 #endif
所以 cpu_rq(i) 可以先理解为 (struct rq*)(runqueues +I)
(5)init_idle()
linux-4.10/kernel/sched/core.c
5264 /**
5265 * init_idle - set up an idle thread for a given CPU
5266 * @idle: task in question
5267 * @cpu: cpu the idle task belongs to
5268 *
5269 * NOTE: this function does not set the idle thread's NEED_RESCHED
5270 * flag, to make booting more robust.
5271 */
5272 void init_idle(struct task_struct *idle, int cpu)
5273 {
5274 struct rq *rq = cpu_rq(cpu);
5275 unsigned long flags;
5276
5277 raw_spin_lock_irqsave(&idle->pi_lock, flags);
5278 raw_spin_lock(&rq->lock);
5279
5280 __sched_fork(0, idle); //创建idle 为0号进程,可以认为是给idle(task_struct)结构体赋值
5281 idle->state = TASK_RUNNING;
5282 idle->se.exec_start = sched_clock();
5283 idle->flags |= PF_IDLE;
5284
5285 kasan_unpoison_task_stack(idle);
5286
5287 #ifdef CONFIG_SMP
5288 /*
5289 * Its possible that init_idle() gets called multiple times on a task,
5290 * in that case do_set_cpus_allowed() will not do the right thing.
5291 *
5292 * And since this is boot we can forgo the serialization.
5293 */
5294 set_cpus_allowed_common(idle, cpumask_of(cpu));
5295 #endif
5296 /*
5297 * We're having a chicken and egg problem, even though we are
5298 * holding rq->lock, the cpu isn't yet set to this cpu so the
5299 * lockdep check in task_group() will fail.
5300 *
5301 * Similar case to sched_fork(). / Alternatively we could
5302 * use task_rq_lock() here and obtain the other rq->lock.
5303 *
5304 * Silence PROVE_RCU
5305 */
5306 rcu_read_lock();
5307 __set_task_cpu(idle, cpu);
5308 rcu_read_unlock();
5309
5310 rq->curr = rq->idle = idle;
5311 idle->on_rq = TASK_ON_RQ_QUEUED;
5312 #ifdef CONFIG_SMP
5313 idle->on_cpu = 1;
5314 #endif
5315 raw_spin_unlock(&rq->lock);
5316 raw_spin_unlock_irqrestore(&idle->pi_lock, flags);
5317
5318 /* Set the preempt count _outside_ the spinlocks! */
5319 init_idle_preempt_count(idle, cpu); //设置为可抢占
5320
5321 /*
5322 * The idle tasks have their own, simple scheduling class:
5323 */
5324 idle->sched_class = &idle_sched_class; //设置为idle调度器
5325 ftrace_graph_init_idle_task(idle, cpu);
5326 vtime_init_idle(idle, cpu);
5327 #ifdef CONFIG_SMP
5328 sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu);
5329 #endif
5330 }
给idle 这个数据结果赋值,也就是初始化
(6)set_cpu_rq_start_time()
linux-4.10/kernel/sched/core.c
5631 static void set_cpu_rq_start_time(unsigned int cpu)
5632 {
5633 struct rq *rq = cpu_rq(cpu);
5634
5635 rq->age_stamp = sched_clock_cpu(cpu);
5636 }
linux-4.10/kernel/sched/clock.c
294 /*
295 * Similar to cpu_clock(), but requires local IRQs to be disabled.
296 *
297 * See cpu_clock().
298 */
299 u64 sched_clock_cpu(int cpu)
300 {
301 struct sched_clock_data *scd;
302 u64 clock;
303
304 if (sched_clock_stable())
305 return sched_clock();
306
307 if (unlikely(!sched_clock_running))
308 return 0ull;
309
310 preempt_disable_notrace();
311 scd = cpu_sdc(cpu);
312
313 if (cpu != smp_processor_id())
314 clock = sched_clock_remote(scd);
315 else
316 clock = sched_clock_local(scd);
317 preempt_enable_notrace();
318
319 return clock;
320 }
321 EXPORT_SYMBOL_GPL(sched_clock_cpu);
(7) init_sched_fair_class()
linux-4.10/kernel/sched/fair.c
9474 __init void init_sched_fair_class(void)
9475 {
9476 #ifdef CONFIG_SMP
9477 open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
9478
9479 #ifdef CONFIG_NO_HZ_COMMON //在系统idle的时候,停掉tick。
9480 nohz.next_balance = jiffies;
9481 zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
9482 #endif
9483 #endif /* SMP */
9484
9485 }
公平调度器类和实时进程调度器类 被定义成为一个全局常量,分别是fair_sched_class 和 rt_sched_class。 struct sched_class 调度类,理解为接口的设计就可以了,虽然每个调度类有自己的调度算法(调度函数),但是外部使用调度类的接口都是一致的。
linux-4.10/kernel/sched/fair.c
9399 /*
9400 * All the scheduling class methods:
9401 */
9402 const struct sched_class fair_sched_class = {
9403 .next = &idle_sched_class,
9404 .enqueue_task = enqueue_task_fair,
9405 .dequeue_task = dequeue_task_fair,
9406 .yield_task = yield_task_fair,
9407 .yield_to_task = yield_to_task_fair,
9408
9409 .check_preempt_curr = check_preempt_wakeup,
9410
9411 .pick_next_task = pick_next_task_fair,
9412 .put_prev_task = put_prev_task_fair,
9413
9414 #ifdef CONFIG_SMP
9415 .select_task_rq = select_task_rq_fair,
9416 .migrate_task_rq = migrate_task_rq_fair,
9417
9418 .rq_online = rq_online_fair,
9419 .rq_offline = rq_offline_fair,
9420
9421 .task_dead = task_dead_fair,
9422 .set_cpus_allowed = set_cpus_allowed_common,
9423 #endif
9424
9425 .set_curr_task = set_curr_task_fair,
9426 .task_tick = task_tick_fair,
9427 .task_fork = task_fork_fair,
9428
9429 .prio_changed = prio_changed_fair,
9430 .switched_from = switched_from_fair,
9431 .switched_to = switched_to_fair,
9432
9433 .get_rr_interval = get_rr_interval_fair,
9434
9435 .update_curr = update_curr_fair,
9436
9437 #ifdef CONFIG_FAIR_GROUP_SCHED
9438 .task_change_group = task_change_group_fair,
9439 #endif
9440 };
linux-4.10/kernel/sched/rt.c
2325 const struct sched_class rt_sched_class = {
2326 .next = &fair_sched_class,
2327 .enqueue_task = enqueue_task_rt,
2328 .dequeue_task = dequeue_task_rt,
2329 .yield_task = yield_task_rt,
2330
2331 .check_preempt_curr = check_preempt_curr_rt,
2332
2333 .pick_next_task = pick_next_task_rt,
2334 .put_prev_task = put_prev_task_rt,
2335
2336 #ifdef CONFIG_SMP
2337 .select_task_rq = select_task_rq_rt,
2338
2339 .set_cpus_allowed = set_cpus_allowed_common,
2340 .rq_online = rq_online_rt,
2341 .rq_offline = rq_offline_rt,
2342 .task_woken = task_woken_rt,
2343 .switched_from = switched_from_rt,
2344 #endif
2345
2346 .set_curr_task = set_curr_task_rt,
2347 .task_tick = task_tick_rt,
2348
2349 .get_rr_interval = get_rr_interval_rt,
2350
2351 .prio_changed = prio_changed_rt,
2352 .switched_to = switched_to_rt,
2353
2354 .update_curr = update_curr_rt,
2355 };
这里只是简单列出sched_init() 的流程代码,在这个流程中初始化了很多数据结构体,这些数据结构的作用没有具体介绍,在后面需要了解的时候在具体介绍吧。现在先有个简单的了解,需要时再深入研究。
linux sched init简介相关推荐
- 浅析 Linux 初始化 init 系统: UpStart
浅析 Linux 初始化 init 系统: UpStart Upstart 简介 假如您使用的 Linux 发行版是 Ubuntu,很可能会发现在您的计算机上找不到/etc/inittab 文件了,这 ...
- Linux设备文件简介
设备文件简介 本文为转载,留给自己学习之用 大家可以直接到原作者的空间查看: <Linux设备文件简介> http://lamp.linux.gov.cn/Linux/device_fil ...
- Linux系统init过程之 UpStart
本文引自: 浅析 Linux 初始化 init 系统,第 2 部分: UpStart Upstart 简介 假如您使用的 Linux 发行版是 Ubuntu,很可能会发现在您的计算机上找不到/etc/ ...
- linux 创建 tmpfs 分区,【Linux】tmpfs简介及增加方式
一. 什么是tmpfs? tmpfs是一种基于内存的文件系统,它和虚拟磁盘ramdisk比较类似,但不完全相同,和ramdisk一样,tmpfs可以使用RAM,但它也可以使用swap分区来存储.而且传 ...
- linux wc 命令简介
此wc命令不是让大家没有食欲的地方.而是linux下一个简单的小命令. NAME wc - word, line, character, and byte count SYNOPSIS wc [-cl ...
- linux init进程是所有用户进程的祖先进程,Linux中init进程介绍及常用方法
init(为英语:initialization的简写)是 Unix 和 类Unix 系统中用来产生其它所有进程的程序.它以守护进程的方式存在,其进程号为1. 所谓的init进程,它是一个由内核启动的用 ...
- Kali Linux 安全渗透教程第二更Linux安全渗透简介
第1章 Linux安全渗透简介 渗透测试是对用户信息安全措施积极评估的过程.通过系统化的操作和分析,积极发现系统和网络中存在的各种缺陷和弱点,如设计缺陷.技术缺陷.本章将简要介绍Linux安全渗透及 ...
- 资料收集新一代 Linux 文件系统 btrfs 简介
来自: http://www.ibm.com/developerworks/cn/linux/l-cn-btrfs/ Btrfs 简介 文件系统似乎是内核中比较稳定的部分,多年来,人们一直使用 ext ...
- 面向dba的linux shell 脚本简介,面向 DBA 的 Linux Shell 脚本简介
DBA:Linux 面向 DBA 的 Linux Shell 脚本简介 作者:CasimirSaternos 学习一些在 Linux 上安装.运行和维护 Oracle 数据库所需的基本 bash sh ...
最新文章
- GDOP定位算法的MATLAB仿真
- Python字符串逐字符或逐词反转方法
- 用python处理excel的基本语法_《使用python3读取处理excel表的数据内容如何对内容求平均值》 用python读取excel文件...
- xuggler实现视频压缩_Xuggler视频处理简介
- PHP+SQLite3简约网址导航、书签管理器网站源码
- jQuery ajax error函数(交互错误信息的获取)
- 长文详解Attention、Seq2Seq与交互式匹配
- app = Flask(__name__) 是个什么东西
- mpush 服务端配置 for windows 服务自动运行
- node-opcua的使用 --- [1] 简单server
- Intellij (IDEA) 学生认证全流程
- Switch 开关 文字设置在一边显示
- 迷你音乐播放器v1.0正式上线!
- 什么是GPT,如何克隆GPT类型的磁盘?
- go语言中赋值出错:no new variables on left side of :=
- python人机大战小游戏代码
- 思博伦OpenFlow性能测试白皮书上篇
- 对搜索引擎不友好的网站具有怎样的特征?
- 锐捷AP胖模式配置方法
- 计算精确,完全可以作为包括高速公路在内的卵型曲线坐标计算。