Linux内核模块课程设计

上传人:xia****ian 文档编号:139435431 上传时间:2022-08-22 格式:DOC 页数:15 大小:855.51KB
收藏 版权申诉 举报 下载
Linux内核模块课程设计_第1页
第1页 / 共15页
Linux内核模块课程设计_第2页
第2页 / 共15页
Linux内核模块课程设计_第3页
第3页 / 共15页
资源描述:

《Linux内核模块课程设计》由会员分享,可在线阅读,更多相关《Linux内核模块课程设计(15页珍藏版)》请在装配图网上搜索。

1、Linux课程设计项目名称: 内核模块编程 姓 名: * 班 级: 计算机*班 学 号: 2008* 指导教师: * 日 期: 2011.6.192011.6.24 目录一.课程设计目的2二任务描述2三选题原因2四、准备阶段3五整体思路8六程序代码8七遇到的问题12八测试结果13九总结15一.课程设计目的通过课程设计对操作系统基本原理进行更深入的认识,以Linux为具体研究对象,分析理解操作系统底层实现,综合利用已学知识与技术,就Linux操作系统各功能方面进行模拟或实现二任务描述编写proc文件系统相关的内核模块:设计一个模块,该模块功能是列出系统中所有内核线程的程序名、PID号和进程状态。

2、再设计一个带参数的模块,参数为进程的PID号,功能是列出进程的家族信息,包括父进程、兄弟进程和子进程的程序名、PID号。三选题原因学习操作系统时,没有把内核这一块学好,所以想借此机会加强对操作系统底层的理解。四、准备阶段看到此题时不知道proc文件的作用,对内核的概念也很模糊,并且错误的以为内核利用一些命令来调用进程呢。很多东西都不理解,所以首先是看书上网逐一进行学习。下面是查找的一些资料。1.关于linux内核编程书本上有详细介绍并且也比较好理解。首先把书上例题演示了一遍,对模块编程就掌握的差不多了。模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的

3、一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。应用程序与内核模块程序的比较$sN _H;1o7f0C语言应用程序LUPA开源社区#t)VsE+s7T 内核模块程序LUPA开源社区1|-CX*C*U%sq4L1p使用函数LUPA开源社区g(D chDLibc库LUPA开源社区)l-KY5V:e45b 内核函数7si zK)O*n0运行空间aWx7h0用户空间LUPA开源社区#I wYfTV+H 内核空间$?k(e u7HQY4I0运行权限!e O;ba8X#H0普通用户LUPA开源社区:X AJ%

