linux及安全《Linux内核设计与实现》第三章——20135227黄晓妍

第三章

(由于linux不区分进程和线程,所以它们在linux中被称为task,也叫任务)

总结:本章主要包括进程以及线程的概念和定义,Linux内核如何管理每个进程,他们在内核中如何被列举,如何创建,最终如何消亡。操作系统存在的意义在于运行用户程序,进程管理是所有操作系统的心脏所在。

3.1进程

进程是处于执行期的程序,是正在执行的程序代码的实时结果。但不仅局限于一段可执行的代码,还包括其他资源(打开的文件,挂起的信号,内核内部数据,处理器的状态,一个或者多个内存映射的内存地址空间,一个或者多个执行线程,存放全局变量的数据段)

线程

执行线程,即为线程,进程中活动的对象,是内核调度的对象。(内核并不是调度进程哟~)每一个线程都拥有一个独立的计数器,进程栈和一组进程寄存器。

进程提供的两种虚拟机制:

虚拟处理器:给进程一种自己在独享处理器的假象

虚拟内存:让进程在分配和管理内存空间的时候觉得自己拥有整个系统的所有内存资源

程序

进程处理执行期的程序以及相关资源的总称。

进程的整个周期

从它被创建的时刻开始存活(一般是fork()系统调用创建),接着调用exec()创建新的地址空间,并把新的程序载入,最终程序通过exit()系统调用退出执行。进程退出执行后被设置为僵死状态,直到它的父进程调用wait()或者waitpid()为止。

3.2进程描述符及任务结构

进程描述符的结构:

task_struct,定义在<linux/sched.h>文件中。任务队列的双向循环链表(内核存放进程列表的地方),每一项都是task_sturct.它包含一个具体的进程的所有信息(打开的文件,进程的地址空间,挂起的信号,进程的状态等)

3.2.1分配进程描述符

Linux通过slab分配器分配task_struct结构。只需要在栈底(对于向下增长的栈)或者栈顶(向上增长的栈)创建新的struct thread_info来动态生成task_struct结构。

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

3.2.2进程描述符的存放

内核通过唯一的pid进程标识符(其类型是pid_t,但实际上是int)来标识每一个进程。内核把pid放在她们各自的进程描述符中。它的默认值为32768(short int的 max),这个值表示系统中允许同时存在的进程的最大数目。(可以通过/proc/sys/kernel/pid_max来提高上限)

访问任务需要获得task_struct指针,通过current宏查找进程描述符的速度很重要。X86内核栈的尾端创建thread_info结构,通过偏移间接查找。栈大小(8KB)需要屏蔽掉后面13位(8192),4kb屏蔽12位(4096)

汇编代码:

返回:

X8的寄存器太少了才这样做,实际上访问进程描述符是一个很频繁的操作,所以寄存器多一些的操作系统,都会用一个专门的寄存器来保存task_struct。

3.2.3进程状态

进程描述符state描述进程当前的状态:

TASK_RUNNING运行

TASK_INTERRUPTIBLE可中断(阻塞)

TASK_UNINTERRUPTIBLE不可中断

_TASK_TRACED被其他进程跟踪

_TASK_STOPPPED停止

图3

3.2.4设置当前进程状态

使用set_current_stste(state)或者set_task_state(current,state)函数。

图4

等价于

图5

3.2.5进程上下文

可执行代码从一个可执行文件载入到进程地址空间执行。当它陷入内核时,内核“代表进程执行”并处于在进程上下文中,在此上下文中,current宏是有效的。

3.2.6进程家族树

进程之间有明显的继承关系。Linux系统中所有进程都是pid=1的进程的后代。(pid=1的进程是操作系统启动的最后阶段启动的init进程)

进程间的继承关系存放在进程描述符中。(task_struct结构)

获得父进程的进程描述符

图6

获得子进程的进程描述符

图7

因为有这样的继承关系,我们从任意一个进程去访问任务列表中其他所有进程。欣慰任务队列本身又是一个双向链表,所以其实是很容易实现的。

