=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)

上传人:第*** 文档编号:31311039 上传时间:2018-02-06 格式:DOC 页数:6 大小:60.50KB
返回 下载 相关 举报
=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)_第1页
第1页 / 共6页
=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)_第2页
第2页 / 共6页
=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)_第3页
第3页 / 共6页
=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)_第4页
第4页 / 共6页
=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)_第5页
第5页 / 共6页
点击查看更多>>
资源描述

《=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)》由会员分享,可在线阅读,更多相关《=5内核启动流程之(start_kernel()-rest_init()-cpu_idle() schedule() 0&1号进程)(6页珍藏版)》请在金锄头文库上搜索。

1、1) _lookup_processor_type(); 【查找处理器类型=位于 arch/arm/kernel/head.S】2) _lookup_machine_type() ; 【查找机器类型】3) _vet_atags(); 【函数实现的就是判断 r2 是否是有效的 tag 列表指针,如果不是,就将零指针赋值给 r2】4) _create_page_tables(); 【创建页表】5) _enable_mmu(); 【使能 MMU】6) _mmap_switched(); 【拷贝数据,清 BBS】decompress_kernel()【解压缩内核文件=位于 arch/arm/boot/

2、compressed/misc.c】7) start_kernel(); 【进入真正的内核初始化函数=位于 init/main.c】各种初始化函数86) rest_init(); 【最后的初始化操作】87) cpu_idle(); 【函数会被调用来使系统处于闲置(idle)状态并等待用户程序的执行。至此,整个 Linux 内核启动完毕! 】【1】asmlinkage void _init start_kernel(void)各种初始化函数/* Do the rest non-_inited, were now alive */rest_init();【2 】 static noinline v

3、oid _init_refok rest_init(void)int pid;rcu_scheduler_starting();/内核 RCU 锁机制调度启动,因为下面就要用到/* 我们必须先创建 init 内核线程,这样它就可以获得 pid 为 1。* 尽管如此 init 线程将会挂起来等待创建 kthreads 线程。* 如果我们在创建 kthreadd 线程前调度它,就将会出现 OOPS。*/kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);/创建 kernel_init 内核线程,内核的 1 号进程!【此处创建 ini

4、t 进程,就是韦东山 342 页的 init_post()函数,参考”=5 内核启动流程之(init_post()在 rest_init()中被调用.doc”】numa_default_policy();/设定 NUMA 系统的内存访问策略为默认pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);/创建 kthreadd 内核线程,它的作用是管理和调度其它内核线程。它循环运行一个叫做 kthreadd 的函数,该函数的作用是运行 kthread_create_list 全局链表中维护的内核线程。调用 kthread_creat

