news 2026/4/22 18:17:14

操作系统课程设计:2-添加内核模块

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
操作系统课程设计:2-添加内核模块

1.实验目的

1.掌握内核模块基本编程技术

2.向内核中添加一个内核模块,打印进程控制块信息,编译模块

3.加载、卸载模块

2.实验截图及结果分析

(1)实验截图

① 编译环节

② 加载模块

③ 卸载模块

卸载前:

卸载后:

④ 删除编译的文件

(2)实验结果分析

本次实验围绕添加内核模块展开,从编译、加载、卸载模块以及打印进程控制块信息等多方面进行操作,实验结果具有多维度的分析价值。

①编译环节

在编译过程中,通过执行make命令,依据Makefile文件中的配置,系统成功调用kbuild构建系统。从输出的编译信息可知,系统首先进入内核源码目录,读取顶层Makefile文件,随后依次对showPCB.c进行编译生成.o文件,再经过MODPOST处理和链接等步骤,最终生成后缀为.ko的内核模块showPCB.ko。这一过程严格遵循内核模块编译的标准流程,表明Makefile配置正确,kbuild构建系统能够顺利工作,确保了模块从源码到可加载内核模块的正确转换。

②加载模块环节

使用sudo insmod showPCB.ko命令加载模块后,通过sudo dmesg查看内核日志,获取到丰富的进程控制块信息。这些信息反映了进程在系统中的实时状态。例如,pid为 3075,表明当前运行进程在系统中的唯一标识;state、flags等字段详细描述了进程当前的运行状态和相关属性。其中,rcu_tasks_nvcsw为 0,说明在最近一次 RCU 更新完成后,该 CPU 上未发生非抢占式上下文切换。这些信息为深入了解系统进程调度和资源管理提供了有力依据,也验证了模块中打印进程控制块信息功能的正确性。

③卸载模块环节

卸载前使用lsmod命令查看系统中已加载的模块,showPCB模块显示在列表中,证明其已成功加载。执行sudo rmmod showPCB命令卸载模块后,再次使用lsmod查看,showPCB模块从列表中消失,表明卸载操作成功。这验证了模块的可卸载性,符合内核模块动态加载和卸载的机制设计,确保了系统资源的有效管理,当模块不再使用时能够及时从内核中移除,释放相关资源。

④删除编译文件环节

执行make clean命令,依据Makefile中clean目标的定义,系统成功删除了编译生成的showPCB.ko、showPCB.mod.c、showPCB.mod.o和showPCB.o文件。这一操作不仅清理了项目目录,避免文件冗余,还有助于在后续重新编译时确保生成的文件是最新的,防止因旧文件残留导致的编译错误,保持开发环境的整洁和规范性。

整体而言,本次实验各项操作结果符合预期,成功实现了向内核添加模块、打印进程控制块信息、编译、加载和卸载模块等目标。

3.实验程序

(1)showPCB.c

#include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/list.h> // 定义task_struct类型别名 typedef struct task_struct ts; // 模块初始化函数,使用正确的函数名 __init 修饰 static int __init my_module_init(void) { ts *now; now = current; printk("用户标识:\ncomm: %s\n\n", now->comm); printk("进程当前的状态:\nstate: %ld\n\n", now->state); printk("反映进程状态的信息,但不是运行状态:\nflags: %d\n\n", now->flags); printk("指向 ptrace_area 的指针,其中包含了调试信息和控制方法。通过使用 ptrace 系统调用,父进程可以与子进程进行交互: \nptrace: %d\n\n", now->ptrace); printk("正在CPU上运行的进程:\non_cpu: %d\n\n", now->on_cpu); printk("处理器:\ncpu: %d\n\n", now->cpu); printk("表示唤醒目标(wakee)被唤醒的次数:\nwakee_flips: %d\n\n", now->wakee_flips); printk("存储唤醒目标(wakee)的翻转衰减时间戳,具体来说,它表示最后一次唤醒目标翻转(flip)的时间: \nwakee_flip_decay_ts: %ld\n\n", now->wakee_flip_decay_ts); printk("一个函数,用于将指定的CPU唤醒,将CPU从空闲状态切换到活动状态:\nwake_cpu: %d\n\n", now->wake_cpu); printk("一个成员变量,用于表示进程是否在就绪队列(run queue)上:\non_rq: %d\n\n", now->on_rq); printk("进程优先级字段,它表示进程的优先级级别:\nprio: %d\n\n", now->prio); printk("进程优先级字段之一,表示进程的静态优先级:\nstatic_prio: %d\n\n", now->static_prio); printk("用于表示进程优先级的一个字段,它基于static_prio和调度策略计算出来:\nnormal_prio: %d\n\n", now->normal_prio); printk("用于表示实时进程优先级的一个字段:\nrt_priority: %d\n\n", now->rt_priority); printk("一个结构体,用于表示硬件分支跟踪(btrace)的序列:\nbtrace_seq: %d\n\n", now->btrace_seq); printk("实用于本进程的调度政策: \npolicy: %u\n\n", (unsigned int)now->policy); printk("一个字段,表示进程可以在哪些处理器上执行:\nnr_cpus_allowed: %d\n\n", now->nr_cpus_allowed); printk("一个统计量,表示在最近一次RCU(Read-Copy-Update)更新完成之后,该CPU上从开始到现在为止,执行了非抢占式上下文切换的次数:\nrcu_tasks_nvcsw: %ld\n\n", now->rcu_tasks_nvcsw); printk("一个统计量,表示在最近一次RCU(Read-Copy-Update)更新完成之后,该CPU上从开始到现在为止,执行了空闲任务的次数:\nrcu_tasks_idle_cpu: %d\n\n", now->rcu_tasks_idle_cpu); printk("表示进程退出状态的字段,有两种取值,1-EXIT_ZOMBIE(僵尸进程),2-EXIT_DEAD(进程已经死亡且已经回收):\nexit_state: %d\n\n", now->exit_state); printk("进程退出时的退出码,通常用于表示进程的退出状态,是一个整数值,通常为0表示进程正常终止,而非0值表示进程执行过程中有错误发生,比如溢出、除数为0等: \nexit_code %d\n\n", now->exit_code); printk("进程终止时发给父进程的信号:\nexit_signal: %d\n\n", now->exit_signal); printk("父进程消亡时发出的信号:\npdeath_signal: %d\n\n", now->pdeath_signal); printk("job control(作业控制)是bash环境下的一个工作管理机制。它能够在一个终端机下面进行多个工作管理。这些工作都是bash的子进程: \njobctl: %ld\n\n", now->jobctl); printk("personality是指进程的个性化设置,用于控制进程的行为和属性。personality是一个进程描述符的成员,可以通过设置personality字段来启用不同的进程个性化设置: \npersonality: %d\n\n", now->personality); printk("一个原子标志类型,用于实现非原子操作的标记: \natomic_flags: %ld\n\n", now->atomic_flags); printk("一个正整数,通常用于唯一标识正在运行的进程: \npid: %d\n\n", (int)now->pid); printk("tgid(线程组标识符)是一个进程标识符,它表示当前线程所在的线程组的标识符: \ntgid: %d\n\n", (int)now->tgid); printk("stack_canary是一种安全机制,用于防止栈溢出攻击。它通常被用于保护函数返回地址,以防止攻击者通过覆盖返回指针来控制程序的执行流程: \nstack_canary: %ld\n\n", now->stack_canary); printk("一个进程标识符,通常用于标识会话层。会话层是操作系统中负责进程间通信(IPC)的一层,它管理着进程之间的通信和资源共享: \nsessionid: %d\n\n", now->sessionid); return 0; } // 模块清理函数,使用正确的函数名 __exit 修饰 static void __exit my_module_cleanup(void) { printk("<1>Goodbye cruel world\n"); } // 注册模块初始化和清理函数 module_init(my_module_init); module_exit(my_module_cleanup); // 指定模块许可证 MODULE_LICENSE("GPL");

