内核中_init,_exit中的作用

__init, __initdata等属性标志,是要把这种属性的代码放入目标文件的.init.text节,数据放入.init.data节──这一过程是通过编译内核时为相关目标平台提供了xxx.lds链接脚本来指导ld完成的。
      对编译成module的代码和数据来说,当模块加载时,__init属性的函数就被执行;
   对 静态编入内核的代码和数据来说,当内核引导时, do_basic_setup()函数调用do_initcalls()函数,后者负责所有.init节函数的执行
   在初始化完成后,用这些关键字标识的函数或数据所占的内存会被释放掉。
1)
所有标识为__init的函数在链接的时候都放在.init.text这个区段内,
在这个区段中,函数的摆放顺序是和链接的顺序有关的,是不确定的。

2)
所有的__init函数在区段.initcall.init中还保存了一份函数指针,
在初始化时内核会通过这些函数指针调用这些__init函数指针,
并在整个初始化完成后,释放整个init区段
(包括.init.text,.initcall.init等),

注意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,
和1)中所述的这些函数本身在.init.text区段中的顺序无关。

在2.4内核中,这些函数指针的顺序也是和链接的顺序有关的,是不确定的。

在2.6内核中,initcall.init区段又分成7个子区段,分别是
.initcall1.init
.initcall2.init
.initcall3.init
.initcall4.init
.initcall5.init
.initcall6.init
.initcall7.init
(参见include/linux/init.h和vmlinux.lds )
当需要把函数fn放到.initcall1.init区段时,只要声明
core_initcall(fn);
即可。

其他的各个区段的定义方法分别是:
core_initcall(fn) --->.initcall1.init
postcore_initcall(fn) --->.initcall2.init
arch_initcall(fn) --->.initcall3.init
subsys_initcall(fn) --->.initcall4.init
fs_initcall(fn) --->.initcall5.init
device_initcall(fn) --->.initcall6.init
late_initcall(fn) --->.initcall7.init

而与2.4兼容的initcall(fn)则等价于device_initcall(fn)。

各个子区段之间的顺序是确定的,即先调用.initcall1.init中的函数指针
再调用.initcall2.init中的函数指针,等等。
而在每个子区段中的函数指针的顺序是和链接顺序相关的,是不确定的。

在内核中,不同的init函数被放在不同的子区段中,因此也就决定了它们的调用顺序。
这样也就解决了一些init函数之间必须保证一定的调用顺序的问题。

2. Linux Kernel源代码中与段有关的重要宏定义

A. 关于__init、__initdata、__exit、__exitdata及类似的宏

打开Linux Kernel源代码树中的文件:include/init.h,可以看到有下面的宏定议:

#define __init  __attribute__ ((__section__ (".init.text")))  __cold

#define __initdata    __attribute__ (( __section__ (".init.data")))

#define __exitdata   __attribute__ (( __section__ (".exit.data")))

#define __exit_call  __attribute_used__ __attribute__ (( __section__ (".exitcall.exit")))

#define __init_refok  oninline __attribute__ ((__section__ (".text.init.refok")))

#define __initdata_refok __attribute__ ((__section__ (".data.init.refok")))

#define __exit_refok noinline __attribute__ ((__section__ (".exit.text.refok")))

.........

#ifdef MODULE

#define __exit  __attribute__ (( __section__ (".exit.text"))) __cold

#else

#define __exit __attribute_used__ __attribute__ ((__section__ (".exit.text"))) __cold

#endif

对于经常写驱动模块或翻阅Kernel源代码的人,看到熟悉的宏了吧:__init, __initdata, __exit, __exitdata。

__init 宏最常用的地方是驱动模块初始化函数的定义处,其目的是将驱动模块的初始化函数放入名叫.init.text的输入段。当内核启动完毕后,这个段中的内存会被释放掉供其他使用。

__initdata宏用于数据定义,目的是将数据放入名叫.init.data的输入段。其它几个宏也类似。

另外需要注意的是,在以上定意中,用__section__代替了section。还有其它一些类似的宏定义,这里不一一列出,其作用都是类似的。

 

模块加载分为动态加载和静态加载。
所谓静态加载就是,开机加载系统时将模块加载上去,这就是编译进内核。
动态加载就是在开机以后将模块加载上去,这就是编译成模块!

 

init_module是默认的模块的入口,如果你想指定其他的函数作为模块的入口就需要
module_init函数来指定,比如
module_init   (your_func);
其中your_func是你编写的一个函数的名称.

 

init_module()是真正的入口,module_init是宏,如果在模块中使用,最终还是要转换到init_module()上。

如果不是在模块中使用,module_init可以说没有什么作用。总之,使用module_init方便代码在模块和非模块间移植。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jQuery笔记总结

来源于:http://blog.poetries.top/2016/10/20/review-jQuery/ http://www.jianshu.com/p/f8e3936b34c9 首先,来了解一下jQuery学习的整体思路 第一节 jQuery初步认知 jQuery概述 JQuery概念 javascript概念 基于Js语言的API和语法组织逻辑,通…

芯片生产流程

每个半导体产品的制造都需要数百个工艺,泛林集团将整个制造过程分为八个步骤:晶圆加工-氧化-光刻-刻蚀-薄膜沉积-互连-测试-封装。 一、晶圆加工 所有半导体工艺都始于一粒沙子!因为沙子所含的硅是生产晶圆所需要的原材料。晶圆是将硅(Si)或砷…

GRE Sub math 报名

