Linux内核的idle进程分析
1. idle是什么
简单的说idle是一个进程,其pid号为 0。其前身是系统创建的第一个进程。也是唯一一个没有通过fork()产生的进程。
在smp系统中,每一个处理器单元有独立的一个执行队列,而每一个执行队列上又有一个idle进程,即有多少处理器单元。就有多少idle进程。
系统的空暇时间,事实上就是指idle进程的"执行时间"。既然是idle是进程。那我们来看看idle是怎样被创建,又详细做了哪些事情?
2. idle的创建
我们知道系统是从BIOS加电自检,载入MBR中的引导程序(LILO/GRUB),再载入linux内核開始执行的,一直到指定shell開始执行告一段落,这时用户開始操作Linux。
而大致是在vmlinux的入口
startup_32(head.S)中为pid号为0的原始进程设置了运行环境,然后原是进程開始运行start_kernel()完毕Linux内核的初始化工作。
包含初始化页表,初始化中断向量表,初始化系统时间等。继而调用 fork(),创建第一个用户进程:
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); 这个进程就是著名的pid为1的init进程,它会继续完毕剩下的初始化工作,然后execve(/sbin/init), 成为系统中的其它全部进程的祖先。关于init我们这次先不研究,回过头来看pid=0的进程,在创建了init进程后,pid=0的进程调用 cpu_idle()演变成了idle进程。
current_thread_info()->status |= TS_POLLING;
在 smp系统中。除了上面刚才我们讲的主处理器(运行初始化工作的处理器)上idle进程的创建,还有从处理器(被主处理器activate的处理器)上的idle进程,他们又是怎么创建的呢?接着看init进程,init在演变成/sbin/init之前,会运行一部分初始化工作,当中一个就是 smp_prepare_cpus(),初始化SMP处理器,在这过程中会在处理每一个从处理器时调用
task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, NULL, 0);
init_idle(task, cpu);
即从init中复制出一个进程,并把它初始化为idle进程(pid仍然为0)。从处理器上的idle进程会进行一些Activate工作,然后运行cpu_idle()。
整个过程简单的说就是,原始进程(pid=0)创建init进程(pid=1),然后演化成idle进程(pid=0)。init进程为每一个从处理器(执行队列)创建出一个idle进程(pid=0)。然后演化成/sbin/init。
3. idle的执行时机
idle 进程优先级为MAX_PRIO,即最低优先级。
早先版本号中,idle是參
与调度的。所以将其优先级设为最低。当没有其它进程能够执行时,才会调度执行idle。而眼下的版本号中idle并不在执行队列中參与调度,而是在执行队列结构中含idle指针,指向idle进程,在调度器发现执行队列为空的时候执行,调入执行。
4. idle的workload 从上面的分析我们能够看出,idle在系统没有其它就绪的进程可执行的时候才会被调度。无论是主处理器。还是从处理器,最后都是执行的cpu_idle()函数。所以我们来看看cpu_idle做了什么事情。 由于idle进程中并不执行什么有意义的任务,所以通常考虑的是两点:1.节能,2.低退出延迟。
其核心代码例如以下: void cpu_idle(void) { int cpu = smp_processor_id(); current_thread_info()->status |= TS_POLLING; /* endless idle loop with no priority at all */ while (1) { tick_nohz_stop_sched_tick(1); while (!need_resched()) {
check_pgt_cache(); rmb();
if (rcu_pending(cpu)) rcu_check_callbacks(cpu, 0); if (cpu_is_offline(cpu)) play_dead();
local_irq_disable();
__get_cpu_var(irq_stat).idle_timestamp = jiffies; /* Don't trace irqs off for idle */ stop_critical_timings(); pm_idle();
start_critical_timings(); }
tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); } }
循环推断need_resched以减少退出延迟,用idle()来节能。 默认的idle实现是hlt指令。hlt指令使CPU处于暂停状态,等待硬件中断发生的时候恢复,从而达到节能的目的。
即从处理器C0态变到C1态(见 ACPI标准)。这也是早些年windows平台上各种"处理器降温"工具的主要手段。当然idle也能够是在别的ACPI或者APM模块中定义的,甚至是自己定义的一个idle(比方说nop)。
小结:
1.idle是一个进程,其pid为0。
2.主处理器上的idle由原始进程(pid=0)演变而来。从处理器上的idle由init进程fork得到,可是它们的pid都为0。
3.Idle进程为最低优先级。且不參与调度。仅仅是在执行队列为空的时候才被调度。
4.Idle循环等待need_resched置位。默认使用hlt节能。
Linux内核的idle进程分析的更多相关文章
- Linux内核--网络栈实现分析(十一)--驱动程序层(下)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870 更多请查看专栏,地 ...
- Linux内核态抢占机制分析(转)
Linux内核态抢占机制分析 http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html 摘 要]本文首先介绍非抢占式内核(Non-Preemptive ...
- Linux内核抢占实现机制分析【转】
Linux内核抢占实现机制分析 转自:http://blog.chinaunix.net/uid-24227137-id-3050754.html [摘要]本文详解了Linux内核抢占实现机制.首先介 ...
- (转)Linux内核基数树应用分析
Linux内核基数树应用分析 ——lvyilong316 基数树(Radix tree)可看做是以二进制位串为关键字的trie树,是一种多叉树结构,同时又类似多层索引表,每个中间节点包含指向多个节点的 ...
- Linux内核--网络栈实现分析(七)--数据包的传递过程(下)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7545855 更多请查看专栏,地 ...
- 【转载】linux内核笔记之进程地址空间
原文:linux内核笔记之进程地址空间 进程的地址空间由允许进程使用的全部线性地址组成,在32位系统中为0~3GB,每个进程看到的线性地址集合是不同的. 内核通过线性区的资源(数据结构)来表示线性地址 ...
- linux内核SPI总线驱动分析(一)(转)
linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析 (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...
- Linux内核--网络栈实现分析(二)--数据包的传递过程--转
转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的”(上 ...
- linux内核中链表代码分析---list.h头文件分析(一)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...
随机推荐
- django rest_framework比较完整的自定义实现样例
里面有自定义的更新策略, 序列化时,考虑nest及显示. 很有参考意义. 然后,前端,可以考虑用angular.js或vue.js实现. 每次以token进行认证. url.py router = D ...
- CentOS7中开机出现end_request:I/O error,dev fd0,sector 0的解决办法
https://blog.csdn.net/wangjinyang_123/article/details/40583635
- JS函数练习题
第一题:封装一个输入半径求圆的面积的函数 var banJing = parseInt(prompt("请输入圆的半径")); var x = m(banJing); alert( ...
- 生成元(UVa1583)
题目具体描述见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...
- int类中的方法
我们知道在python中,一切对象都是类,对象的方法都封装在类中,现在来探讨一下int类中的方法: 我们可以通过help(int)和dir(int)来查看int类中都封装了那些方法: 1.bi ...
- lr_get_transaction_duration 函数介绍
lr_get_transaction_duration 用于获取事务所消耗的时间. 实例: Action() { double trans_time; //定义变量 web_url("www ...
- vscode 解决vue emmet不起作用
现在 vscode 自带的提示已经很好用了,大部分时间自带的提示展示的 emmet 内容已经是所需的了 在首选项 设置中配置 v1.15.1 之后需要这样设置: "emmet.trigger ...
- Scrapy 笔记(三)
摘抄自Python 一.随机user-agent 的设置 关于配置和代码 这里我找了一个之前写好的爬虫,然后实现随机更换User-Agent,在settings配置文件如下: DOWNLOADER_M ...
- python升级带来的yum异常:File "/usr/bin/yum", line 30
问题: $ yum File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ SyntaxError: invalid ...
- TCP 的那些事儿-1
TCP是一个巨复杂的协议,因为他要解决很多问题,而这些问题又带出了很多子问题和阴暗面.所以学习TCP本身是个比较痛苦的过程,但对于学习的过程却能让人有很多收获.关于TCP这个协议的细节,我还是推荐你去 ...