当前课程知识点:Linux 内核分析与应用 >  第3章 进程管理 >  3.4 动手实践-打印进程描述符task_struct中的字段 >  Video

返回《Linux 内核分析与应用》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《Linux 内核分析与应用》慕课在线视频列表

Video课程教案、知识点、字幕

大家好 本节视频就来动手实践打印进程描述符task_struct中的字段

采用的方法是插入内核模块使用的方法是遍历进程链表

下面先来浏览一下task_struct的结构

在这里我们要看自己系统内核的源代码

因为不同版本的内核中字段会有所改变

首先在kernel.org中下载自己系统对应的源代码

我自己内核版本是4.15

那我是使用sublime来进行查看

那相对的我们要在

include文件夹的目录下来打开头文件

task_struct结构主要存放在sched.h中

这就是PCB在内核中的全貌了

它是一个非常庞大的结构体字段非常非常多

在这里我们仅关注它PCB本身

并且一些能反应它结构的一些字段

首先来看第一个字段是thread_info 也就是他的状态信息

再往下它有它的内核栈 这是它的一些进程的标志

ptrace字段主要是用来实现断点调试的

再往下我们可以看见一些优先级信息

动态优先级 静态优先级和实时优先级

再往下我们可以看到policy字段 这是它的进程调度策略

再往下我们可以看到调度器统计进程的运行信息 就是这个结构体

接下来就是我们tasks字段 这是一个双向链表

正是这个字段把所有的进程连到了一块 我们才能对进程进行遍历

下面是它的线性地址的所有信息了

mm和active_mm

active_mm主要就是

最后访问的地址空间指针

再往下我们也可以看到一些pid进程的标识符

这里还有一些判断的标志比如说 这个

它就是进程的终止代号

再往下我们可以看到进程的亲属关系

亲父 养父 子 兄 进程组头

那再往下

我们可以看到这两个信息 是用来反映进程上下文切换的次数的

这个字段是用来反映主动上下文切换的次数

这个是是用来反应被动上下文切换的次数

再往下 这两个字段是用来记录缺页统计

这个数组是相应程序的名字

这两个字段负责进程之间的通信

再往下也是一个非常重要的就是它的文件信息

fs保存一个指向文件系统信息的指针

files保存一个指向进程文件描述符表的指针

再往下是它的命名空间

再往下我们可以看到 是它的信号描述符了

再往下我们可以看到IRQ这些都是它的中断信息

再往后我们可以看到这个字段这是它的内存回收包括io

这是记录进程的io计数 后面的字段还有很多很多

在这里我们要对PCB的一些重要字段进行打印

那我们也是要尽量体现一下

PCB的一个结构 首先我们需要打印

它的属性信息 比如它的状态 它的进程标识符

还有它的一些优先级信息 还有它的亲属关系

还有它的文件系统的信息

当然 我们还需要打印进程内存方面的信息 我们现在来进行实验

在这里我已经建立了工作目录

Makefile文件还是之前一样的

在这里已经将目标文件命名为task_struct.o

那我们一定要对应的c文件命名为task_struct.c

好我们来进入

拿在编写内核模块时 我们首先要写上我们得框架

下面是许可证

入口函数

init宏是由init.h文件所支持

这个是出口函数

我们在出口函数这里进行一行打印

接下来需要指明出口点和入口点

入口点 出口点是由module.h所支持的

那我们接下来主要是写一个遍历

所有进程的一个代码

这里我们需要运用到list.h文件中的几个宏 我们首先来看

list.h文件

在list.h文件中 我们首先需要用到的是

list_for_each

那list_for_each 我们可以看这个宏

实际上它是一条for语句

我们就是使用这个来进行遍历 遍历的就是head链表

在遍历到每一个节点时 使用pos来指向

那在每一个指向之后 我们需要运用到的是

list_entry 我们可以来看一下list_entry

list_entry实际上是一个container_of宏

这个宏中ptr代表的是结构体中的member的地址

type就是结构体的类型 member就是结构体中的成员

也就是我们上一步使用for语句

遍历到了每一个节点

在这个节点中 根据我们前面所了解到的字段中 已经是tasks来

连接起来的 也就是说我们现在已经找到了tasks

那么就使用tasks这个字段来得到

当前这个结构体的首地址

之后再使用一个指针指向

然后我们就可以再对这个结构体进行相应的打印操作

我们来看一下代码

首先我们需要 经过前面的分析之后 我们需要几个

指针

我们使用task和p指针

再定义一个双向链表指针

在这里设定一个count字段

来统计一下当前系统中总共有多少个

设初值为0

接下来我们先进行一行信息的打印

我们来对链表进行遍历的时候 我们首先

希望它从第一个开始 那么第一个是怎么来表示的呢

内核中我们可以这样来使用

首先它是一个init_task结构 所以我们使用相应的指针来指向

也就是我们的init_task

也就是用0号进程的一个PCB

接下来我们进行遍历操作

