内核资源收集
1. 传统unix系统把一些重要任务委托给周期性执行的进程, 这些任务包括刷新磁盘高速缓存, 交换出不用的页框, 维护网络
连接等等.
如果把它们放到后台调度, 能得到较好的响应. 现代操作系统把它们的函数委托给内核线程(kernel thread). linux系统中内
核在以下几方面不同于普通进程:
a. 内核线程只运行在内核态. 普通进程可运行在内核态,也可以运行在用户态.
b. 内核线程因为只运行在内核态, 所以只使用大于PAGE_OFFSET的线性地址空间. 普通进程(32位系统)可以用4GB的
线性地址空间.
2. 创建一个内核线程
kernel_thread()函数创建一个新的内核线程. 其参数包括所要执行的内核函数的地址(fn). 新内核函数开始执行fn函数,如果
该函数结束, 内核线程执行系统调用_exit(), 并把fn()的返回值传递给它
3. 进程0
所有进程的祖先叫进程0, idle进程或因为历史原因叫做swapper进程, 它是在linux的初始化阶段从无到有创建的一个内核
线程. 这个祖先进程使用了一系列表态分配的数据结构:
a. 由init_task变量中的进程描述符, 由INIT_TASK宏完成对它的初始化.
b. 存放在init_thread_union变量中的thread_info描述符和内核堆栈, 由INIT_THREAD_INFO宏完成对它们的初始化.
c. 由进程描述符指向的下列表:
1>init_mm
2>init_fs
3>init_files
4>init_signals
5>init_sighand
这些表分别由下列宏初始化:
INIT_MM
INIT_FS
INIT_FILES
INIT_SIGNAL
INIT_SIGHAND
d. 主内核页全局目录存放在swapper_pg_dir中
start_kernel()函数初始化内核需要的所有数据结构, 激活中断, 创建另一个进程1(一般叫init进程):
start_kernel(init, NULL, CLONE_FS|CLONE_SIGHAND)
调试程序选择到进程1时, init进程开始执行init()函数. 创建init进程后, 进程0执行cpu_idle()函数,该函数本质上是在
开中断的情况下重复执行hlt汇编指令. 只有没有其它进程处于TASK_RUNNING状态时, 调试程序才选择进程0.
多处理器系统中, 每个CPU都有一个进程0. 在系统初始化阶段,运行在CPU0上的swapper进程初始化内核数据结构,然后激活
其它CPU,并通过copy_process()函数创建另外的swapper进程.
4. 进程1
进程0创建内核线程执行init()函数, init()依次完成内核初始化. init()调用exec()系统调用装入可执行程序init. 至此, init内核
线程变为一个普通进程.且拥有自己的每进程(per-process)内核数据结构. 系统关闭前, init进程一直存活.
5. 其它内核线程
linux使用很多其他内核线程. 其中一些在初始化阶段创建,一直运行到系统关闭; 而其它一些在内核必须执行一个任务时
"按需"创建, 这种任务在内核的执行上下文中得到很好的执行.
一些内核线程例子:
a. keventd
执行keventd_wq工作队列
b. kapmd
处理高级电源管理相关事件
c. kswapd
执行内存回收
d. pdflush
刷新"脏"缓冲区中的内容到磁盘以回收内存
e. kblock
执行kblockd_workqueue工作队列中的函数. 实际上它周期性的激活块设备驱动程序
f. ksoftirqd
运行tasklet; 系统中每个CPU都有这样一个内核线程
阅读(528) | 评论(0) | 转发(0) |