4、A4u 超级用户LUPA开源社区W7P!MUbMLP入口函数&xBJ(H:B H0 main()LUPA开源社区;fC.U o6F%e r H8Hmodule_init()4f RQV j KZM6F0出口函数LUPA开源社区2r)v0Q%wWI exit()LUPA开源社区cSr,o/Vzimodule_exit()LUPA开源社区v%K$IgD$j5?(a编译LUPA开源社区h%Ny mUZ2qt!AGcc cLUPA开源社区3_;M+Makefile连接+H(iB f.w$v7J0GccLUPA开源社区&wZKg!o&LinsmodLUPA开源社区Egc0E y C6O W运行LUPA开

5、源社区*o_$&G直接运行LUPA开源社区o!LK-Qo#dm D insmodsS#HOn v0调试LUPA开源社区uT-Q;kd7xGdbX.hw dP 0kdbug, kdb,kgdb等LUPA开源社区T ?o#F.H;m(Bg2. 编译工具make :Make工具通过一个称为 Makefile 的文件来完成并自动维护编译工作。课本上有提供一个超级通用的Makefile,此文件要与模块在同一个文件夹下。ifneq ($(KERNELRELEASE),)obj-m += nullparam.oelsePWD := $(shell pwd)KVER := $(shell uname -r)K

6、DIR := /lib/modules/$(KVER)/buildall:$(MAKE) -C $(KDIR) M=$(PWD)clean:rm -rf *.o *.mod.c *.ko *.symvers *.order *.markersendifKERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义, 所以make将读取执行else之后的内容。如果make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C $(KDIR) 指明跳转到内核源码目录下读取那里的

7、Makefile;M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句, 指明模块源码中各文件的依赖关系,以及要生成的目标模块名。obj-m += nullparam.o表示编译连接后将生成nullparam.o模块2.用户级线程:指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。 内核线程:指

8、需要内核的参与,由内核完成线程的调度。其依赖于操作系统核心,由内核的内部需求进行创建和撤销。3.proc文件系统:proc即process的缩写,最初的proc文件系统只是存放进程的相关信息。但现在的/proc文件系统除此之外还包含系统的状态信息和配置信息。/proc文件系统相当于内核的一个快照,该目录下的所有信息都是动态的从正在运行的内核中读取。基于这种原因,/proc文件系统就成为了用户和内核之间交互的接口。一方面,用户可以从/proc文件系统中读取很多内核释放出来的信息;另一方面,内核也可以在恰当的时候从用户那里得到输入信息,从而改变内核的相关状态和配置。相比传统的文件系统,/proc是

9、一种特殊的文件系统,即虚拟文件系统。这里的虚拟是强调/proc文件系统下的所有文件都存在于内存中而不是磁盘上。也就是说/proc文件系统只占用内存空间,而不占用系统的外存空间。/proc 虚拟文件系统可以广泛地用来报告内核的信息,也可以用来进行动态配置。它对于驱动程序和模块编程来说都是非常完整的。4. proc_dir_entry结构:proc文件系统的组织结构是proc_dir_entry结构,所有属于proc文件系统的文件,都对应一个proc_dir_entry结构,这个结构在proc_fs.h中定义。 struct proc_dir_entry /用来唯一标志proc_dir_entry

10、结构的节点号unsigned short low_ino; unsigned short namelen; /这个proc文件的名字。const char *name; /该proc文件的模式, 第一部分是文件的类型,第二部分是该文件的权限。mode_t mode; nlink_t nlink; uid_t uid; gid_t gid; /即我们使用“ls”命令时,所显示出的文件大小。unsigned long size; struct inode_operations * proc_iops; /* 是一个inode_operations结构,其中设置了针对这个proc索引节点的操作函数,

11、这样,我们就可以针对不同类型的proc文件,提供不同的方法,以完成不同的工作。*/ struct file_operations * proc_fops; /*是一个file_operations结构,其中放置了针对这个proc文件的操作函数,我们可以把对proc文件的读写操作,放在这个结构中,用以实现对/proc目录中的文件的读,写功能。*/get_info_t *get_info; /*当用户向proc文件读取的数据小于一个页面大小时,可以使用这个函数向用户返回数据。*/struct module *owner; struct proc_dir_entry *next, *parent,

12、*subdir; /*使用这些链表,在内存中,proc_dir_entry结构就以树的形式链接在一起。 */void *data; read_proc_t *read_proc; write_proc_t *write_proc; atomic_t count; /*该结构的使用计数。当一个proc_dir_entry结构的count减为零时,会释放该结构*/ int deleted; /*这是一个删除标志,当我们调用remove_proc_entry函数要删除一个proc_dir_entry时,如果发现该结构还在使用,就会设置该标志并且退出。 */ kdev_t rdev; /* read_

13、proc_t *read_proc 和write_proc_t *write_proc:这两个函数提供了对proc文件进行操作的简单接口。我们知道,对于proc文件,我们可以从中读取核心数据,还可以向其中写入数据,因此,对于一些功能比较简单的proc文件,我们只要实现这两个函数(或其中之一)即可,而不用设置inode_operations结构,这样,整个操作比较简单。实际上,我们会在后面的分析中看到,在注册proc文件的时候,会自动为proc_fops设置一个缺省的file_operations结构,如果我们只实现了上面提到的两个读写操作,而没有设置自己file_operations结构,那么

14、,会由缺省的inode_operations结构中的读写函数检查调用这两个函数。*/;5.函数create_proc_entry,由它创建并注册proc文件。struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) /*函数内容不必详细了解,只要会调用此函数即可。name为要创建的文件名,mode为创建文件的属性;parent指向该文件父目录的指针,如果创建的虚拟文件位于/proc下,则这个参数为NULL(表示 /proc 根目录)。*/6. re

15、ad_proc_t: 如果只是创建了虚拟文件,那么它并不能被读写。为此,我们必须为每个虚拟文件挂接读写函数,因为此题中只用到读函数,所以只看了函数指针read_proc字段的相关内容。类型定义如下:typedef int (read_proc_t)(char *page, char *start, off_t off, int count, int *eof, void *data); 当用户读创建的虚拟文件时,该文件对应的read_proc函数将被调用。该函数将数据写入内核的缓冲区page中。page 参数是数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常

16、一页是 4KB)时,需要使用 start 和 off 参数。当所有数据全部写入之后,就需要设置 eof(文件结束参数)。data 表示的是私有数据。page 缓冲区在内核空间中。7删除proc文件void remove_proc_entry(const char *name, struct proc_dir_entry *parent) 该函数在参数parent的所有孩子中查找指定的名字name,如果找到匹配的节点,那么,就将该结构从树结构中去掉。然后,如果删除的proc_dir_entry是目录结构,那么,就减少其父节点的链接数。8. sprintf函数: int sprintf( char

17、 *buffer, const char *format , argument . );除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,就在第二个参数:格式化字符串上。;返回值:字符串长度。输出格式:例如sprintf(s, %8d, 123); /产生: 123 ,宽度占8 个位置,右对齐。五整体思路:内核的输出进到了内核缓冲区中, /proc 目录下的所有信息都是动态的从正在运行的内核中读取,在这里使用proc文件系统显示内核内容,即用proc文件系统实现内核模块与用户交互。用户空间使用shell脚本。(因为想练一下shell脚本,所以用户空间没有用一般函数。)六程序代码#i

