Linux内核设计与实现——进程管理

主要内容

  • 进程
  • 进程描述符及任务结构
  • 进程创建
  • 线程在linux中的实现
  • 进程终结

1. 进程

进程不仅仅是一段可执行程序代码,还包含其他资源,如打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个或多个执行线程,存放全局变量的数据段等等。具体可见进程的地址空间。

线程是进程中活动的对象,拥有独立的PC程序计数器,进程栈和一组进程寄存器,是内核调度的基本对象。

进程的两种虚拟机制:虚拟处理器和虚拟内存

相关函数:

  • fork(),系统调用从内核返回两次,一次回到父进程,一次回到新产生的子进程
  • exec(),创建新的地址空间并载入程序
  • exit() 退出执行
  • wait() , waitpid(),父进程等待子进程终结

2. 进程描述符及任务结构

双向链表的任务队列

  1. 分配进程描述符
    linux通过slab分配器分配task_struct结构,通过预先分配和重复使用,可以避免动态分配和释放带来的资源消耗。
    在进程的内核栈中,每个任务的thread_info结构在它内核栈的尾端分配,结构中task域存放的是指向该任务实际task_struct的指针。
  2. 进程描述符的存放
    pid,最大值默认为short int的最大值32768,可以修改pid_max文件来提高上限
  3. 进程状态


    进程状态转化.png
  • TASK_RUNNING,运行——进程或者正在执行,或者在运行队列中等待执行
  • TASK_INTERRUPTIBLE,可中断——进程正在睡眠(被阻塞),等待某些条件的达成
  • TASK_UNINTERRUPTIBLE,不可中断
  • _TASK_TRACED,被其它进程跟踪的进程
  • _TASK_STOPPED,进程停止执行,如接收到SIGSTOP,SIGTINT等信号
  1. 设置当前进程状态
    set_task_state(task, state)
  2. 进程上下文
    当一个程序执行了系统调用或者触发了某个异常,它就陷入了内核空间,此时,我们呈内核“代表进程执行”并处于进程上下文中
  3. 进程家族树
    Unix系统的进程之间存在一个明显的集成关系,所有进程都是PID为1的init进程的后代
    进程关系:父子,兄弟,在进程描述符中存放,每个task_struct都有指向父进程、子进程的指针

3. 进程创建

linux中创建进程分两步,fork和exec

  • linux的fork()使用写时拷贝(copy-on-write)实现,因为有可能fork后是执行一个新的映像,父进程和子进程共享同一份拷贝,只有在需要写入的时候,才会被复制。因此,fork()的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符

linux通过clone()系统调用do_fork(),do_fork()调用copy_process()函数,然后让进程开始运行,copy_process()完成的工作如下:

  1. 调用dup_task_struct()为新进程分配内核栈,task_struct等,其中的值与当前进程相同,此时,子进程与父进程的描述符也相同
  2. 检查创建子进程后,当前用户所拥有的进程数目没有超出给它分配的资源限制
  3. 子进程使自己与父进程区别开来。进程描述符内许多统计信息成员都要被清0或设为初始值
  4. 子进程状态设置为TASK_UNINTERRUPTIBLE,以保证不会投入运行
  5. 更新task_struct的flags成员,表明进程权限等
  6. 调用alloc_pid()为新进程分配一个有效的PID
  7. 根据传递给clone()的参数,copy_process()拷贝或共享打开的文件,文件系统信息,信号处理函数,进程地址空间和命名空间等
  8. 扫尾工作,返回指向子进程的指针

回到do_fork()函数后,内核会优先选择子进程首先执行,因为子进程通常会马上调用exec()函数,可以避免写时拷贝的额外开销。
创建进程的fork()函数实际上最终是调用clone()函数。

vfork()调用,不拷贝父进程的页表项,子进程作为父进程的一个单独的线程在它的地址空间里运行,父进程被阻塞直到子进程退出或执行exec(),子进程不能向地址空间写入。
现在for()引入了写时拷贝并且明确了子进程先执行,vfork()的好处就仅限于不执行父进程的页表项了。
而且如果exec()调用失败会怎样?

4. 线程在Linux中的实现

从内核的角度来说,并没有线程这个概念,Linux把所有的线程都当做进程来实现,线程仅仅被视为一个与其他进程共享某些资源的进程。
Windows在内核中提供了专门支持线程的机制。而对Linux来说,只是一种进程间共享资源的手段。

线程的创建和普通进程的创建类似,只不过调用clone()的时候需要传递额外参数标识

  1. 一个普通的fork():clone(SIGCHLD, 0)
  2. 创建线程:clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) 使子进程和父进程共享地址空间,文件资源,文件描述符,信号处理程序等。

内核线程:

  • 内核线程没有独立的地址空间,只在内核空间运行,可以被调度或抢占

5. 进程终结

当一个进程终结时,内核必须释放它所占有的资源并告知父进程
终结任务依靠do_exit()来完成:

  1. 设置task_struct中的标识成员设置为PF_EXITING
  2. 调用del_timer_sync()删除内核定时器, 确保没有定时器在排队和运行
  3. 调用exit_mm()释放进程占用的mm_struct
  4. 调用sem__exit(),使进程离开等待IPC信号的队列
  5. 调用exit_files()和exit_fs(),释放进程占用的文件描述符和文件系统资源
  6. 把存放在task_struct的exit_code成员中的任务退出代码置为exit()提供的退出代码,或者去完成任何其他由内核机制规定的退出动作,退出代码存放在此供父进程随时检索
  7. 调用exit_notify()向父进程发送信号,给子进程重新找养父(init进程),并把进程状态设为EXIT_ZOMBIE
  8. do_exit()调用schedule()切换到新的进程,不会再被调度,do_exit()永不返回

至此,与进程相关联的所有资源都被释放掉了,进程处于(EXIT_ZONBIE退出状态)且不可运行,占用的内存仅剩内核栈、thread_info结构和tast_struct结构,此时进程存在的唯一目的就是向它的父进程提供信息。父进程检索到信息后,由进程所持有的剩余内存被释放,归还给系统。

wait()通过系统调用wait4()来实现,返回子进程的PID,调用该函数时提供的指针会包含子函数退出时的退出代码

  • 删除进程描述符,父进程调用release_task()
  • 如果没有父进程,子进程exit_notify()的时候,调用forget_original_parent() -> find_new_reaper()来执行寻父过程
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容