(2)Makefile

obj-m := showPCB.o KERNELDIR = /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -f showPCB.ko showPCB.mod.c showPCB.mod.o showPCB.o
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 13:53:15

13、利用 Windows 环境开发应用程序的技术指南

利用 Windows 环境开发应用程序的技术指南 在现代软件开发中,充分利用操作系统提供的环境和功能可以显著提升应用程序的性能和用户体验。本文将深入介绍 Windows 系统中一些重要的开发技术,包括 PlayToManager 初始化、后台任务的实现与注册、搜索合约的集成等内容。 1. Pl…

作者头像 李华
网站建设 2026/4/18 7:38:14

19、数据管理全解析:从本地到远程的数据处理方案

数据管理全解析:从本地到远程的数据处理方案 在应用开发中,数据管理是至关重要的一环。本文将详细介绍不同类型数据的管理方式,包括会话状态、临时数据、用户数据,以及如何使用 SQLite 数据库和获取远程数据。 1. 会话状态管理 会话状态的保存和恢复是确保应用在不同状态…

作者头像 李华
网站建设 2026/4/17 20:56:20

科学提升孩子记忆力的五大方法

作为家长&#xff0c;你是否经常为孩子“记不住”知识点而焦虑&#xff1f;明明反复背诵&#xff0c;考试时却一片空白。其实&#xff0c;这并非孩子不够努力&#xff0c;而是记忆方法出了偏差。根据脑科学研究&#xff0c;人类大脑的记忆潜力远超想象&#xff0c;关键在于激活…

作者头像 李华
网站建设 2026/4/17 2:41:48

免费音频转换利器:用fre:ac解决你的音频处理难题

免费音频转换利器&#xff1a;用fre:ac解决你的音频处理难题 【免费下载链接】freac The fre:ac audio converter project 项目地址: https://gitcode.com/gh_mirrors/fr/freac 你是不是也遇到过这样的困扰&#xff1a;下载的音乐格式不兼容播放器&#xff0c;收藏的CD想…

作者头像 李华
网站建设 2026/4/14 2:08:43

三维重建终极指南:Astra Toolbox快速上手完整教程

三维重建终极指南&#xff1a;Astra Toolbox快速上手完整教程 【免费下载链接】astra-toolbox ASTRA Tomography Toolbox 项目地址: https://gitcode.com/gh_mirrors/as/astra-toolbox Astra Toolbox 是一款功能强大的开源三维重建与断层扫描工具箱&#xff0c;专为医学…

作者头像 李华
网站建设 2026/4/22 15:40:59

施工企业必看:红圈跟明建云哪个好?全面功能与核心优势大揭秘

面对堆积如山的报表、散落各处的数据,以及瞬息万变的市场,施工企业的管理者们常常感到力不从心:项目成本究竟是否可控?资金流是否安全?经营风险藏在哪里?选择一款真正懂业务、能落地的数字化管理系统,已不再是“锦上添花”,而是关乎企业生存与高质量发展的“必修课”。在众多…

作者头像 李华