这里我们就使用pos

来指向

传入的参数是task

中的tasks字段

也就是用0号进程的tasks来进行遍历

正是这个字段将所有的

进程连在一块

那我们现在就可以来

对找到某一个节点之后 我们就可以利用这一个节点

的tasks字段来找到这个结构体的初始地址

我们就使用这个list_entry

对应的字段要填入

对应的字段tasks

那我们找到之后我们希望

对它打印的时候 我们还是希望通过一个指针来进行操作

也就是我们前面所定义这个P指针的用处

我们可以通过P指针来指向它

那我们一旦进入到这里的时候我们就可以对

我们得count字段进行加加 表示我们已经找到了进程

我们在这里换行符

为了美观一点我们换两行

好 接下来我们就可以对

P指针进行操作 此时的p已经

已经指向了每个进程对应的tasks结构体的

首部 我们就可以对它来进行操作了

直接进行打印就可

在这里我们首先选择的是pid信息

方法就是p指针里面的pid字段

对应的格式符是%d

接下来是状态字段

状态字段我们对应的就是%lx

好接下来我们来选择打印它的优先级信息

打它的动态优先级

就是P PIO字段

我们也可以尝试打印它的静态优先级

接下来我们还可以打印它的亲属关系

我们可以打印下它的父进程的pid号

在这里打印的方式是首先

我们在使用P中的parent

指针先指向它的父进程 之后

再指向父进程的PID号

接下来我们还可以打印它的文件系统信息

我们刚才分析过之后可以知道我们可以使用它的files

来进行打印 我们可以打印它的count字段

它的count字段

是存放这个结构体被使用的一个次数 对应的还可以再打印

它的fs字段所指向的umask字段

那我们在这里接下来打印的是

每一个进程所对应的它的

地址空间的信息 但是我们不可以在这里直接指向它的P

所对应的mm或者是active_mm

因为在linux中内核线程的mm是空的

那么在这个时候如果要对它进行打印的话 就会出错

会出现一个指针错误 所以在这里要加上一个if判断语句

我们来判断如果这个

mm指针这个区域是空的 就不进行打印 如果不是空的 再对它进行打印

我们在这里就指向它的mm字段

我们在这里选择打印它的total_vm

也就是它的线性区总的页数是多少

在这里我们还需要进行一项工作就是 在这里我们进行了很多的打印

但是我们可以看到我们在这里的头文件并没有添加

所以我们要在这里要添加对应的每一个头文件

首先

我们使用到了task_struct结构

那么我们在我们得

源码中可以看出来 是在sched.h文件中

接下来

我们还在我们得代码中使用了

它的count字段

count字段来源于它的fs

umask字段来自于files 那么我们要把它fs和files

相对应的头文件添加进来

我们可以在源码中来查看一下这两个的位置

首先我们来查找

files对应的是fs_struct.h

那么我们在查找时他就应该是在include的linux下

是在这里 所以我们要把这个头文件也要添加进去fdtable.h

那对应的我们还要再寻找fs

fs_struct在这里对应的头文件应该是fs_struct.h

那我们在后面还打印了对应的内存信息

也就是我们需要寻找他的mm

也就是mm_types.h

我们也是寻找include/linux目录下

在这里也就是mm_types.h

由于我们在这里使用了init_task

是一个0号进程 那么也是有相应的头文件来支持的

对应的是

这个头文件 好我们来大致的检查一下我们的代码

在这里

我们在这里还可以使用count字段来打印它的总体个数

我们在最后添加上

也就是

进程的个数

好 我们来进行编译

在这里会有一个警告说%d是 int的打印格式

但是我们在这里是atomic_t也就是原子类的打印

那么是P的files下的count字段我们先来看一下count字段

是在这里它是一个原子类型

count字段 前面说到它记录的是files_struct结构体使用的次数

那么这个统计的结果也就是提供了一个参考 它是一个共享变量

count既然统计的是次数 那么自然他的操作就是加一操作么

但是+1操作也是分为三步的

第一步先从内存中将变量的值读取到寄存器中

第二步寄存器加一 第三步从寄存器写回到内存

如果执行这三步时中间发生了中断 就有可能会影响到count字段的值

所以就会涉及到同步问题

那么原子操作就是linux系统提供的一种同步的措施

原子操作就可以保证指令是以原子的方式来被执行的

中间不受打断 没有任何的中断

我们首先来看atomic_t是定义在linux的types.h中

它是一个结构体中间也是一个int的类型

那么对它的一些操作是在

二尺目录下x86 include的asm目录下的atomic.h文件中

那么这里我们使用的是atomic_read

这里就可以保证它是对原子的一种读取操作

那么我们之前所说的 对它自加一和自减一的操作 怎么来保证它的一个

同步呢 在后面我们也会有 专门的原子操作

atomic_inc和atomic_dec 这里呢就是

内核中提供的对原子类型

的一些操作方式都是在

atomic.h文件中 我们在这里修改一些代码

