《linux内核设计与实现》读书笔记linux进程管理(代码片段)

东皇※太一 东皇※太一     2023-02-19     673

关键词:

进程与线程

①进程就是处于执行期的程序,通常进程还包含挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个或多个执行线程,还包含存放全局变量的数据段等。

②线程是进程中活动的对象,每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。进程和线程是程序运行时状态,是动态变化的,进程和线程的管理操作(比如,创建,销毁等)都是有内核来实现的。

③我们使用操作系统就是为了运行用户程序,而内核调度的对象是线程,对linux而言,不严格区分进程和线程,线程就是一种特殊的进程,或轻量级进程。

④进程提供两种虚拟机制:虚拟处理器和虚拟内存,这两种虚拟机制给进程一种假象,让这些进程觉得:

每个进程拥有独立的虚拟处理器和虚拟内存

每个线程拥有各自的虚拟处理器,同一个进程中的线程可以共享虚拟内存。

注:程序本身并不是进程,进程是处于执行期的程序以及相关资源的总称。

进程描述符及结构

内核把进程的列表存放在任务队列的双向循环链表中(task list),链表中每一项都是类型为task_struct、这就是进程描述符的结构,在<linux/sched.h>文件中定义。

进程描述符中包含了一个具体进程的所有信息。

 进程分配描述符

Linux通过slab分配器分配task_struct结构,只需创建一个新的结构struct thread_info,该结构在<thread_info.h>中定义:

struct thread_info 
    struct task_struct      *task; //指向当前进程内核栈对应的进程的进程描述符
    struct exec_domain      *exec_domain;
    __u32                   flags;
    __u32                   status;
    __u32                   cpu;
    int                     preempt_count;
    mm_segment_t            addr_limit;struct restart_block         
    restart_block;void      *sysenter_return;
    int                     uacc    ess_err;
;

个人物的thread_info结构在它的内核栈的尾端分配,结构中task域中存放的是指向该任务实际task_struct的指针。

内核中通过PID来标识每个进程,PID的类型为pid_t,实际是int类型,最大值在<linux/threads.h>中定义,也可通过修改/proc/sys/kernel/pid_max的值来提高。

进程的状态

系统中的每个进程都必然处于五种进程状态中的一种。

进程的各个状态之间的转化构成了进程的整个生命周期,如下:

 该域的值也必为下列五种状态标志之一:

TASK_RUNNING:等待执行或者正在执行

TASK_INTERRUPTIBLE:正在睡眠或者被阻塞

TASK_UNINTERRUPTIBLE:不可中断

__TASK_TRACED:被其它进程跟踪的进程

__TASK_STOPPED:进程停止执行

内核中调整某个进程的状态,通过set_task_state(task,state)函数,在<linux/sched.h>中。

系统调用和异常处理程序是对内核明确定义的接口,进程只有通过这些接口才能陷入内核执行,对内核的所有访问都必须通过这些接口。

进程的创建

①首先调用fork(),通过拷贝当前进程创建一个子进程。

②然后exec()函数族负责读取可执行文件并将其载入地址空间开始运行。

因为子进程几乎是父进程的完全复制,进程在创建它的时刻开始存活,所以父子两个进程会运行同一个程序。因此需要用一种方式来区分它们,否则这两个进程只能做同样的事。

父子进程最重要的区别是:fork()的返回值不同。父进程中的返回值是子进程的进程号(PID),而子进程中返回值是0,因此可通过返回值来判断该进程是父进程还是子进程。

 linux中的fork使用了写时拷技术,就是平时父子进程共享同一个拷贝,只有在需要写入的时候数据才会被复制,从而使各个进程拥有各自的拷贝。避免了拷贝大量根本就不会使用的数据。

创建过程:

fork()——》clone() ——》do_fork() ——》copy_process() ——》dup_task_struct()

新创建的子进程被唤醒并让其投入运行,因为一般子进程都会马上调用exec()函数。

进程的终止

子进程中通过调用do_exit()退出,或者 内核的其它部分调用kthread_stop()退出。