5、e创建一个 kthread,它会被加入到 kthread_create_list 链表中;被执行过的 kthread会从 kthread_create_list 链表中删除;且 kthreadd 会不断调用 scheduler 函数让出CPU。此线程不可关闭。上面两个线程就是我们平时在 Linux 系统中用 ps 命令看到:rcu_read_lock();kthreadd_task = find_task_by_pid_ns(pid, rcu_read_unlock();complete(/获取 kthreadd 的线程信息,获取完成说明 kthreadd 已经创建成功。并通过一个 compl

6、ete 变量(kthreadd_done )来通知 kernel_init 线程。/* 为让系统运作起来,* boot idle 线程必须至少执行一次 schedule():*/init_idle_bootup_task(current);/设置当前进程为 idle(闲置)进程类。preempt_enable_no_resched();/使能抢占,但不重新调度schedule();/执行调度,切换进程。preempt_disable();/进程调度完成,回到这里,禁用抢占。/*在抢占禁用时调用 cpu_idle*/cpu_idle();/此时内核本体进入了 idle 状态,用循环消耗空闲的 C

7、PU 时间片,该函数从不返回。在有其他进程需要工作的时候,该函数就会被抢占!这个函数因构架不同而异。【3 】 void cpu_idle(void)local_fiq_enable();/这行代码是打开 ARM 系统的快速中断,所谓的 FIQ 是相对于普通的/IRQ 来说的,FIQ 是可以打断普通的 IRQ 中断,反之不行。/*下面就进入无限循环的空闲进程处理:*/while (1)void (*idle)(void)= pm_idle;/这行代码是调用定制的空闲处理函数。 【自己挂接,否则使用默认空闲处理函数】/1.idle 是一个进程,其 pid 为 0。/2.主处理器上的 idle 由原

8、始进程 (pid=0)演变而来。协从处理器上的 idle 由init 进程 fork 得到,但是它们的 pid 都为 0。/3.Idle 进程为最低优先级,且不参与调度,只是在运行队列为空的时候才被调度。/4.Idle 循环等待 need_resched 置位。默认使用 hlt 节能。#ifdef CONFIG_HOTPLUG_CPUif(cpu_is_offline(smp_processor_id()leds_event(led_idle_start);/点亮 idle 进程指示灯,CPU 处于空闲状态。cpu_die();/CPU 死亡?#endif /HOTPLUG=热插拔 这段代码是

9、处理热插拔的 CPU 机制,当允许当前这个/CPU 进入睡眠状态,就可以进入。if (!idle)idle =default_idle;/这段代码是当没有用户定义的空闲处理函数时,就调用缺省的空闲处理函/数。缺省的空闲处理函数,就会调用系统架构的空闲处理函数。/默认的 idle 实现是 hlt 指令,hlt 指令使 CPU 处于暂停状态,等待硬件中断发生的时候恢复,从而达到节能的目的。默认的 idle 实现是 hlt 指令,hlt 指令使 CPU 处于暂停状态,等待硬件中断发生的时候恢复,从而达到节能的目的。/【与 while(1)第一行的代码遥相呼应 】leds_event(led_idle

10、_start);/这行代码是打开 LED 显示空闲运行状态。 【告诉外界我现在是空闲状态】tick_nohz_stop_sched_tick(1);/这行代码是停止进程调度计数。while(!need_resched()【暗藏小循环:内核即将返回用户空间的时候,如果 need resched 标志被设置,会导致 schedule()被调用,此时就会发生用户抢占。 】idle();/这段代码是当需要调度标志为空时,就不断调用空闲处理函数进行运行。/【这段代码涉及用户抢占机制,need_resched()=1 表示发生了抢占,马上终止空闲进程并启动调度器。 】leds_event(led_idle

11、_end);/这行代码是当需要调度其它进程运行了,LED 结束显示空闲运行状态。/【告诉外界我现在不是空闲状态】tick_nohz_restart_sched_tick();/这行代码是重新开始计算调度运行计数。preempt_enable_no_resched();/使能抢占,但不重新调度schedule();/这行代码是对进程任务进行调度,以便立即运行正在等待的任务。/schedule()是调度器函数preempt_disable();/preempt_enable()开启抢占/preempt_disable()禁止抢占/preempt_enable_no_resched()开始抢占无需重

12、新调度/while(1)结束1 内核抢占概述2.6 新的可抢占式内核是指内核抢占,即当进程位于内核空间时,有一个更高优先级的任务出现时,如果当前内核允许抢占,则可以将当前任务挂起,执行优先级更高的进程。在 2.5.4 版本之前, Linux 内核是不可抢占的,高优先级的进程不能中止正在内核中运行的低优先级的进程而抢占 CPU 运行。进程一旦处于核心态( 例如用户进程执行系统调用),则除非进程自愿放弃 CPU,否则该进程将一直运行下去,直至完成或退出内核。与此相反,一个可抢占的 Linux 内核可以让 Linux内核如同用户空间一样允许被抢占。当一个高优先级的进程到达时,不管当前进程处于用户态还

13、是核心态,如果当前允许抢占,可抢占内核的 Linux 都会调度高优先级的进程运行。2 用户抢占内核即将返回用户空间的时候,如果 need resched 标志被设置,会导致schedule()被调用,此时就会发生用户抢占。在内核返回用户空间的时候,它知道自己是安全的。所以,内核无论是在从中断处理程序还是在系统调用后返回,都会检查 need resched 标志。如果它被设置了,那么,内核会选择一个其他(更合适的) 进程投入运行。简而言之,用户抢占在以下情况时产生:从系统调返回用户空间。从中断处理程序返回用户空间。【请看调度器函数】/* * schedule() is the main sche

14、duler function. */ 【4 】 asmlinkage void _sched schedule(void) struct task_struct *prev, *next; unsigned long *switch_count; struct rq *rq; int cpu; need_resched: preempt_disable();/禁止内核抢占cpu = smp_processor_id();/获取当前 CPUrq = cpu_rq(cpu);/获取该 CPU 维护的运行队列(run queue)rcu_note_context_switch(cpu);/更新全局状

15、态,标识当前 CPU 发生上下文的切换。 prev = rq-curr; /运行队列中的 curr 指针赋予 prev。 schedule_debug(prev);if (sched_feat(HRTICK)hrtick_clear(rq);raw_spin_lock_irq( /锁住该队列 switch_count = /记录当前进程的切换次数 if (prev-state & !(preempt_count() & PREEMPT_ACTIVE) /是否同时满足以下条件:1 该进程处于停止状态,2 该进程没有在内核态被抢占。if (unlikely(signal_pending_state

16、(prev-state, prev) /若不是非挂起信号,则将该进程状态设置成 TASK_RUNNING prev-state = TASK_RUNNING; else /若为非挂起信号则将其从队列中移出 /* * If a worker is going to sleep, notify and * ask workqueue whether it wants to wake up a * task to maintain concurrency. If so, wake * up the task. */ if (prev-flags & PF_WQ_WORKER) struct task_struct *to_wakeup;

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 中学教育 > 其它中学文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号