系统初始化函数集subsysinitcall和初始化段应用.docx
- 文档编号:28726883
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:7
- 大小:16.91KB
系统初始化函数集subsysinitcall和初始化段应用.docx
《系统初始化函数集subsysinitcall和初始化段应用.docx》由会员分享,可在线阅读,更多相关《系统初始化函数集subsysinitcall和初始化段应用.docx(7页珍藏版)》请在冰豆网上搜索。
系统初始化函数集subsysinitcall和初始化段应用
系统初始化函数集(subsys_initcall)和初始化段应用
系统初始化函数集(subsys_initcall)和初始化段应用
前言:
前段时间做一个项目需要设计一个动态库,并希望在加载库的同时自动执行一些初始化动作,于是联想到了linux内核众子系统的初始化,于是研究之,并在过这程中发现了初始化段的存在,利用初始化段实现了该功能。
工作一年,笔记积累多了,慢慢变得杂乱无章,于是开博,一方面整理笔记,梳理知识,另一方面和大家交流,共同进步。
keyword:
subsys_initcall,init,init_call
1系统初始化调用函数集分析(静态)
1.1函数定义
在linux内核代码里,运用了subsys_initcall来进行各种子系统的初始化,具体怎么初始化的呢?
其实并不复杂。
以2.6.29内核作为例子。
在
#definepure_initcall(fn)__define_initcall("0",fn,0)
#definecore_initcall(fn)__define_initcall("1",fn,1)
#definecore_initcall_sync(fn)__define_initcall("1s",fn,1s)
#definepostcore_initcall(fn)__define_initcall("2",fn,2)
#definepostcore_initcall_sync(fn)__define_initcall("2s",fn,2s)
#definearch_initcall(fn)__define_initcall("3",fn,3)
#definearch_initcall_sync(fn)__define_initcall("3s",fn,3s)
#definesubsys_initcall(fn)__define_initcall("4",fn,4)
#definesubsys_initcall_sync(fn)__define_initcall("4s",fn,4s)
#definefs_initcall(fn)__define_initcall("5",fn,5)
#definefs_initcall_sync(fn)__define_initcall("5s",fn,5s)
#definerootfs_initcall(fn)__define_initcall("rootfs",fn,rootfs)
#definedevice_initcall(fn)__define_initcall("6",fn,6)
#definedevice_initcall_sync(fn)__define_initcall("6s",fn,6s)
#definelate_initcall(fn)__define_initcall("7",fn,7)
#definelate_initcall_sync(fn)__define_initcall("7s",fn,7s)
而__define_initcall又被定义为
#define__define_initcall(level,fn,id)\
staticinitcall_t__initcall_##fn##id__used\
__attribute__((__section__(".initcall"level".init")))=fn
所以subsys_initcall(fn)==__initcall_fn4它将被链接器放于section.initcall4.init中。
(attribute将会在另一篇文章中介绍)
1.2初始化函数集的调用过程执行过程:
start_kernel->rest_init
系统在启动后在rest_init中会创建init内核线程
init->do_basic_setup->do_initcalls
do_initcalls中会把.initcall.init.中的函数依次执行一遍:
for(call=__initcall_start;call<__initcall_end;call++){
......
result=(*call)();
.........
}
这个__initcall_start是在文件
.initcall.init:
AT(ADDR(.initcall.init)-LOAD_OFFSET){
__initcall_start=.;
INITCALLS
__initcall_end=.;
}
INITCALLS被定义于
#defineINITCALLS\
*(.initcall0.init)\
*(.initcall0s.init)\
*(.initcall1.init)\
*(.initcall1s.init)\
*(.initcall2.init)\
*(.initcall2s.init)\
*(.initcall3.init)\
*(.initcall3s.init)\
*(.initcall4.init)\
*(.initcall4s.init)\
*(.initcall5.init)\
*(.initcall5s.init)\
*(.initcallrootfs.init)\
*(.initcall6.init)\
*(.initcall6s.init)\
*(.initcall7.init)\
*(.initcall7s.init)
2基于模块方式的初始化函数(动态)2.1函数定义subsys_initcall的静态调用方式应该讲清楚来龙去脉了,现在看看动态方式的初始化函数调用(模块方式)。
在
#definecore_initcall(fn)module_init(fn)
#definepostcore_initcall(fn)module_init(fn)
#definearch_initcall(fn)module_init(fn)
#definesubsys_initcall(fn)module_init(fn)
#definefs_initcall(fn)module_init(fn)
#definedevice_initcall(fn)module_init(fn)
#definelate_initcall(fn)module_init(fn)
这是在定义MODULE的情况下对subsys_initcall的定义,就是说对于驱动模块,使用subsys_initcall等价于使用module_init
2.2module_init分析下面先看看module_init宏究竟做了什么
#definemodule_init(initfn)\
staticinlineinitcall_t__inittest(void)\/*定义此函数用来检测传入函数的类型,并在编译时提供警告信息*/
{returninitfn;}\
intinit_module(void)__attribute__((alias(#initfn)));/*声明init_modlue为initfn的别名,insmod只查找名字为init_module函数并调用*/
typedefint(*initcall_t)(void);/*函数类型定义*/
在以模块方式编译一个模块的时候,会自动生成一个xxx.mod.c文件,在该文件里面定义一个structmodule变量,并把init函数设置为上面的init_module()而上面的这个init_module,被alias成模块的初始化函数(参考 __attribute__,alias,visibility,hidden>)。 也就是说,模块装载的时候(insmod,modprobe),sys_init_module()系统调用会调用module_init指定的函数(对于编译成>模块的情况)。 2.3module的自动加载内核在启动时已经检测到了系统的硬件设备,并把硬件设备信息通过sysfs内核虚拟文件系统导出。 sysfs文件系统由系统初始化脚本挂载到/sys上。 udev扫描sysfs文件系统,根据硬件设备信息生成热插拔(hotplug)事件,udev再读取这些事件,生成对应的硬件设备文件。 由于没有实际的硬件插拔动作,所以这一过程被称为coldplug。 udev完成coldplug操作,需要下面三个程序: udevtrigger——扫描sysfs文件系统,生成相应的硬件设备hotplug事件。 udevd——作为deamon,记录hotplug事件,然后排队后再发送给udev,避免事件冲突(raceconditions)。 udevsettle——查看udev事件队列,等队列内事件全部处理完毕才退出。 要规定事件怎样处理就要编写规则文件了.规则文件是udev的灵魂,没有规则文件,udev无法自动加载硬件设备的驱动模块。 它一般位于 3初始化段的应用这里给出一个简单的初始化段的使用例子,将a.c编译成一个动态库,其中,函数a()和函数c()放在两个不同的初始化段里,函数b()默认放置;编译main.c,链接到由a.c编译成的动态库,观察各函数的执行顺序。 #cata.c#include typedefint(*fn)(void); inta(void) { printf("a\n"); return0; } __attribute__((__section__(".init_array.2")))staticfninit_a=a; intc(void) { printf("c\n"); return0; } __attribute__((__section__(".init_array.1")))staticfninit_c=c; intb() { printf("b\n"); return0; } #catmain.c #include intb(); intmain() { printf("main\n"); b(); } #catmk.sh gcc-fPIC-g-ca.c gcc-shared-g-oliba.soa.o cpliba.so/lib/-fr gccmain.cliba.so ldconfig ./a.out #gcc-fPIC-g-ca.c #gcc-shared-g-oliba.soa.o #cpliba.so/lib/ #gccmain.cliba.so #ldconfig #./a.out a c main b
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 系统 初始化 函数 subsysinitcall 应用