18、nclude#include#include#include#includeMODULE_LICENSE(Dual BSD/GPL);static struct proc_dir_entry *myfile;static int mod_init_modtest(void);static void mod_exit_modtest(void);module_init(mod_init_modtest);module_exit(mod_exit_modtest);static int proc_read_nullparam(char *page,char *start,off_t off,int

19、 count,int *eof,void *data)int record=0;struct task_struct *p;for_each_process(p)record=record+sprintf(page+record,name:%20s pid:%8d state:%8ldn,p-comm,p-pid,p-state);printk(KERN_INFOsssssssssssssssssssssssssssssssssssfffffffffffffffffffffffffffffffffffssssssssssssssssssss%sn,p-comm);/测试时用到的return r

20、ecord;int mod_init_modtest(void)myfile=create_proc_entry(nullparam,0500,NULL);myfile-read_proc=proc_read_nullparam;return 0;void mod_exit_modtest(void)remove_proc_entry(nullparam,NULL);printk(KERN_INFO-Module_export_symbol was deleted!-n);MODULE_AUTHOR(CHEN MENG YUAN);MODULE_DESCRIPTION(module1:Modu

21、le_export_symbol -sum_op-fac_op-);MODULE_VERSION(Ver );#include#include#include#include#includeMODULE_LICENSE(Dual BSD/GPL);static struct proc_dir_entry *myfile;static int mod_init_modtest(void);static void mod_exit_modtest(void);module_init(mod_init_modtest);module_exit(mod_exit_modtest);/static st

22、ruct task_struct *p,*allp;cannot definit here static int pid=0;module_param(pid,int,S_IRUGO);static int proc_read_pidparam(char *page,char *start,off_t off,int count,int *eof,void *data)int record=0;struct task_struct *p,*tmp1,*tmp2;for_each_process(p) if(p-pid=pid) record=record + sprintf(page+reco

23、rd,my name:%15s pid:%8dn,p-comm,p-pid); record=record + sprintf(page+record,Parent name:%15s pid:%8dn,p-parent-comm,p-parent-pid); list_for_each_entry(tmp1,&(p-children),sibling) record=record + sprintf(page+record,children name:%15s pid:%8dn,tmp1-comm,tmp1-pid); list_for_each_entry(tmp2,&(p-real_pa

24、rent-children),sibling) record=record + sprintf(page+record,brother name:%15s pid:%8dn,tmp2-comm,tmp2-pid); return record;int mod_init_modtest(void)myfile=create_proc_entry(pidparam3,0500,NULL);myfile-read_proc=proc_read_pidparam;return 0;void mod_exit_modtest(void)remove_proc_entry(pidparam3,NULL);

