第三章 进程

可以看到很多熟悉的结构体

进程状态:

可运行状态(TASK_ RUNNING)

进程要么在CPU上执行,要么准备执行。

可巾断的等待状态(TASK_ INTERRUPTIBLE)

进程被挂起(睡眠),直到一些条件变为真,这些条件包括:产生-个硬件巾断,释放进程正等待的系统资源,或传递一个信号,它们都能唤醒进程,即让进程的状态回到TASK RUNNING。

不可中断的等待状态(TASK_ _UNINTERRUPTIBLE)

与前一一个状态类似,但有一个例外,把信号传递到睡眼的进程不能改变它的状态。这种状态很少用到,但在一些特定的情况下这种状态是很有用的:进程必须等待,不能被中断,直到给定的事件发生。例如,当进程打开一个设备文件,其相应的设备驱动程序开始探测相应的硬件设备时会用到这种状态,探测完成以前,设备驱动程序不能被中断,否则,硬件设备会处于不可预知的状态。

暂停状态(TASK_ STOPPED)

进程的执行被暂停。当进程接收到SIGSTOP. SIGTSTP、SIGTTIN或SIGTTOU信号后,进入暂停状态。当-一个进程被另-一个进程监控时[例如debugger执行ptrace()系统调用监控-.个测试程序],任何信号都可以把这个进程置于TASK_ STOPPED 状态。

僵死状态(TASK_ ZOMBIE)

进程的执行被终止,但是,父进程还没有发布wait()类系统调用[wait(),wait3(),wait4()或waitpid()]以返回有关死进程的信息。发布wait()类系统调用前,内核不能丟弃包含在死进程描述符中的数据,因为父进程可能还需要它。(参见本章结尾的“删除进程”一节)。

Linux有两种策略选择其中之一:

TASK_ STOPPED或TASK_ ZOMB IE状态的进程不链接在专门的链表中,也没必要把它们分组,因为父进程叮以通过进程的PID,或进程间的亲属关系检索到子进程。

把TASK_ INTERRUPTIBLE或TASK_ _UNINTERRUPTIBLE状态的进程再分成很多类,每一类对应一个特定的事件。在这种情况下,进程状态提供的信息满足不了快速检索进程,因此,有必要引入另外的进程链表。这些附加的链表叫等待队列( wait queue )。

关于轻量级进程和线程:每一个轻量级进程都与一个特定的内核线程关联。内核线程只能由内核管理并像普通进程一样被调度。轻量级进程可以共享内核大部分数据结构。

进程链表:双向循环链表,链表的头是init_tash描述符,由task数组的第一个元素指向,为所有进程的祖先,称为进程0。中间为进程描述符

关于linux下的进程使用限制:

Linux下对进程执行了以下的限制:

RLIMIT_CPU
进程使用CPU的最长时间。如果进程超过了这个限制,内核就向它发-一个SIGXCPU信号,然后如果进程还不终止,再发一个SIGKILL信号(参见第九章)。

RLIMIT_FSIZE

允许文件大小的最大值。如果进程试图把一个文件的大小扩充到大于这个值,内核就给这个进程发SIGXFSZ信号。

RLIMIT_DATA

堆大小的最大值。在扩充进程的堆之前,内核检查这个值(参见第七章中“堆的管理”一节)。

RLIMIT_STACK

