Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22413
  • 博文数量: 18
  • 博客积分: 810
  • 博客等级: 准尉
  • 技术积分: 205
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-10 21:09
文章分类
文章存档

2009年(15)

2008年(3)

我的朋友

分类: LINUX

2009-04-29 13:03:58

 

3.1 进程描述符及任务结构

进程存放在任务队列task list的双向循环链表中;

链表中存放进程描述符,task_struct(定义在)

linux通过slab分配器分配task_struct结构,达到对象复用和缓存着色的目的;

slab分配器动态生成task_struct,只需在栈底船舰一个新的结构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结构在它的内核栈的尾端分配,其中的task域指向实际task_struct指针。

current_thread_info()->task;指向当前进程描述符

进程状态:

  • TASK_RUNNING
  • TASK_INTERRUPTIBLE——进程正在睡眠,某些条件达成后被唤醒
  • TASK_UNINTERRUPTIBLE——不可被打断
  • TASK_ZOMBIE——进程已结束,父进程未调用wait4(),子进程描述符仍被保留
  • TASK_STOPPED

 

set_task_state(task, state);设置进程状态

set_current_state(state)set_task_state(current, state)等价;

进程描述符中还包括进程间的关系,指向父进程的task_struct parent以及称为children的子进程链表

3.2 进程创建

fork()+exec()——fork()通过拷贝当前进程创建一个子进程;exec()读取可执行文件并将其载入地址空间运行。

写时拷贝——父子进程共享同一拷贝,只有在需要写入时,数据才会复制,从而使各个进程拥有各自的拷贝

fork()

调用clone()

clone()调用do_fork()

do_fork()调用copy_process()

(1) 调用dup_task_struct()为新进程创建内核栈、thread_info结构和task_struct,与当前进程值相同;

(2) 父子进程开始区别,子进程描述符中很多成员清0或设置初始值;

(3) 子进程状态设为TASK_UNINTERRUPTIBLE,以保证不会投入运行;

(4) 调用copy_flags()更新task_structflags成员,表明进程是否拥有超级用户权限的PF_SUPERPRIV标志清0,表明进程还没调用exec()函数的PF_FORKNOEXEC标志被设置;

(5) get_pid()为新进程获取有效PID

(6) 根据传递给clone()的参数标志,拷贝或共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间等。

(7) 父子进程平分剩余时间片;

(8) copy_process()作扫尾工作并返回一个指向子进程的指针

clone()参数标志:

 

Flag

Meaning

CLONE_FILES

Parent and child share open files.

CLONE_FS

Parent and child share filesystem information.

CLONE_IDLETASK

Set PID to zero (used only by the idle tasks).

CLONE_NEWNS

Create a new namespace for the child.

CLONE_PARENT

Child is to have same parent as its parent.

CLONE_PTRACE

Continue tracing child.

CLONE_SETTID

Write the TID back to user-space.

CLONE_SETTLS

Create a new TLS for the child.

CLONE_SIGHAND

Parent and child share signal handlers and blocked signals.

CLONE_SYSVSEM

Parent and child share System V SEM_UNDO semantics.

CLONE_THREAD

Parent and child are in the same thread group.

CLONE_VFORK

vfork() was used and the parent will sleep until the child wakes it.

CLONE_UNTRACED

Do not let the tracing process force CLONE_PTRACE on the child.

CLONE_STOP

Start process in the TASK_STOPPED state.

CLONE_SETTLS

Create a new TLS (thread-local storage) for the child.

CLONE_CHILD_CLEARTID

Clear the TID in the child.

CLONE_CHILD_SETTID

Set the TID in the child.

CLONE_PARENT_SETTID

Set the TID in the parent.

CLONE_VM

Parent and child share address space.

3.3 线程

线程也拥有自己的task_struct,与普通进程的区别是内核线程没有独立的地址空间(mm指针为NULL

int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)

一般情况下,内核线程会将创建的函数永远执行下去,该函数由一个循环构成,需要时唤醒并执行,完成任务会自行休眠。

3.4 进程终结

exit()

调用do_exit()

(1) task_struct中的标志成员设置为PF_EXITING

(2) 调用del_timer_sync()删除任意内核定时器;

(3) 调用acct_process()来输出记账信息;

(4) 调用__exit_mm()放弃进程占用的内存描述符mm_struct

(5) exit_sem()

(6) 调用__exit_files(), __exit_fs(), exit_namespace(), exit_sighand() 分别递减文件描述符、文件系统数据、进程名字空间、信号处理函数的引用计数;

(7) task_struct中的exit_code成员中的任务退出代码设置为exit()提供的代码;

(8) 调用exit_notify()向父进程发送信号,将子进程的父进程重新设置为线程组中的其他进程或init进程,进程状态设置为TASK_ZOMBE

(9) 调用schedule()切换到其他进程

调用do_exit()后,线程已僵死,但系统保留了进程描述符。

删除进程描述符release_task()

(1) free_uid()减少进程拥有者的进程使用计数;

(2) unhash_process()pidhash上删除该进程,同时从task_list中删除该进程;

(3) 将跟踪进程的父进程重设为其最初的父进程并将其从ptract list中删除;

(4) 调用put_task_struct()释放进程内核栈和thread_info所占的页,释放task_struct所占的slab高速缓存。

阅读(354) | 评论(0) | 转发(0) |
0

上一篇:Chap15 页高度缓存和页回写

下一篇:目录

给主人留下些什么吧!~~