Blogging Fan's Planet

Live Simply, Stay Happy, Give More, Expect Less
随笔 - 3, 文章 - 0, 评论 - 0, 引用 - 0
数据加载中……

[导入]learning kernel -- 进程管理

====================================
learning kernel -- 进程管理
====================================

linux系统的kernel stack和process descriptor
=========================================
系统为每个进程在linux内核中分配一个kernel stack,每个kernel stack的底端(对于向下增长的栈)存放struct thread_info:

struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
unsigned long flags;
unsigned long status;
__u32 cpu;
__s32 preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
unsigned long previous_esp;
__u8 supervisor_stack[0];
};
其中thread_info里的struct task_struct里面保存了运行进程的几乎所有信息。内核提供current宏得到当前运行进程的task_struct的地址。
一个进程的可以具有5种状态:

* TASK_RUNNING: 该进程正在运行或者在runqueue里通过进程调度等待运行
* TASK_INTERRUPTIBLE: 该进程处于睡眠状态,放在waitqueue里面,等待特定的条件来唤醒。当收到信号,它也会被唤醒。唤醒后变成TASK_RUNNING状态。
* TASK_UNINTERRUPTIBLE: 和TASK_INTERRUPTIBLE类似,但不能使用信号唤醒。
* TASK_ZOMBIE: 子进程退出后但父进程还没有使用wait4来获取子进程退出状态,此时子进程处于TASK_ZOMBIE。此时子进程基本上已经释放了内存和打开的文件等,但它对应的kernel stack和task_struct内容还是保存的。这些在父进程调用完wait4后来回收。
* TASK_STOPED

Process and The Linux Implementation of Threads
================================================
Why Copy-on-Write
-----------------
Linux系统运行基本上都是基于进程fork一个子进程方式的,为此如何尽量减少fork的成本是个很重要的问题。本来fork一个子进程要拷贝父进程的kernel stack, task_struct, 父进程的user space的栈空间等,这样的开销是比较大的,尤其对于很多进程,常常fork子进程后马上来一个exec清除这些内容,拷贝的过程完全是浪费的。Copy-on-Write的想法是fork一个子进程后不马上copy那些内容(但kernel stack和task_struct还是省不了的,不过这两个结构不大),而是共享这些资源。只有在需要write修改这些数据时才会标记哪些数据然后copy这些标记的数据。这样就保证了quick process execution。

Process Creation--fork过程
-------------------------
fork调用clone函数, clone再调用do_fork,do_fork做以下事:dup_task_struct, copy_process, get_pid,然后根据copy_process的参数选择到底是copy还是share打开的文件,文件系统信息,信号处理器,进程地址空间等。这些都完了后split父进程的时间片给一部分给子进程。

The Linux Implementation of Threads
-----------------------------------
linux实现线程的方式有些unique,几乎把线程当作进程来处理。配合Copy-on-Write技术,达到了数据的共享,对于每个线程只是copy一份task_struct的结构和kernel stack。

Process Termitation
-------------------
每个进程结束后都会调用exit(编译器会在main函数后默认添加它),它会release该进程占用的空间,files,fs等,set它的exit_code,然后通知父进程自己退出并把自己设置为TASK_ZOMDIE状态。此时kernel stack和task_struct内容还保留,只有父进程调用wait返回后这些资源才开始回收。
文章来源:http://fanfuns.blogspot.com/2009/04/learning-kernel.html

posted on 2009-11-26 17:15 Fan Hongwei 阅读(162) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理