Linux Kernel Development 笔记(二)进程

进程是在运行中的程序,但进程又不仅仅只是执行中的代码,还包括一套资源,包括文件,传递中的信号,内部内核数据,进程状态,一个内存地址空间,一个或多个执行线程以及含有全局变量的数据段。线程是进程中的活动单元,一个线程包含唯一的PC指针,进程堆栈以及一套CPU寄存器。内核调度是以线程为单位而不是进程。Linux有唯一的线程实现方式,它并不区分线程和进程,对于Linux来说,线程是一种特殊的进程类型。在现代操作系统中,进程提供了两种虚拟功能,一个虚拟的处理器以及一个虚拟的内存空间。这给予进程一个假象,他像是单独的拥有处理器以及整个系统内存,尽管它与众多弟兄分享着共同的处理器以及内存。不过有趣的是,线程是共享虚拟内存的,虽然每一个线程单独拥有自己的虚拟处理器。

进程的诞生是通过创建而来,在Linux中,是通过fork()系统调用来创建的。创建的新进程会复制目前调用fork的进程。因为调用fork的进程成为父进程,拷贝父进程基因的进程称为子进程。父进程在创建完子进程后,会继续执行剩下的代码。子进程也是在与父进程同一个位置开始执行(也就是调用fork后返回的地方)。这个fork会分别在父进程以及子进程中返回,返回一个整型数分别代表父进程以及子进程。一般来说,创建新进程的目的不是为了运行旧程序,而是运行新程序。在Linux中,则会调用exec系统调用来创建新的地址空间以及装载新的程序。最后,进程通过exit系统调用退出,并释放所拥有的资源。当进程退出后,会被置为zombie状态(僵尸状态),直到其父进程通过wait系列系统调用来等待其状态。

内核把一系列进程保存在一个循环的双向链表,称之为任务列表(Task list)。每一个任务列表项称为进程描述项(struct task_struct),包含了进程的所有信息。这个描述结构相对来说比较大,包含了已打开的文件,进程地址空间,传递中的信号,进程状态等等。进程的描述结构是通过 slab allocaor创建的。2.6内核以前的版本,task_struct是存放到每个进程的内核栈的最底部,主要是配合少寄存器的机器而设计的。现在,都是通过slab动态创建的。但新的结构struct thread_info被放置在以前task_struct所放置的位置了(进程内核栈的底部或顶部)。改结构的task元素指向对应的task_struct。

系统通过进程ID来辨认进程(PID),该值是一个模糊类型(就是其物理表现不清晰的)pid_t,大部分是int类型。内核会把pid保存在每一个进程描述里。为了兼容,进程的数量控制在32768个。但这个对于未来使用是不够的,可以通过修改/proc/sys/kernel/pid_max来修改。在内核里,进程通常是由指向struct_task的指针来代言。为了能快速的获得当前进程的信息(当前进程的strcut_task),内核提供了一个宏current。一般current是通过先获取thread_info,在通过它的task项获得的,而且可以采用thread_info位于内核栈的最底部的特性来巧妙取得。

进程有五种状态,分别是

运行态(TASK_RUNNING):

进程处于一种可运行的状态,要么进程正在运行,要么是进程进入了等待队列即将运行。在用户态下,这是仅有可能的进程状态。内核态下,正在运行的进程也可以赋予此种状态

可中断态(TASK_INTERRUPTIBLE):

此时进程处于休眠状态,等待某些条件的到来。一旦条件到来,则内核会置进程状态为TASK_RUNNING。同时,如果收到信号信息,进程或许会提早恢复到可运行状态。

不可中断态(TASK_UNINTERRUPTIBLE):

这个状态跟可中断状态是一致的,除了此状态在收到信号信息时候,进程是不会恢复到可运行状态之外。这种状态一般用在不可被打断的等待或激活条件很快产生的情况,因为其不会被信号打断,故此此状态一般比可中断状态用频率低。

跟踪态(__TASK_TRACED):

表明此进程正在被别的进程跟踪,例如调试器,通过ptrace

停止态(__TASK_STOPPED):

如果进程不再运行同时也不能再运行,则置为此态。这个一般是在任务收到SIGSTOP, SIGTSTP,SIGTTIN或SIGTTOU信号或在调试状态收到任何信号后发生的。

内核经常需要更改进程的状态,一般都是通过set_task_state(task, state)系统函数来执行的。

一般情况下,进程是运行在用户态的,一旦程序调用系统函数或触发一个例外,则程序会进入内核态。在这点上,内核可以说是代替进程运行在进程的上下文中。一旦内核进入

此状态,则current就可以用了。一旦退出内核态(一般都系统函数返回),则会返回到用户态继续执行代码,如果暂时没有更高优先级的进程抢占处理器。进程只能通过系统

函数调用才能开始进入内核态。

Linux的进程间,存在唯一的层级关系。所有的进程都是init进程的后代,此进程的PID为1。内核在启动过程的最后一刻启动了init进程,接着init进程读取系统的initscripts脚本,

依次执行更多的程序,最终完成启动过程。所有的进程都是有init进程诞生的,故此他们都是init的子进程,而同属与一个父进程的进程成为弟兄,这些都通过进程描述结构体的parent,以及children项来记录的。通过一个进程,可以遍历所有的进程。init进程的描述符结构是静态的创建为init_task。


