二,每一个进程都有一个父进程。
三、进程有两种存在方式:前台运行,后台运行。
四、一般的服务都是后台运行的,基本的程序都是前台运行的。
看父进程,我们一般是用树结构来查看。
pstree
-p:显示父id
-u:显示用户组
kill -9 +进程的id
我们知道,进程运行需要各种各样的系统资源,如内存、文件、打印机和最
宝贵的 CPU 等,所以说,调度的实质就是资源的分配。系统通过不同的调度算法(Scheduling Algorithm)来实现这种资源的分配。通常来说,选择什么样的调度算法取决于资源分配的策略(Scheduling Policy)。
有关调度相关的结构保存在 task_struct 中,如下:
active_mm 是为内核线程而引入的,因为内核线程没有自己的地址空间,为了让内核线程与普通进程具有统一的上下文切换方式,当内核线程进行上下文切换时,让切换进来的线程的 active_mm 指向刚被调度出去的进程的 active_mm(如果进程的mm 域不为空,则其 active_mm 域与 mm 域相同)。
在 linux 2.6 中 sched_class 表示该进程所属的调度器类有3种:
进程的调度策略有5种,用户可以调用调度器里不同的调度策略:
在每个 CPU 中都有一个自身的运行队列 rq,每个活动进程只出现在一个运行队列中,在多个 CPU 上同时运行一个进程是不可能的。
运行队列是使用如下结构实现的:
tast 作为调度实体加入到 CPU 中的调度队列中。
系统中所有的运行队列都在 runqueues 数组中,该数组的每个元素分别对应于系统中的一个 CPU。在单处理器系统中,由于只需要一个就绪队列,因此数组只有一个元素。
内核也定义了一下便利的宏,其含义很明显。
Linux、c/c++服务器开发篇-------我们来聊聊进程的那些事
Linux内核 进程间通信组件的实现
学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括 C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg 等),免费分享
在分析调度流程之前,我们先来看在什么情况下要执行调度程序,我们把这种情况叫做调度时机。
Linux 调度时机主要有。
时机1,进程要调用 sleep() 或 exit() 等函数进行状态转换,这些函数会主动调用调度程序进行进程调度。
时机2,由于进程的时间片是由时钟中断来更新的,因此,这种情况和时机4 是一样的。
时机3,当设备驱动程序执行长而重复的任务时,直接调用调度程序。在每次反复循环中,驱动程序都检查 need_resched 的值,如果必要,则调用调度程序 schedule() 主动放弃 CPU。
时机4 , 如前所述, 不管是从中断、异常还是系统调用返回, 最终都调用 ret_from_sys_call(),由这个函数进行调度标志的检测,如果必要,则调用调用调度程序。那么,为什么从系统调用返回时要调用调度程序呢?这当然是从效率考虑。从系统调用返回意味着要离开内核态而返回到用户态,而状态的转换要花费一定的时间,因此,在返回到用户态前,系统把在内核态该处理的事全部做完。
Linux 的调度程序是一个叫 Schedule() 的函数,这个函数来决定是否要进行进程的切换,如果要切换的话,切换到哪个进程等。
从代码分析来看,Schedule 主要完成了2个功能:
进程上下文切换包括进程的地址空间的切换和执行环境的切换。
对于 switch_mm 处理,关键的一步就是它将新进程页面目录的起始物理地址装入到寄存器 CR3 中。CR3 寄存器总是指向当前进程的页面目录。
switch_to 把寄存器中的值比如esp等存放到进程thread结构中,保存现场一边后续恢复,同时调用 __switch_to 完成了堆栈的切换。
在进程的 task_struct 结构中有个重要的成分 thread,它本身是一个数据结构 thread_struct, 里面记录着进程在切换时的(系统空间)堆栈指针,取指令地址(也就是“返回地址”)等关键性的信息。
关于__switch_to 的工作就是处理 TSS (任务状态段)。
TSS 全称task state segment,是指在 *** 作系统进程管理的过程中,任务(进程)切换时的任务现场信息。
linux 为每一个 CPU 提供一个 TSS 段,并且在 TR 寄存器中保存该段。
linux 中之所以为每一个 CPU 提供一个 TSS 段,而不是为每个进程提供一个TSS 段,主要原因是 TR 寄存器永远指向它,在任务切换的适合不必切换 TR 寄存器,从而减小开销。
在从用户态切换到内核态时,可以通过获取 TSS 段中的 esp0 来获取当前进程的内核栈 栈顶指针,从而可以保存用户态的 cs,esp,eip 等上下文。
TSS 在任务切换过程中起着重要作用,通过它实现任务的挂起和恢复。所谓任务切换是指,挂起当前正在执行的任务,恢复或启动另一任务的执行。
在任务切换过程中,首先,处理器中各寄存器的当前值被自动保存到 TR(任务寄存器)所指定的任务的 TSS 中;然后,下一任务的 TSS 被装入 TR;最后,从 TR 所指定的 TSS 中取出各寄存器的值送到处理器的各寄存器中。由此可见,通过在 TSS 中保存任务现场各寄存器状态的完整映象,实现任务的切换。
因此,__switch_to 核心内容就是将 TSS 中的内核空间(0级)堆栈指针换成 next->esp0。这是因为 CPU 在穿越中断门或者陷阱门时要根据新的运行级别从TSS中取得进程在系统空间的堆栈指针。
thread_struct.esp0 指向进程的系统空间堆栈的顶端。当一个进程被调度运行时,内核会将这个变量写入 TSS 的 esp0 字段,表示这个进程进入0级运行时其堆栈的位置。换句话说,进程的 thread_struct 结构中的 esp0 保存着其系统空间堆栈指针。当进程穿过中断门、陷阱门或者调用门进入系统空间时,处理器会从这里恢复期系统空间栈。
由于栈中变量的访问依赖的是段、页、和 esp、ebp 等这些寄存器,所以当段、页、寄存器切换完以后,栈中的变量就可以被访问了。
因此 switch_to 完成了进程堆栈的切换,由于被切进的进程各个寄存器的信息已完成切换,因此 next 进程得以执行指令运行。
由于 A 进程在调用 switch_to 完成了与 B 进程堆栈的切换,也即是寄存器中的值都是 B 的,所以 A 进程在 switch_to 执行完后,A停止运行,B开始运行,当过一段时间又把 A 进程切进去后,A 开始从switch_to 后面的代码开始执行。
schedule 的调用流程如下:
Linux系统提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。在Linux系统中,进程的4GB内存空间被分为两个部分——用户空间与内核空间。用户空间的地址一般分布为0~3GB(即PAGE_OFFSET,在Ox86中它等于OxC0000000),这样,剩下的3~4GB为内核空间,用户进程通常只能访问用户空间的虚拟地址,不能访问内核空间的虚拟地址。用户进程只有通过系统调用(代表用户进程在内核态执行)等方式才可以访问到内核空间。每个进程的用户空间都是完全独立、互不相干的,用户进程各自有不同的页表。而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。内核空间的虚拟地址到物理地址映射是被所有进程共享的,内核的虚拟空间独立于其他程序。Linux中1GB的内核地址空间又被划分为物理内存映射区、虚拟内存分配区、高端页面映射区、专用页面映射区和系统保留映射区这几个区域。对于x86系统而言,一般情况下,物理内存映射区最大长度为896MB,系统的物理内存被顺序映射在内核空间的这个区域中。当系统物理内存大于896MB时,超过物理内存映射区的那部分内存称为高端内存(而未超过物理内存映射区的内存通常被称为常规内存),内核在存取高端内存时必须将它们映射到高端页面映射区。Linux保留内核空间最顶部FIXADDR_TOP~4GB的区域作为保留区。当系统物理内存超过4GB时,必须使用CPU的扩展分页(PAE)模式所提供的64位页目录项才能存取到4GB以上的物理内存,这需要CPU的支持。加入了PAE功能的Intel Pentium Pro及以后的CPU允许内存最大可配置到64GB,它们具备36位物理地址空间寻址能力。由此可见,对于32位的x86而言,在3~4GB之间的内核空间中,从低地址到高地址依次为:物理内存映射区隔离带vmalloc虚拟内存分配器区隔离带高端内存映射区专用页面映射区保留区。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)