1024G嵌入式资源大放送!包括但不限于CC、单片机、Linux等。私信回复1024,即可免费获取!前言 上一篇:文件系统有很多,但这几个最为重要介绍了procfs(进程文件系统的缩写),包含一个伪文件系统(启动时动态生成的文件系统),用于通过内核访问进程信息。这个文件系统通常被挂载到proc目录,proc中不仅仅放了进程相关信息,也存放着很多系统相关的信息。 这些信息都是内核开放给用户的,proc就是用户与内核直接交互的一个入口。从内核的角度看,内核是通过怎么样的方式把这些信息暴露给用户呢?这篇笔记我们来学习一下:内核创建proc节点的例子 我们先来看一个例子(Linux4。9。88fsproccpuinfo。c): 这就是创建proc下cpuinfo这个节点的相关代码,有了cpuinfo节点,我们就可以通过访问这个节点来得到cpu的一些信息: 从以上代码中,我们可以看到,其用proccreate这个函数来创造相关节点的,这个函数是一个内联函数,存放在Linux4。9。88includelinuxprocfs。h下:staticinlinestructprocdirentryproccreate(constcharname,umodetmode,structprocdirentryparent,conststructfileoperationsprocfops){returnproccreatedata(name,mode,parent,procfops,NULL);} 知识点:什么是内联函数?内联函数简单来说就是编译器将指定的函数体插入并取代每一处调用该函数的地方上下文,从而节省了每次调用函数带来的额外时间开支。 一般用于能够快速执行的函数,因为在这种情况下函数调用的时间消耗显得更为突出。这种方法对于很小的函数也有空间上的益处,并且它也使得一些其他的优化成为可能。 这么一看,似乎与宏有点相似?与宏有何不同? 宏调用并不执行类型检查,甚至连正常参数也不检查,但是函数调用却要检查。 C语言的宏使用的是文本替换,可能导致无法预料的后果,因为需要重新计算参数和操作顺序。 在宏中的编译错误很难发现,因为它们引用的是扩展的代码,而不是程序员键入的。 许多结构体使用宏或者使用不同的语法来表达很难理解。内联函数使用与普通函数相同的语言,可以随意的内联和不内联。 内联代码的调试信息通常比扩展的宏代码更有用。 以上介绍摘选自百度百科,关于内联更详细的介绍可自行查阅。 接着上面,proccreate函数有四个参数,分别为:name:要创建的文件名。 mode:文件的访问权限。 parent:父文件夹的procdirentry指针。 procfops:改文件的操作函数。 看到这个函数,有没有感到很熟悉?我们在学习驱动基础的时候,有用到了devicecreate函数来创建节点: devicecreate创建的设备节点存放于dev目录下,而proccreate函数创建的与系统信息相关的节点存放于proc目录下。既然它们这么相似,下面我们就模仿编写驱动的方式来编写我们关于proc的测试代码。proc实践 我们模仿字符设备驱动的编写方式,来编写基于proc的驱动。首先需要创建一个文件操作结构体helloprocoperations,创建一些helloprocopen、helloprocclose、helloprocread、helloprocwrite填到这个操作表里:微信公众号:嵌入式大杂烩includelinuxfs。hincludelinuxinit。hincludelinuxprocfs。hincludelinuxmodule。hincludelinuxuaccess。hstaticcharkernelbuf〔1024〕;defineMIN(a,b)(ab?a:b)staticinthelloprocopen(structinodenode,structfilefile){printk(sslined,FILE,FUNCTION,LINE);return0;}staticssizethelloprocread(structfilefile,charuserbuf,sizetsize,lofftoffset){interr;printk(sslined,FILE,FUNCTION,LINE);errcopytouser(buf,kernelbuf,MIN(1024,size));returnMIN(1024,size);}staticssizethelloprocwrite(structfilefile,constcharuserbuf,sizetsize,lofftoffset){interr;printk(sslined,FILE,FUNCTION,LINE);errcopyfromuser(kernelbuf,buf,MIN(1024,size));returnMIN(1024,size);}staticinthelloprocclose(structinodenode,structfilefile){printk(sslined,FILE,FUNCTION,LINE);return0;}staticconststructfileoperationshelloprocoperations{。ownerTHISMODULE,。openhelloprocopen,。readhelloprocread,。writehelloprocwrite,。releasehelloprocclose,};staticintinithelloprocinit(void){proccreate(helloproc,0,NULL,helloprocoperations);return0;}staticvoidexithelloprocexit(void){removeprocentry(helloproc,NULL);}moduleinit(helloprocinit);moduleexit(helloprocexit);MODULEDESCRIPTION(proctest);MODULELICENSE(GPL); 最上边的那个例子中用了一个fsinitcall宏,这与moduleinit的底层是差不多相同的(有宏参数不一样):moduleinitinitcalldeviceinitcalldefineinitcall fsinitcalldefineinitcall 为了方便,我们直接用moduleinit。 Makefile文件:KERNDIRhomebook100askimx6ullsdkLinux4。9。88C表示将当前的工作目录切换到指定目录中,M表示模块源码目录,modules表示编译模块all:makeC(KERNDIR)Mpwdmodulesclean:makeC(KERNDIR)Mpwdmodulescleanrmrfmodules。orderobjm表示将proctest。c这个文件编译为proctest。ko模块objmproctest。o 编译: 传到板子里测试: 可以看到,我们已经成功地在proc中留下了一个helloproc小脚印。可以看到,我们创建的基于proc下的驱动与创建基于dev下的真实的设备驱动的思路及套路是很相似的。这些都是属于内核的范畴,都是属于内核的东西,内核把想给我们能直接使用的东西(文件)都放于proc、dev等目录下,我们在应用端就可以很方便地访问这些文件开发我们的应用。猜你喜欢: 静态链接与动态链接(Linux) Linux驱动基础篇:hello驱动 Linux简单认识认识ELF文件 如何查看Linux命令工具的源码? Linux下应用开发基础知识大总结 Linux总线设备驱动模型 1024G嵌入式资源大放送!包括但不限于CC、单片机、Linux等。私信回复1024,即可免费获取!