当前位置: 首页 > news >正文

汕头企业网站建设公司seo排名优化推荐

汕头企业网站建设公司,seo排名优化推荐,免费网上商城模板,无法解析服务器域名如何管理驱动模块 由于Linux驱动模块众多,系统对模块加载顺序有要求,一些基础模块在系统启动时需要很早就被加载;开发者加入自己的模块时,需要维护一个模块初始化列表,上面两方面的做起来很困难,为了科学地…

如何管理驱动模块

由于Linux驱动模块众多,系统对模块加载顺序有要求,一些基础模块在系统启动时需要很早就被加载;开发者加入自己的模块时,需要维护一个模块初始化列表,上面两方面的做起来很困难,为了科学地管理这些模块,首先要解决两个问题:

  1. 如何方便开发者快捷加入自己的模块
  2. 如何管理模块的加载顺序

Linux 内核开发者是怎么实现的呢?在内核镜像文件中,自定义了一个段,这个段里面专门用来存放这些初始化函数的地址,内核启动时,只需要在这个段地址处取出函数指针,依次执行即可。

对模块的开发者,Linux内核提供了统一的宏定义接口,驱动开发者只需要将驱动程序用这些宏定义来修饰,这个模块的初始化函数接口的指针就被自动添加到了上述的段中,开发者完全不需要关心这个实现的细节。

对于各种各样的驱动而言,会存在一定的依赖关系,需要遵循先后顺序来进行初始化,考虑到这个问题,Linux内核开发者也对这一部分的初始化顺序做了分级处理。


Linux驱动模块的加载方式

Linux 驱动模块有两种加载方式,一是静态编译链接进内核,在系统启动过程中进行初始化;另外一是编译成可动态加载的module,通过insmod动态加载重定位到内核。


Linux 使用宏定义

Linux提供了一组宏定义对模块进行静态和动态加载,同时对不同的模块加载顺序做了处理,提供了不同的宏定义方法。这组宏定义在路径/kernel/include/linux/init.h中。

#ifndef MODULE#define __define_initcall(level,fn,id) \static initcall_t __initcall_##fn##id __used \__attribute__((__section__(".initcall" level ".init"))) = fn#define early_initcall(fn)	    	__define_initcall("early",fn,early)
#define pure_initcall(fn)		    __define_initcall("0",fn,0)
#define core_initcall(fn)		    __define_initcall("1",fn,1)
#define core_initcall_sync(fn)		__define_initcall("1s",fn,1s)
#define postcore_initcall(fn)		__define_initcall("2",fn,2)
#define postcore_initcall_sync(fn)	__define_initcall("2s",fn,2s)
#define arch_initcall(fn)		    __define_initcall("3",fn,3)
#define arch_initcall_sync(fn)		__define_initcall("3s",fn,3s)
#define subsys_initcall(fn)		    __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn)	__define_initcall("4s",fn,4s)
#define fs_initcall(fn)			    __define_initcall("5",fn,5)
#define fs_initcall_sync(fn)		__define_initcall("5s",fn,5s)
#define rootfs_initcall(fn)		    __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)		    __define_initcall("6",fn,6)
#define device_initcall_sync(fn)	__define_initcall("6s",fn,6s)
#define late_initcall(fn)		    __define_initcall("7",fn,7)
#define late_initcall_sync(fn)		__define_initcall("7s",fn,7s)
#define __initcall(fn)              device_initcall(fn)
#define module_init(x)	            __initcall(x);#else /* MODULE *//* Don't use these in modules, but some people do... */
#define early_initcall(fn)		module_init(fn)
#define core_initcall(fn)		module_init(fn)
#define postcore_initcall(fn)	module_init(fn)
#define arch_initcall(fn)		module_init(fn)
#define subsys_initcall(fn)		module_init(fn)
#define fs_initcall(fn)			module_init(fn)
#define device_initcall(fn)		module_init(fn)
#define late_initcall(fn)		module_init(fn)
#define security_initcall(fn)	module_init(fn)/* Each module must use one module_init(). */
#define module_init(initfn)					\static inline initcall_t __inittest(void)		\{ return initfn; }					\int init_module(void) __attribute__((alias(#initfn)));/* This is only required if you want to be unloadable. */
#define module_exit(exitfn)					\static inline exitcall_t __exittest(void)		\{ return exitfn; }					\void cleanup_module(void) __attribute__((alias(#exitfn)));
#endif /*end ifndef MODULE*/