Step1 注册ETS帐号 Step2 登录帐号,点击Register/Find Test Centers, Dates Step3 按照提示查询考场 如果没有结果而是出现了如下提示,意味着这个地方没有考位了,需要选择其他地方的考位 Step 4 接下来就和GRE general test的过程一样了&…

platform_device_系列函数及其设备注册的作用

platform_device_系列函数,实际上是注册了一个叫platform的虚拟总线。使用约定是如果一个不属于任何总线的设备,例如蓝牙,串口等设备,都需要挂在这个虚拟总线上。 driver/base/platform.c //platform设备声明 struct device pla…

示例解读 Python 2 和 Python 3 之间的主要差异

开发四年只会写业务代码,分布式高并发都不会还做程序员? 每门编程语言在发布更新之后,主要版本之间都会发生很大的变化。 在本文中,Vinodh Kumar 通过示例解释了 Python 2 和 Python 3 之间的一些重大差异,以帮助说明…

数字后端——布局

由于I / O单元和模块的布放已经在布图规划时完成,因此布局的剩余任务主要是对标准单元的布局。布局方案在布图规划时就已经做了决定,要么选择展平式布局,要么就是层次化布局。 一、布局目标 布局的目标也即布局内容实施之后所要达到的预期值…

python基础 函数 (四)

一 函数基本 def func1():print("hello world")return 1, "hello", ("wo", "ai"), ["ni", "da"], {"you": "xi"} # return 可以返回任意# 结果: (1, hello, (wo, ai), [ni, da…

c#注释

c#的注释分为:这里不能不说一下什么是注释。 注释本身不会执行,只是说明性文字,只供程序员阅读。 注释又分为:单行注释,多行注释,文档注释。 单行注释://开始 多行注释:/*开始&#…

嵌入式linux字符设备驱动

1. 我们需要先调用register_chrdev_region()或 alloc_chrdev_region()来向系统申请设备号int register_chrdev_region( dev_t first, unsigned int count, char *name ); //函数通过已知的设备号first来注册字符设备区域。 int alloc_chrdev_region( dev_t *dev, unsigned int…

数字后端——时钟树综合

在数字集成电路设计中,时钟信号是数据传输的基准,它对于同步数字系统的功能、性能和稳定性起决定性作用,所以时钟信号的特性及其分配网络尤被人们关注。时钟信号通常是整个芯片中有最大扇出、通过最长距离、以最高速度运行的信号。时钟信号必…

52次课(mysql用户管理、常用sql语句、 mysql数据库备份恢复)

MySQL创建用户以及授权 默认用户是root用户,不可能所有人员都用root用户,创建用户防止误删除,因为mysql里边有多个库每个库里有很多表,所以需要给单独的用户做一些授权我只需要它对某一个数据库有权限,或者说对某个数据…

线程池的种类,区别和使用场景

newCachedThreadPool: 底层:返回ThreadPoolExecutor实例,corePoolSize为0;maximumPoolSize为Integer.MAX_VALUE;keepAliveTime为60L;unit为TimeUnit.SECONDS;workQueue为SynchronousQueue(同步队…

20145225 《信息安全系统设计基础》第14周学习总结

第九章 虚拟存储器 虚拟存储器是计算机系统最重要的概念之一,它是对主存的一个抽象 三个重要能力: 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据&#xf…

数字后端——布线

布线是继布局和时钟树综合之后的重要物理实施任务,其内容是将分布在芯片核内的模块、标准单元和输入输出接口单元( I /O pad)按逻辑关系进行互连,其要求是百分之百地完成它们之间的所有逻辑信号的互连,并为满足各种约束条件进行优…

动态加载和静态加载及其编译步骤

在类unix操作系统中,驱动加载方式一般分为:动态加载和静态加载,下面分别对其详细论述。 一、动态加载 动态加载是将驱动模块加载到内核中,而不能放入/lib/modules/下。 在2.4内核中,加载驱动命令为:ins…

streamsets 集成 minio s3测试

具体streamsets crate 集成可以参考 streamsets crate 以下文档只关注minio 集成的配置 minio 服务 搭建 具体搭建参考: https://www.cnblogs.com/rongfengliang/p/9197315.html 创建bucket (crate 集成使用) 测试的csv 文件从https://www.s…

sqlite性能优化

1、数据库性能上 1.1 批量事务插入,提升数据插入的性能 由于sqlite默认每次插入都是事务,需要对文件进行读写,那么减少事务次数就能简书磁盘读写次数从而获得性能提升。 1.2 单条sql优于多条sql 实测发现,对于几十条sql插入当你替…

【codecombat】 试玩全攻略 第十四关 已知敌人

第十四关 已知敌人 在这一关里,我们的英雄获得了一副可以看见敌人的眼镜,所以他很强势的学会了“发现敌人”的技能。 hero.findNearestEnemy()命令,单词多了,首字母都要大写了,不然分不出来。玩过wow的小伙伴用过 宏命…

数字后端——信号完整性分析

随着光刻和集成电路制造工艺的不断进步,以及芯片的特征尺寸从深亚微米到纳米的迅速采用,人们一方面因为芯片的功能极大提高而受益,另一方面,当逻辑门的沟道长度减小时,门的开关时间会减小,这意味着输出驱动…

新浪前端面试

1、什么是Html语义化? 语义化 div > section,div > nav(语言自己能解释), input/(关闭符号) br/相对于样式标记,如 i(样式)/ em(语义);b(样式&#xff…