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(&regs), 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节能。

时间: 2024-12-27 16:06:01

Linux内核的idle进程分析的相关文章

Linux内核抢占实现机制分析【转】

Linux内核抢占实现机制分析 转自:http://blog.chinaunix.net/uid-24227137-id-3050754.html [摘要]本文详解了Linux内核抢占实现机制.首先介绍了内核抢占和用户抢占的概念和区别,接着分析了不可抢占内核的特点及实时系统中实现内核抢占的必要性.然后分析了禁止内核抢占的情况和内核抢占的时机,最后介绍了实现抢占内核所做的改动以及何时需要重新调度. [关键字]内核抢占,用户抢占,中断, 实时性,自旋锁,抢占时机,调度时机,schedule,pree

Linux内核抢占实现机制分析

Sailor_forever  [email protected] 转载请注明 http://blog.csdn.net/sailor_8318/archive/2008/09/03/2870184.aspx [摘要]本文详解了Linux内核抢占实现机制.首先介绍了内核抢占和用户抢占的概念和区别,接着分析了不可抢占内核的特点及实时系统中实现内核抢占的必要性.然后分析了禁止内核抢占的情况和内核抢占的时机,最后介绍了实现抢占内核所做的改动以及何时需要重新调度. [关键字]内核抢占,用户抢占,中断, 

(转)Linux内核基数树应用分析

Linux内核基数树应用分析 ——lvyilong316 基数树(Radix tree)可看做是以二进制位串为关键字的trie树,是一种多叉树结构,同时又类似多层索引表,每个中间节点包含指向多个节点的指针数组,叶子节点包含指向实际对象的指针(由于对象不具备树节点结构,因此将其父节点看做叶子节点). 图1是一个基数树样例,该基数树的分叉为4(2^2),树高为4,树的每个叶子结点用来快速定位8位文件内偏移,可以定位4x4x4x4=256(叶子节点的个数)页,如:图中虚线对应的两个叶子结点的路径组成值

Linux内核--网络栈实现分析(十一)--驱动程序层(下)

本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870 更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html 作者:闫明 注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析.”(下)“表示分析是从上向下分析. 在博文Linux内核--网络栈

Linux内核态抢占机制分析(转)

Linux内核态抢占机制分析  http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html 摘 要]本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核(Preemptive Kernel)的区别.接着分析Linux下有两种抢占:用户态抢占(User Preemption).内核态抢占(Kernel Preemption).然后分析了在内核态下:如何判断能否抢占内核(什么是可抢占的条件):何时触发重新调度(何时设置可抢

linux内核学习:进程管理

进程状态 TASK_RUNNING 可运行或正在运行 TASK_INTERRUPTIBLE 进程被阻塞,但可以被信号唤醒 TASK_UNINTERRUPTIBLE 进程被阻塞,且不可以被信号唤醒 TASK_STOPPED 进程已停止,且不能再投入运行 TASK_ZOMBIE 所谓的僵死进程,进程描述符仍然保留 关键函数和结构 task_struct thread_info current clone fork exec wait exit linux内核学习:进程管理,布布扣,bubuko.co

【转载】linux内核笔记之进程地址空间

原文:linux内核笔记之进程地址空间 进程的地址空间由允许进程使用的全部线性地址组成,在32位系统中为0~3GB,每个进程看到的线性地址集合是不同的. 内核通过线性区的资源(数据结构)来表示线性地址区间,线性区是由起始线性地址,长度和一些访问权限来描述的.线性区的大小为页框的整数倍,起始地址为4096的整数倍. 下图展示了x86 Linux 进程的地址空间组织结构: 正文段 .text ,这是CPU执行的机器指令部分.通常正文段是共享的,而且是只读的,以防止程序修改其自身的指令. 数据段 .d

Linux内核剖析 之 进程地址空间(二)

//接前一章,本节主要介绍线性区以及相关线性区的操作. 线性区 Linux通过类型为vm_area_struct的对象实现线性区. vm_area_struct: struct vm_area_struct { struct mm_struct * vm_mm; /* The address space we belong to. */ unsigned long vm_start; /* Our start address within vm_mm. */ unsigned long vm_e

linux内核中与进程相关的数据结构(基于linux-mainline-rc4)

1.进程描述符    struct task_struct {  volatile long state; ....... struct list_head tasks; ....... struct mm_struct *mm, *active_mm; ....... struct vm_area_struct *vmacache[VMACACHE_SIZE]; ...... pid_t pid; pid_t tgid; .......   }所在文件:include/linux/sched.