Makefile是如何控制模块的加载模式的?在init.h中可以看到下面的宏定义:

#ifndef MODULE
// 宏定义--->(静态加载方式)
#else 
// 宏定义--->(动态加载方式)
#endif

当配置Makefiel时,将某个module配置为obj-m时,MODULE 这个宏就被定义,此时当前模块就被编译到内核代码中,内核启动时这个模块就被静态加载,反之,模块配置为obj-y,当前模块被配置为动态加载方式。


宏定义 __define_initcall 分析

我们看看如何解析这个宏__define_initcall:

#define __define_initcall(level,fn,id) \static initcall_t __initcall_##fn##id __used \__attribute__((__section__(".initcall" level ".init"))) = fn

_ * attribute * _ () 是gnu C中的扩展语法,它可以用来实现很多灵活的定义行为。
_ * attribute * _ ((_ * section * _ (“.initcall” #id “.init”)))表示编译时将目标符号放置在括号指定的段中。

在宏定义中,# 的作用是将目标字符串化,## 在宏定义中的作用是符号连接,将多个符号连接成一个符号,并不字符串化。

level是一个数字或者是数字+s,这个数字代表这个fn执行的优先级,数字越小,优先级越高,带s的fn优先级低于不带s的fn优先级

__used是一个宏定义

#define __used __attribute__((__used__))

使用前提是在编译器编译过程中,如果定义的符号没有被引用,编译器就会对其进行优化,不保留这个符号,而__attribute__((used))的作用是告诉编译器这个静态符号在编译的时候即使没有使用到也要保留这个符号。

这里的 initcall_t 是函数指针类型,对应的段:.initcall,如下:

typedef int (*initcall_t)(void);

上面所述,这个宏将我们的初始化函数放在".initcall" level ".init"中。这个段可以在Vmlinux.lds.h里面找到,如下:

#define INITCALLS                              \*(.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)

INITCALL 可以在vmlinux.lds.S里面找到:

.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {__init_begin = .;_sinittext = .;*(.init.text)_einittext = .;}.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }. = ALIGN(16);.init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {__setup_start = .;*(.init.setup)__setup_end = .;}.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {__initcall_start = .;INITCALLS //这里__initcall_end = .;}.con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {__con_initcall_start = .;*(.con_initcall.init)__con_initcall_end = .;}

Vmlinux.lds.h 中是系统启动时存放初始化数据的指针,执行完成后会被释放掉内存。根据上面的内存布局,可以列出初始化宏和 内存的对应关系

_init_begin        |-------------------||  .init.text       | ---- __init|-------------------||  .init.data       | ---- __initdata
_setup_start       |-------------------||  .init.setup      | ---- __setup_param
__initcall_start   |-------------------||  .initcall1.init  | ---- core_initcall|-------------------||  .initcall2.init  | ---- postcore_initcall|-------------------||  .initcall3.init  | ---- arch_initcall|-------------------||  .initcall4.init  | ---- subsys_initcall|-------------------||  .initcall5.init  | ---- fs_initcall|-------------------||  .initcall6.init  | ---- device_initcall|-------------------||  .initcall7.init  | ---- late_initcall
__initcall_end     |-------------------||                   ||    ... ... ...    ||                   |
__init_end         |-------------------|

宏定义 #define module_init(initfn)

#define module_init(initfn)					        \static inline initcall_t __inittest(void)		\{ return initfn; }					            \int init_module(void) __attribute__((alias(#initfn)));

前两句话只是做了一个检测,当传进来的函数指针的参数和返回值与initcall_t不一致时,就会有告警。第三句,是使用alias将initfn变名为init_module,当调用insmod将module加载进内核时,就会去找init_module作为入口地址,即传进来的initfn, 这样module就被加载了。


举例:

为了更方便地理解,我们举个例子来说明,开发者声明了这样一个函数:module_init(hello_init);

首先宏展开成:__define_initcall(“6”,hello_init, 6)
然后接着展开:static initcall_t __initcall_hello_init6 = hello_init; 定义了函数指针变量。
同时声明 __initcall_hello_init6 这个变量即使没被引用也保留符号,且将其放置在内核镜像的.initcall6.init段处。


xxx_initcall()宏定义调用追踪


从上面的分析,我们知道xxx_initcall是如何被定义,知道目标函数的放置位置,那么使用xxx_initcall()修饰的函数是怎么被调用的呢?下面就从内核 init/main.c函数起始部分start_kernel开始往下追踪,它的调用顺序为:

start_kernel  -> rest_init();-> kernel_thread(kernel_init, NULL, CLONE_FS);-> kernel_init()-> do_basic_setup();-> do_initcalls();

rest_init();启动 RCU 锁调度器 ,调用函数 kernel_thread 创建 kernel_init 进程,也就是 init 内核进程, init 进程的 PID 为 1。调用函数 kernel_thread 创建 kthreadd 内核进程,此内核进程的 PID 为 2。kthreadd 进程负责所有内核进程的调度和管理。

do_initcalls() 在这个函数中执行所有使用xxx_initcall()声明的函数,完成 Linux 下驱动模型子系统的初始化。

static void __init do_initcalls(void)
{initcall_t *fn;for (fn = __early_initcall_end; fn < __initcall_end; fn++)do_one_initcall(*fn);
}

函数中的 fn 为函数指针,fn++ 相当于函数指针+1,相当于内存地址+sizeof(fn)

int do_one_initcall(initcall_t fn)
{ret.result = fn();//执行功能函数
}

在do_one_initcall函数里执行被初始化的模块。

http://www.hkea.cn/news/810922/

相关文章:

  • 盐城网站设计网站流量统计工具
  • 网站上如何做相关推荐郑州建网站的公司
  • 漂亮大气的装潢室内设计网站模板 单页式html5网页模板包前端优化
  • 论坛网站开发开题报告青岛百度推广多少钱
  • 文山做网站如何优化百度seo排名
  • 上海展陈设计公司有哪些成都网站seo性价比高
  • 小韩网站源码360广告投放平台
  • 网站地图的重要性短信广告投放软件
  • 搭建直播网站需要怎么做教育培训机构平台
  • 濮阳网站网站建设网络营销策划是什么
  • 做新闻网站需要什么手续河北软文搜索引擎推广公司
  • 广州网站建设联系电话seo推广的公司
  • 一起做网店一样的网站关键词歌曲免费听
  • 负责网站建设推广本周热点新闻事件
  • 快速做网站优化谷歌在线浏览入口
  • 苏州企业网站建设开发与制作2023年6月份又封城了
  • 用java做网站可以吗吉林seo刷关键词排名优化
  • 网站建设面试google广告投放技巧
  • 整形网站整站源码如何让关键词排名靠前
  • php网站后台搭建外贸网站大全
  • 建 新闻 网站营销战略有哪些内容
  • 营销融合app网站seo招聘
  • 快速做网站的方法网站换了域名怎么查
  • 建筑工程网络计划图怎么编制百度seo搜索排名
  • 免费建网站系统百度云登陆首页
  • wordpress 采集微博网站建设优化
  • 做淘宝客新增网站推广百度用户服务中心人工电话
  • 域名备案网站建设书模板百度统计登录
  • 禁止WordPress访问官网优化关键词排名提升
  • 爬取漫画数据做网站今日热搜新闻头条