栈大小的最大值。在扩充进程的用户态堆栈之前,内核检查这个值(参见第七,章中" 缺页异常处理程序”一节)。

RLIMIT_CORE

内存信息转储文件的大小。当一个进程异常终止时,内核要在进程的当前目录下创建一个内存信息转储文件,在这个文件创建之前,内核检查这个值(参见第九章的“接收信号之前所执行的操作”一节)。如果这个限制为0,那么,内核就不创建这个文件。

RLIMIT_RSS

进程所拥有的页框的最大数。实际上,内核从来不检查这个值,因此,没有实现这个使用限制。

RLIMIT_NPROC ,

用户能拥有的进程最大数[参见本章“clone(), fork()及vfork()系统调用”- 节]。

RLIMIT_NOFILE

打开文件的最大数。当打开一个新文件或复制-一个文件描述符时,内核检查这个值(参见第十二章)。

RLIMIT_MEMLOCK

非交换内存的最大尺寸。当进程试图通过mlock()或mlockal1()系统调用锁住一个页框时,内核检查这个值(参见第七章巾“分配线性地址区间”--节)。

RLIMIT_AS

进程地址空间的最大尺寸。当进程使用malloc()或相关函数扩大它的地址空间时,内核检查这个值(参见第七章中“进程的地址空间”)。

对于以上的限制,每一个会有一个rlimit的结构体,如果想要修改可以看这个

#include <sys/resource.h>

if (getrlimit(RLIMIT_NOFILE,&rlim)==0){

printf("%x\n",rlim.rlim_cur);

rlim.rlim_cur=(rlim_t)4;

setrlimit(RLIMIT_NOFILE,&rlim);

}

任务状态段TSS: 每个进程都有,最小长度104,每个TSS有自己的8字节任务段描述符,TSSD,如果TSSD指向当前正在CPU上运行的进程的TSS,那么Type域被置为11;否则被置为9 (注4)。Type域最低第2位叫做忙位(Busy
bit),就是这- -位区分值9和11。因为在对这一位进行修改前,处理器执行“忙锁定”,因此,多任务操作系统可以测试这一位以检查CPU是否试图切换到正在执行的进程。但是Linux没有利用这个硬件特点(参见第十一章)。

由Linux创建的TSsD存放在全局描述符表(GDT)中,GDT的基地址存放在gdtr寄存器中。tr 寄存器包含了当前正在CPU上运行的进程的TSSD选择符,也包含了两个隐藏的非编程域: TSSD的Base域和Limit域。通过这种方式,处理器就能直接对TSS寻址,而不用从GDT中检索TSS的地址。

Switch_to宏进行进程切换,这个函数作用于prev和next参数,这两个参数分别指向前一个进程的进程描述符和新进程的。这个函数的调用不同于一般函数的调用,因为__ switch _to() 从eax和edx取参数prev和next (我们在前面已看到这些参数就是保存在那里),而不像大多数函数 。这里将esi,edi,ebp保存在prev内核态堆栈中,在prev->tss.esp中保存esp的内容,以便指向内核态堆栈的顶部,会在prev->tss.eip保存标号为1的地址,恢复执行时将执行这条指令

创建进程:

clone,fork和vfork,Linux用clone{}实现了传统的fork(}系统调用,clone() 的第一个参数指定为SIGCHLD信号,并把所有的克隆标志清0,第二个参数为0。

前面描述的vfork()系统调用在Linux中是由clone()实现,c1one()的第一个参数指定为SIGCHLD信号和CLONE VM及CLONE VFORK标志,第二个参数为0.

进程0 和进程1 :

所有进程的祖先,又称swapper进程,为Linux初始化阶段由start_kernel创建,start_kernel(}函数初始化内核需要的所有数据结构,开中断,创建另一个内核线程,这个线程命名为进程1.更--般的叫法为init进程。进程1四次轮流调用kernel_thread创建常规内核任务初始化四个必要的内核线程,用于kflushd(刷新脏缓冲区内容到磁盘归还内存)十四章,kupdate(刷新旧缓冲区内容到磁盘减少文件系统不一致的风险)十四章,kpiod(把属于共享内存映射的页面交换出去)十六章,kswapd(执行内存回收功能)十六章。

深入理解Linux内核 学习笔记(3)的更多相关文章

  1. 深入理解Linux内核 学习笔记(1)

    1.用户和用户组 每个用户是一个或多个用户组的一名成员,组由唯一的用户组标识符(user group ID)标识.每个文件的相关权限也恰好与一个组相对应. root为超级用户, 2.模块 为了达到微内 ...

  2. 深入理解Linux内核 学习笔记(5)

    第五章  定时测量 内核必须显式地与三种时钟打交道:实时时钟(Real Time Clock, RTC).时间标记计数器(Time Stamp Counter, TSC)及可编程间隔定时器( Prog ...

  3. 深入理解Linux内核 学习笔记(4)

    第四章 中断和异常 中断通常被分为同步中断和异步中断,同步中断是当指令执行时由CPU控制单元产生的,之所以称为同步,是因为只有在一条指令终止执行后CPU才会发出中断异步中断是由其他硬件设备依照CPU时 ...

  4. 深入理解Linux内核 学习笔记(2)

    第二章 :内存寻址 略.基本同计算机组成原理中的讲述 内核代码和数据结构会存储在一个保留的页框中. 常规Linux安装在RAM物理地址0x00100000开始的地方.因为:页框0是由BIOS使用,存放 ...

  5. 深入理解Linux内核 学习笔记(8)

    第八章 系统调用 API定义了一个给定的服务:系统调用是通过软中断向内核发出一个明确的请求. API可能不调用系统调用,也可能调用多个系统调用. Linux系统调用必须通过执行int 0x80,系统调 ...

  6. 20135316王剑桥Linux内核学习笔记

    王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...

  7. Linux内核学习笔记-2.进程管理

    原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  8. Linux内核学习笔记-1.简介和入门

    原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  9. Linux内核学习笔记二——进程

    Linux内核学习笔记二——进程   一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...

随机推荐

  1. C++中函数重载和函数覆盖的区别

    C++中经常会用到函数的重载和覆盖,二者也在很多场合都拿出来进行比较,这里我就对二者的区别做点总结: 函数重载: 函数重载指的是函数名相同.函数特征值不同的一些函数,这里函数的特征值指的是函数的参数的 ...

  2. BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  3. BZOJ_1774_[Usaco2009 Dec]Toll 过路费_floyd

    BZOJ_1774_[Usaco2009 Dec]Toll 过路费_floyd 题意: 跟所有人一样,农夫约翰以着宁教我负天下牛,休叫天下牛负我的伟大精神,日日夜夜苦思生 财之道.为了发财,他设置了一 ...

  4. ArchLinux 安装五笔输入法

    说明 自己的笔记本已经全盘做成了ArchLinux系统了,用着还好,苦于常用的五笔输入法在Arch下有点不太好装,参考wiki弄好了,这里简单记录下 这里使用ibus-rime 原因有二: ibus- ...

  5. 小程序 表单 获取 formId

    微信小程序使用模板消息需要使用支付prepay_id或表单提交formId, 要获得 formId 需要在 form 标签中声明属性    report-submit="true" ...

  6. .NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现

    先决条件 关于 Ocelot 针对使用 .NET 开发微服务架构或者面向服务架构提供一个统一访问系统的组件. 参考 本文将使用 Ocelot 构建统一入口的 Gateway. 关于 IdentityS ...

  7. Java工程师修炼之路(校招总结)

    Java工程师修炼之路(校招总结) 前言 在下本是跨专业渣考研的985渣硕一枚,经历研究生两年的学习积累,有幸于2019秋季招聘中拿到几个公司的研发岗offer,包括百度,阿里,腾讯,今日头条,网易, ...

  8. Git版本控制 —— IDE工具(IDEA)

    本文介绍使用IDEA控制Git操作 关联本地Git客户端 首先要根据系统环境安装Git客户端 然后使用File --> Settings -->  Version Control --&g ...

  9. Netty源码—六、tiny、small内存分配

    tiny内存分配 tiny内存分配流程: 如果申请的是tiny类型,会先从tiny缓存中尝试分配,如果缓存分配成功则返回 否则从tinySubpagePools中尝试分配 如果上面没有分配成功则使用a ...

  10. Sharepoint 2013内容查询Web部件自定义显示样式(实战)

    分享人:广州华软 星尘 一. 前言 在进行Sharepoint开发时,经常会遇到内容展示个性化需求的问题,当然如果通过自定义开发控件对于内容展示的需求基本都可以很好的解决,但自定义开发也有不好的地方, ...