25、printk(KERN_INFO-Module_export_symbol was deleted!-n);MODULE_AUTHOR(CHEN MENG YUAN);MODULE_DESCRIPTION(module1:Module_export_symbol -sum_op-fac_op-);MODULE_VERSION(Ver );七遇到的问题当时编程时进程状态直接调用task_struct的state字段,没有进行深入研究,老师检查完,我查了一下state的相关知识。现现在列出一部分。1. 进程状态(State) 进程执行时,它会根据具体情况改变状态。进程状态是调度和对换的依据。Lin

26、ux中的进程主要有如下状态,如表4.1所示。表4.1 Linux进程的状态内核表示含义TASK_RUNNING可运行TASK_INTERRUPTIBLE可中断的等待状态TASK_UNINTERRUPTIBLE不可中断的等待状态TASK_ZOMBIE僵死TASK_STOPPED暂停TASK_SWAPPING换入/换出可运行状态处于这种状态的进程,要么正在运行、要么正准备运行。正在运行的进程就是当前进程(由current所指向的进程),而准备运行的进程只要得到CPU就可以立即投入运行,CPU是这些进程唯一等待的系统资源。系统中有一个运行队列(run_queue),用来容纳所有处于可运行状态的进程,

27、调度程序执行时,从中选择一个进程投入运行。在后面我们讨论进程调度的时候,可以看到运行队列的作用。当前运行进程一直处于该队列中,也就是说,current总是指向运行队列中的某个元素,只是具体指向谁由调度程序决定。等待状态处于该状态的进程正在等待某个事件(event)或某个资源,它肯定位于系统中的某个等待队列(wait_queue)中。Linux中处于等待状态的进程分为两种:可中断的等待状态和不可中断的等待状态。处于可中断等待态的进程可以被信号唤醒,如果收到信号,该进程就从等待状态进入可运行状态,并且加入到运行队列中,等待被调度;而处于不可中断等待态的进程是因为硬件环境不能满足而等待,例如等待特定

28、的系统资源,它任何情况下都不能被打断,只能用特定的方式来唤醒它,例如唤醒函数wake_up()等。暂停状态此时的进程暂时停止运行来接受某种特殊处理。通常当进程接收到SIGSTOP、SIGTSTP、SIGTTIN或 SIGTTOU信号后就处于这种状态。例如,正接受调试的进程就处于这种状态。僵死状态进程虽然已经终止,但由于某种原因,父进程还没有执行wait()系统调用,终止进程的信息也还没有回收。顾名思义,处于该状态的进程就是死进程,这种进程实际上是系统中的垃圾,必须进行相应处理以释放其占用的资源。Linux内核中对进程状态进行了如下宏定义。#define TASK_RUNNING 0#defin

29、e TASK_INTERRUPTIBLE 1#define TASK_UNINTERRUPTIBLE 2#define TASK_ZOMBIE 4#define TASK_STOPPED 8在我的测试结果中,几乎都都是1号状态,即可中断的等待状态。八测试结果改进输出格式后的测试结果:查看内核版本信息九总结通过此门课程设计真的学到了很多东西,linux学习只看课本不行,要进行linux环境下的实践才能真正掌握好linux,在课程设计过程中发现很多东西不会,一边查资料问同学,一边尝试,当有结果出来时真的很高兴,激发了我学习linux的兴趣。课程设计完成了,不能说我很好的掌握了内核模块编程与proc文件系统,但自己感觉比以前是进步了,还是很高兴。

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!