进程的创建fork在linux中,是把父进程的资源都拷贝一份给子进程,但如果是简单的拷贝是非常低效能的,故此linux采用的是copy-on-write(COW)技术,此技术是延迟数据的拷贝,在刚开始是不进行实质的拷贝动作,而是父进程与子进程共享同一份。一旦这个被标上要copy的数据要被写入,则会实质性的进行拷贝动作,此时子进程就拥有自己真正的资源。这个技术会延迟虚拟空间中每一page的实质拷贝,直到有实际写入动作发生的时候才做拷贝。故此,linux的进程在进行fork后,接着执行exec,是不会做实质拷贝动作的,仅仅只是拷贝父进程的页表以及创建一个进程描述符结构体。

创建过程:

1. 调用fork,接着会通过调用clone最终调用内部的do_fork,接着先调用copy_process,建立内核栈,thread_info, task_struct。这些内容的值都与创建的进程是一致的。

2. 检查一下子进程是否超过了当前用户允许的最大进程数

3. 子进程会对进程描述结构的一些项进行初始化,以有别于其父进程,一般改动的都是与统计信息相关的字段,大部分还是原封不动。

4. 子进程的状态会置为TASK_UNINTERRUPTIBLE来确保其暂时不能运行

5. 子进程的标志着拥有超级用户优先级的PF_SUPERPRIV 标志位会去掉(在进程描述结构里),换上PF_FORKNOEXEC标志,意味着执行了fork但未执行exec

6. 调用alloc_pid为子进程申请一个PID号

7. 根据传给clone的标志参数,来决定是否复制或者共享一般在进程中线程能共享的资源,包括文件信息,信号处理,地址空间等。

8. 最后copy_process会清除以及返回一个指向子进程指针的给调用者,接着内核运行子进程(注意,不一定是子进程立马就运行),子进程只要简单调用exec便可以

    消除任何因为父进程先运行并执行写内存的动作引发COW的开销。


线程是现代程序的抽象,线程可以在同一个内存空间中执行,并分享进程中的所有资源,是真正的并发。在Linux内核中,其实是无所谓的线程概念的,linux把线程就

当初普通的标准进程,并没有为其开辟特殊的调度语法或数据结构。线程仅仅是一个能与其他进程共享某些资源的进程而已。他们也有唯一的task_struct,不同与一般

的进程的只是他们共享这同一个内存空间而已。这个定义与微软的擦做系统或Sun Solaris有很大的差别。别的系统,进程的信息结构体还要维系着属于其线程的结构信息,

以及线程共享的资源。对于linux,仅仅还是按照原来的做法,直接创建task_struct结构,标注一下共享资源便可。线程的创建跟进程的创建过程是一样了,除了在clone

调用阶段传进去的参数是指定需要共享的资源标志。有一种非常特殊的线程,称为内核线程,此线程只运行在内核状态,它与普通进程的区别是,内核线程无地址空间,

永远也不会切换到用户态去执行。虽然如此,但内核线程依然像普通进程一样接受内核调度以及是可抢占的。有多种内核线程,最著名的是flush任务以及ksoftirqd任务。

内核线程只能有别的内核线程创建,linux一般是在系统启动过程中就由kthreadd内核进程创建各种内核线程。

进程的终止,内核会是释放其所拥有的资源,并通知其父进程其终止的信息。一般来说,进程的终止都是自发引起的,要么是其显示的调用exit函数,要么就是隐晦通过

退出main函数引发的(所以c编译器会把exit函数放在main调用后)。同时,进程也可以由别的方式终止,例如收到信号或者遇到一个不能处理的例外问题。所有的终止

行为,最终都会调用到do_exit,执行如下步骤:

1. 把struct_task的flag标志位设置为PF_EXITING

2. 调用del_timer_sync清除所有内核定时器,确保在无任何定时器以及处理在运行

3. 如果BSD进程计数功能打开,do_exit会调用acct_update_integral来填写计算信息

4. 调用exit_m来释放进程拥有的mm_struc结构体。如果没有别的进程再使用此地址空间(分享的情况),则内核摧毁它

5. 如果进程在等待semaphore,则此时释放它

6. 调用exit_files和exit_fs来减少文件信息以及文件数据对应的计数器,如果计数器为0,则摧毁

7. 设定退出码,存放于task_struct的exit_code字段里。

8. 调用exit_notify来对其父进程发送其终止信号,让其父进程的其他子进程重新排队,并且会把task_struct的标志位置为EXIT_ZOMBIE

9. 最后调用schedule来把处理器让给新的进程。进程的终止不会立马消失,而是作为一种zombie的状态,直到它通知了他父进程或他父进程选择不接收才会真的释放,

    并释放task_struct。一般父进程会调用wait函数来等待子进程终止的消息,wait4调用会阻塞调用进程运行,直到其子进程终止,并返回子进程的PID,并且还会带回

   exit_code。如果是线程组的情况,只有线程组的所有线程都退出,并且线程组长是zombie状态,才会通知线程组长的父进程。

如果父进程比子进程更早退出,系统会让子进程在父进程退出前重新找一个当前线程组的任一进程作为父进程,如果此路不通,则选择init进程作为父进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值