获取下一个进程:

图8

获取上一个进程

图9

遍历整个进程队列(没有必要不要遍历,因为代价很大)

图10

3.3进程创建

分成三步:1.在新的地址空间里创建进程2.读入可执行文件3.开始执行

3.3.1写时拷贝

写时拷贝是一种让子父进程共享同一个拷贝的技术。

相当于资源只有在需要写入的时候才会被复制,在此之前都是以只读的方式共享。

3.3.2fork()

do_fork()完成了创建进程的大部分工作,其中copy_process完成的工作:

1)  调用dup_task_struct()为新进程创建一个内核栈、thread_info、task_sturct这些值与当前进程同步

2)  检查用户所拥有的进程数目是否超出限制

3)  子进程开始把自己与父进程区分

4)  将子进程状态设置为不可中断

5)  调用copy_flags更新flag成员

6)  调用alloc_pid()为新进程分配一个有效的pid

7)  传递参数标识

8)  返回指向子进程的指针

3.3.3vfork()

除了不拷贝页表以外,和fork是一样的。

图11

3.4线程在linux中实现

线程被linux抽象成耗费比较少资源,运行迅速执行的单元。

3.4.1创建线程

和创建进程类似,但是在调用clone()需要传递一些标志性参数

图12

参数的含义:

图13

3.4.2内核线程

内核的后台任务一般通过内核线程执行,内核线程没有独立的地址空间只能运行在内核,内核线程启动以后就一直运行知道调用do_ex()退出,或者内核其他部分调用thread_stop()退出。

3.5进程终结

终结时要释放资源并告知父进程。大部分任务靠do_exit()来完成。

图14

3.5.1删除进程描述符

调用do_exit()以后,线程僵死但是保留了它的进程描述符。父进程获得已终结的子进程信息,或者它通知内核它不关注那些信息以后,子进程的进程描述符才被释放。

Wait()是挂起调用它的进程,直到其中的一个子进程退出,此时函数会返回该子进程的pid。

Release_task是最终执行释放进程描述符放入函数:

图15

3.5.2孤儿进程造成的进退维谷

如果父进程在子进程之前退出,需为子进程找到一个新的父亲。如果找不到,就让init作为它们的父进程

3.6小结

总结:

本章主要包括进程以及线程的概念和定义,Linux内核如何管理每个进程,他们在内核中如何被列举,如何创建,最终如何消亡。操作系统存在的意义在于运行用户程序,进程管理是所有操作系统的心脏所在。

时间: 2024-08-11 03:24:34

linux及安全《Linux内核设计与实现》第三章——20135227黄晓妍的相关文章

linux及安全《Linux内核设计与实现》第一章——20135227黄晓妍