我们在这里就需要修改它的读取方式

那么我们也要注意到一点就是我们得total_vm它

它的参数应该是一个atomic

它的这个指针类型 但是我们在files中

它的类型是一个atomic_t的一个类型

所以我们在这里需要进行取它的地址

我们还需要添加头文件 因为我们在这里 已经使用了 原子操作和原子操作对应的

类型 所以我们在这里要添加

types

还有对应的一些操作

我们来进行编译

好编译通过 我们来插入内核模块

我们打日志信息

好 我们可以看到在当前的进程中一共有284个进程

这里是打印出的一些字段 我们可以看到

这三个并没有total_vm字段说明它们的mm是空的 他们是内核线程

那就比如说它的total_vm是18179 那么说明这个进程的

线性空间总共有18179个页

这就是我们打印出来的一些对应的数据

好 谢谢大家

Linux 内核分析与应用课程列表:

第1章 概述

-1.1 Linux操作系统概述

--1.1 Linux 操作系统概述

-1.2 Linux内核结构以及内核模块编程

--Video

-1.3 Linux内核源码中的双链表结构

--Video

-1.4 源码分析-内核中的哈希表

--Video

-1.5 动手实践-Linux内核模块的插入和删除

--Video

-第1章 概述--章节测验

-第1章导学--引领你进入Linux内核的大门

第2章 内存寻址

-2.1 内存管理之内存寻址

--Video

-2.2 段机制

--Video

-2.3分页机制

--Video

-2.4 动手实践-把虚拟地址转换成物理地址

--Video

-第2章 内存寻址--章节测验

-第二章导学-从零打造自己的操作系统

第3章 进程管理

-3.1 进程概述

--Video

-3.2 Linux进程创建

--Video

-3.3 Linux进程调度

--Video

-3.4 动手实践-打印进程描述符task_struct中的字段

--Video

-3.5工程实践-基于内核模块的负载监控

--Video

-第3章 进程管理--章节测验

-第三章导学-进程背后琳琅满目的宝贝到哪里挖?

第4章 内存管理

-4.1 Linux内存管理机制

--Video

-4.2 进程用户空间管理机制

--Video

-4.3 物理内存分配与回收机制(上)

--Video

-4.4 物理内存分配与回收机制(下)

--Video

-4.5 动手实践-Linux内存映射基础(上)

--Video

-4.6 动手实践-Linux内存映射实现(中)

--Video

-4.7 动手实践-Linux内存映射测试(下)

--Video

-4.8 初学者对内存管理的常见疑惑

--初学者对内存管理的常见疑惑(一)

--初学者对内存管理的常见疑惑(二)

--初学者对内存管理的常见疑惑(三)

-第4章 内存管理--章节测验

第5章 中断

-5.1 中断机制概述

--Video

-5.2 中断处理机制

--Video

-5.3 中断下半部处理机制

--Video

-5.4 时钟中断机制

--Video

-5.5 动手实践-中断上半部的代码分析及应用

--Video

-5.6 动手实践-中断下半部的代码分析及应用

--Video

-第5章 中断--章节测验

第6章 系统调用

-6.1 Linux中的各种API

--Video

-6.2 系统调用机制

--Video

-6.3 动手实践-添加系统调用(系统调用日志收集系统)

--Video

-第6章 系统调用--章节测验

第7章 内核同步

-7.1 内核同步概述

--Video

-7.2 内核同步机制

--Video

-7.3 动手实践-内核多任务并发实例(上)

--Video

-7.4 动手实践-内核多任务并发实例(下)

--Video

-第7章 内核同步--章节测验

第8章 文件系统

-8.1 虚拟文件系统的引入

--Video

-8.2 虚拟文件系统的主要数据结构

--Video

-8.3 文件系统中的各种缓存

--Video

-8.4 页高速缓存机制以及读写

--Video

-8.5 动手实践-编写一个文件系统(上)

--Video

-8.6 动手实践-编写一个文件系统(中)

--Video

-8.7 动手实践-编写一个文件系统(下)

--Video

-第8章 文件系统--章节测验

第9章 设备驱动

-9.1 设备驱动概述

--Video

-9.2 I/O空间管理

--Video

-9.3 设备驱动模型

--Video

-9.4 字符设备驱动程序简介

--Video

-9.5 块设备驱动程序简介

--Video

-9.6 动手实践-编写字符设备驱动程序

--Video

-9.7工程实践-编写块设备驱动的基础(上)

--Video

-9.8 工程实践-块设备驱动程序分析(中)

--Video

-9.9 工程实践-块设备驱动程序实现(下)

--Video

-第9章 设备驱动--章节测验

致谢与说明

-致谢与说明

--Video

直播视频:从Linux内核学习到自主操作系统研发

-从Linux内核学习到自主操作系统研发

附录:实验代码、课件以及相关素材

-各章实验代码

-《Linux内核分析与应用》课件

-《Linux操作系统原理与应用》教材课堂视频

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。