子进程上的操作(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设置为进程的返回值
  7. 调用exit_notify()向父进程发送信号,并把自己的状态设为EXIT_ZOMBIE
  8. do_exit()调用schedule()切换到新进程继续执行

子进程进入EXIT_ZOMBIE之后,虽然永远不会被调度,关联的资源也释放掉了,但是它本身占用的内存还没有释放,比如创建时分配的内核栈,task_struct结构等。这些由父进程来释放。

如果父进程在子进程之前退出,则需给子进程在当前线程组内找一个线程作为父亲,如果不行,就让init做为它们的父进程。这样就保证了所有进程都有父进程.

《内核设计与实现》读书笔记-进程管理

...程序以及相关的资源的总称。线程是进程中活动的对象。内核调度的对象是线程,而不是进程。进程和线程的管理操作(比如创建和销毁)都是由内核来实现的。Linux中的进程于Windows相比是很轻量级的,而且不严格区分进程和线... 查看详情

《linux内核设计与实现》读书笔记从内核出发(代码片段)

内核源码获取①可以直接登录linux内核官方网站http://www.kernel.org,可以随时获取当前版本的linux源代码②也可以使用git工具从远程仓库下载,地址:LinuxKernel:Linux内核源码镜像如:gitclonegit@gitee.com:mirrors/linux_old1.git这... 查看详情

《linux内核设计与实现》读书笔记linux内核简介

Unix的历史①Unix诞生于1969年,至今仍然被认为是现存操作系统中最强大和最优秀的系统。②Unix起源于一个失败的多用户操作系统Multics,Multics终止而Unix萌生。③1973年整个Unix操作系统用C语言进行了重写,为后面各种... 查看详情

《linux内核设计与实现》读书笔记linux进程管理(代码片段)

...于执行期的程序,通常进程还包含挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个或多个执行线程,还包含存放全局变量的数据段等。②线程是进程中活动的对象ÿ... 查看详情

《linux内核设计与实现》读书笔记-内核同步方法(代码片段)

...3.读写自旋锁4.信号量5.读写信号量6.互斥体7.完成变量8.大内核锁9.顺序锁10.禁止抢占11.顺序和屏障12.总结内核中提供了多种方法来防止竞争条件,理解了这些方法的使用场景有助于我们在编写内核代码 查看详情

《linux内核设计与实现》笔记——内核同步简介

相关概念竞争条件多个执行线程(进程/线程/中断处理程序)并发(并行)访问共享资源,因为执行顺序不一样造成结果不一样的情况,称为竞争条件(racecondition)举例说明#include<thread>usingnamespacestd;inti=0;voidthread1(){//for(intx=0;x&... 查看详情

《linux内核设计与实现》读书笔记-内核同步方法(代码片段)

...3.读写自旋锁4.信号量5.读写信号量6.互斥体7.完成变量8.大内核锁9.顺序锁10.禁止抢占11.顺序和屏障12.总结内核中提供了多种方法来防止竞争条件,理解了这些方法的使用场景有助于我们在编写内核代码时选用合适的同步方法&#... 查看详情

《linux内核设计与实现》笔记——vfs

关于VFS有一篇很好的博客http://www.ibm.com/developerworks/cn/linux/l-vfs/建议先阅读本文为基础,然后继续阅读该文章。VFS,虚拟文件系统,为用户提供了文件和文件系统相关的接口。这些接口可以跨越各种文件系统和不同介质执行。VFS... 查看详情

《linux内核设计与实现》学习笔记——i/o调度算法

I/O调度子系统用于调度来自多个进程对块设备的I/O请求。电梯调度首先,如果队列中已存在一个对相邻磁盘扇区操作的请求,那么新请求将和这个已经存在的请求合并为一个请求。2.如果队列中存在一个驻留时间过长的请求,那... 查看详情

linux内核设计与实现的目录

参考技术A译者序序言前言作者简介第1章 Linux内核简介11.1 Unix的历史11.2 追寻Linus足迹:Linux简介21.3 操作系统和内核简介31.4 Linux内核和传统Unix内核的比较51.5 Linux内核版本71.6 Linux内核开发者社区81.7 小结8第2章 从内... 查看详情

《linux内核设计与实现》学习笔记——中断中断处理程序

...线,每个irq线关联一个数值。中断处理程序响应中断时,内核会执行一个函数,中断处理程序/中断服务例程ISR,一个设备的中断处理程序是他的设备驱动的一部分。IO资源包括:中断,I/O端口,共享RAM,DMA。驱动程序需要管理注... 查看详情

《linux设计与实现》笔记——系统调用工作原理添加系统调用的过程

系统调用的意义为了和用户空间上的进程进行交互,内核提供的提供的一组接口。应用程序通过这组接口访问硬件和其他操作系统资源。完成对硬件和资源访问的控制。安全、可靠,多任务、虚拟必须硬件设备的抽象(提供设备... 查看详情

《linux设计与实现》学习笔记——定时器和时间管理

...驱动事件的准确度;调度的粒度更细,进程抢占更准确;内核定时器以更高的频度和准确度执行。 查看详情

linux内核设计与实现进程调度1:基本概念

参考技术A        进程大致可分为I/O密集型和CPU密集型。        调度依据动态优先级,所谓动态优先级就是初始化时给出一个基础优先级,随后优先级可被调度程序动态... 查看详情

《kubernetes网络权威指南》读书笔记|网络虚拟化基石:networknamespace

...xff0c;Linux的namespace(名字空间)的作用就是“隔离内核资源”。Linux的namespace给里面的进程造成了两个错觉:(1)它是系统里唯一的进程。(2)它独享系统的所有资源。默认情况下,Linux进程处在和... 查看详情

android深度探索——第十章读书笔记及心得

...学习了解了printk函数。该函数与printf函数类似,用于打印内核调试信息。只是前者运行在内核空间,后者运行在用户空间。即linux驱动这样的linux内核程序只能使用printk函数输出调试信息。Printk函数的原型:asmLinkKageintprintk(constcha... 查看详情

《linux内核设计与实现》知识整合与讲解-第一章

Linux内核简介第一章主要对Linux的内核进行一个大致的介绍,让大家对Linux的内核有一个比较全面的印象。众所周知Linux起源于unix系统,它们之间有着千丝万缕的联系,伟大的linux之父linus不满于当时unix对于源码更改的限制,花费... 查看详情

读书笔记《unix编程艺术》一

Unix设计的统一思想:一切皆文件。Linux是一个采取了Unix的设计思想,初始行为表现与Unix相同的操作系统,但Linux中的源码并未有任何出自Unix。Linux符合一切皆文件的思想,其中读写操作都是处理文件描述符,... 查看详情