<linux内核设计与实现>第一章 第一章Linux内核简介: 1.3操作系统和内核简介 操作系统:系统包含了操作系统和所有运行在它之上的应用程序.操作系统是指整个在系统中负责完成最基本功能和系统管理的那些部分.这些部分包括内核.设备驱动程序.启动应到程序.命令行shell或者其他种类的用户界面.基本的文件管理系统工具. 内核:如果说用户界面是操作系统的外在表像,那么内核就是操作系统的内在核心. 内核空间:系统态和保护起来的内存空间. 内核的组成: 1.中断服务程序(响应中断) 2.调度程序(

linux及安全第三周总结——20135227黄晓妍

总结部分: Linux内核源代码: Arch 支持不同cpu的源代码:主要关注x86 Init   内核启动的相关代码:主要关注main.c,整个Linux内核启动代码start_kernel函数 Kernel 核心代码 installing the kernel source:如何安装内核源代码 构建Linux系统os 使用gdb跟踪内核运行过程 -S cpu在初始化之前将其冻结 -s 在tcp端口创建server 分析start_kernel函数 Trap init 涉及中断 这个函数用来做

Linux基础入门学习笔记20135227黄晓妍

学习计时:共24小时 读书:1小时 代码:8小时 作业:3小时 博客:12小时 一.学习目标 1. 能够独立安装Linux操作系统 2. 能够熟练使用Linux系统的基本命令 3. 熟练使用Linux中用户管理命令/系统相关命令/文件目录相关命令/打包压缩相关命令/比较合并相关命令/网络相关命令等 4. 熟练应用“搜索”进行举一反三的学习 二.学习资源 1. 课程资料:https://www.shiyanlou.com/courses/413   实验一,课程邀请码:W7FQKW4Y 2. Li

linux及安全第二周总结——20135227黄晓妍

实验部分: 首先运行结果截图 代码分析: Mypcb.h /* *  linux/mykernel/mypcb.h * *  Kernel internal PCB types * *  Copyright (C) 2013  Mengning * */ #define MAX_TASK_NUM        4 #define KERNEL_STACK_SIZE   1024*8 /* CPU-specific state of this task */ struct Thread { uns

linux及安全第六周总结——20135227黄晓妍

总结部分: 操作系统内核三大功能: 进程管理,内存管理,文件系统 最核心的是进程管理 为了管理,首先要对每一个进程进行描述.进程描述符提供了所有内核需要了解的信息. 进程控制模块:task_struct(抽象task_struct的简化图) next_task,prev_task进程链表的管理 tty_struct控制台 fs_struct文件系统描述 file_struct打开的文件描述符 mm_struct内存管理的描述 signal_struct信号的描述 Linux-3.18.6/inc

《LINUX内核设计的艺术》第一章从开机家电到执行main函数之前的过程 学习笔记之一

从开机加电到实行main函数之前的过程 分为三步,目的是实现从启动盘加载操作系统程序,完成实现main函数的准备工作 启动BLOS,准备是模式下的中断向量表和中断服务程序 从启动盘加载操作系统程序到内存.加载操作系统程序就是靠第一步实现的 为实现32位的main函数做过度工作 1.1启动blos,准备实模式下的中断向量表和中断服务程序 由blos来加载软件操作系统的任务 1.1.1         BLOS的启动原理 0XFFFF0 由硬件来启动,CPU硬件设计逻辑设计为加电瞬间就强行将CS的值

《内核设计与实现》第一章读书笔记

<内核设计与实现>第一章读书笔记 第一章:Linux内核简介 1.1 Unix的历史 Unix强大的特点 A.简洁,几百个系统调用,明确的设计目的 B.文件对待所有东西 C.移植性强(C语言) D.进程创建快,使用fork()系统调用. E.进程间通信元语,进程间通信机制 1.2 linux的简介 Linux系统的基础是内核.C库.工具库和系统的基本工具. 1.3 操作系统和内核简介 内核:管理者,操作系统的核心 通常一个内核由负责响应中断的中断服务程序和网络.进程间通信等系统服务共同组成.

当代码遇到数理逻辑——面向对象设计与构造第三章总结

在面向对象课程中的第三章,我尝试了基于JML语言的规格化设计,按照AppRunner中的接口文件实现了Path类和PathContainer, Graph, RailWaySystem迭代类.JML语言是一种规格化语言,完全建立于数理逻辑上,既能够为开发者实现类与方法时提供准确的功能参考,也能够在特定工具支持下充当assert的功能和辅助自动生成测试样例. 本篇博客将从以下几方面对第三章进行总结: JML的基本语法与工具链 基于JmlUnitNg的自动测试方法尝试 三次作业架构 程序Bug分析

Linux内核设计与实现 第十七章

1. 设备类型 linux中主要由3种类型的设备,分别是: 设备类型 代表设备 特点 访问方式 块设备 硬盘,光盘 随机访问设备中的内容 一般都是把设备挂载为文件系统后再访问 字符设备 键盘,打印机 只能顺序访问(一个一个字符或者一个一个字节) 一般不挂载,直接和设备交互 网络设备 网卡 打破了Unix "所有东西都是文件" 的设计原则 通过套接字API来访问 除了以上3种典型的设备之外,还有"伪设备",即一些虚拟的设备,仅提供访问内核功能而已,没有物理设备与之关联