实验题目
实验目的
通过本实验的学习,掌握信创操作系统内核定制中所常用的内核数据结构和函数,具体包括:
i.内核链表;
ii. 内核内存的分配释放;
iii.内核线程;
iv.内核锁;
实验内容
设计一个内核模块,并在此内核模块中创建一个内核链表以及两个内核线程。
• 线程1需要遍历进程链表并将各个进程的 pid、进程名加入到内核链表中。
• 线程2中需不断从内核链表中取出节点并打印该节点的元素。
在卸载模块时停止内核线程并释放资源。
代码思路
(本博客思路仅供参考,禁止抄袭代码,否则后果自负,在此给出相关编写方法和伪代码,可运行代码将于2024年12月31日后更新)
初始化:
创建一个链表用于保存进程的 PID 和进程名。
初始化自旋锁,以保证多线程环境下链表操作的安全性。
创建两个内核线程:
线程1:遍历进程链表,将每个进程的 PID 和进程名保存到内核链表。
线程2:从链表中取出元素并打印进程信息。
线程1:
使用 for_each_process 宏遍历系统中的所有进程。
为每个进程创建一个链表节点,保存其 PID 和进程名,并将其加入链表。
线程2:
不断从链表中取出节点,打印进程的 PID 和进程名,并释放内存。
需要对链表的访问加锁,以避免与线程1的冲突。
模块卸载:
停止线程。
清空链表,释放所有节点的内存。
函数:kernel_module_init()
初始化链表 my_list
初始化自旋锁 lock
创建线程1,执行 thread1_func()
如果线程1创建失败:
打印错误信息并返回错误代码
创建线程2,执行 thread2_func()
如果线程2创建失败:
停止线程1,打印错误信息并返回错误代码
返回 0
函数:thread1_func()
while (线程未停止):
进入读保护 (rcu_read_lock)
遍历系统中所有进程 (for_each_process):
为每个进程分配节点内存
将进程 PID 和 进程名 保存到节点
加锁
将节点插入链表尾部
解锁
退出读保护 (rcu_read_unlock)
休眠 5 秒
函数:thread2_func()
while (线程未停止):
加锁
遍历链表中的每个节点:
打印 PID 和进程名
从链表中删除节点
释放节点内存
解锁
休眠 5 秒
函数:kernel_module_exit()
停止线程1
停止线程2
加锁
遍历并清空链表:
释放每个节点的内存
解锁
打印 "模块卸载成功"
关键步骤详解
线程1 使用 for_each_process 宏遍历系统中的所有进程,使用 kmalloc 动态分配内存来存储每个进程的 PID 和进程名,最后将其加入链表。
线程2 定期从链表中取出并打印进程信息,并释放节点的内存。
自旋锁 用来保证线程1和线程2对链表的访问不会出现竞争条件。
卸载模块 时,停止所有线程并清理链表中的节点。
操作步骤
登录虚拟机
本实验使用信创操作系统,登录方法较为特殊。
(1)复制登录命令,登录Pod
(2)复制Pod登录密码
(3)复制登录命令,登录虚拟机
(4)复制虚拟机登录密码
至此,你应该已经进入虚拟机内部,输入命令即可操纵机器。
查找资源文件
本次实验文件位于~/lab/1
目录下,cd lab/1
进入目录
而后将我们已经在本地编辑好的代码复制进去(通过vim),此处需查询vim使用手册。
输入vi 文件名
查看文件,按ESC
进入编辑模式,而后输入dd
删除光标当前行及以下的部分,转到本机编辑好的文件,复制,右击鼠标即可将当前剪贴板里的内容粘贴进去,按ESC
,输入:wq
保存并退出。
编译模块
输入make
,进行编译(应该不会报错,我没有报错,若有错误请自行百度)。
加载模块&查看日志
输入sudo insmod kernel_module.ko
,不会有输出,而后输入dmesg
查看日志,可以看见实验结果输出。
卸载模块
使用 rmmod
卸载模块
sudo rmmod kernel_module
实验结果
使用 dmesg 命令可以观察到当前系统中运行的所有进程的 pid 与进程名。
成功成功,撒花