linux module_init

就像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含Kernel头文件,大多的Linux驱动程序需要包含下面三个头文件:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
其中,init.h 定义了驱动的初始化和退出相关的函数,kernel.h 定义了经常用到的函数原型及宏定义,module.h 定义了内核模块相关的函数、变量及宏。

      几乎每个linux驱动都有个module_init(与module_exit的定义在Init.h (/include/linux ) 中)。没错,驱动的加载就靠它。为什么需要这样一个宏?原因是按照一般的编程想法,各部分的初始化函数会在一个固定的函数里调用比如:

void init(void)

{

    init_a();

    init_b();

}

如果再加入一个初始化函数呢,那么在init_b()后面再加一行:init_c();这样确实能完成我们的功能,但这样有一定的问题,就是不能独 立的添加初始化函数,每次添加一个新的函数都要修改init函数。可以采用另一种方式来处理这个问题,只要用一个宏来修饰一下:

void init_a(void)

{

}

__initlist(init_a, 1);

它是怎么样通过这个宏来实现初始化函数列表的呢?先来看__initlist的定义:

#define __init __attribute__((unused, __section__(".initlist") ))

#define __initlist(fn, lvl) /
static initlist_t __init_##fn __init = { /
 magic:    INIT_MAGIC, /
 callback: fn, /
 level:   lvl }

请注意:__section__(".initlist"), 这个属性起什么作用呢?它告诉连接器这个变量存放在.initlist 区段,如果所有的初始化函数都是用这个宏,那么每个函数会有对应的一个initlist_t结构体变量存放在.initlist区段,也就是说我们可以在.initlist区段找到所有初始化函数的指针。怎么找到.initlist区段的地址呢?

extern u32 __initlist_start;
extern u32 __initlist_end;

这两个变量起作用了,__initlist_start是.initlist区段的开始,__initlist_end是结束,通过这两个变量我们就可以访问到所有的初始化函数了。这两个变量在那定义的呢?在一个连接器脚本文件里

 . = ALIGN(4);
 .initlist : {
  __initlist_start = .;
  *(.initlist)
  __initlist_end = .;
 }
这两个变量的值正好定义在.initlist区段的开始和结束地址,所以我们能通过这两个变量访问到所有的初始化函数。

      与此类似,内核中也是用到这种方法,所以我们写驱动的时候比较独立,不用我们自己添加代码在一个固定的地方来调用我们自己的初始化函数和退出函数,连接器已经为我们做好了。先来分析一下module_init。定义如下:

#define module_init(x)     __initcall(x);              //include/linux/init.h

#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn)                 __define_initcall("6",fn,6)

#define __define_initcall(level,fn,id) /

         static initcall_t __initcall_##fn##id __used /

         __attribute__((__section__(".initcall" level ".init"))) = fn

      如果某驱动想以func作为该驱动的入口,则可以如下声明:module_init(func);被上面的宏处理过后,变成 __initcall_func6 __used加入到内核映像的".initcall"区。内核的加载的时候,会搜索".initcall"中的所有条目,并按优先级加载它们,普通驱动程 序的优先级是6。其它模块优先级列出如下:值越小,越先加载。

#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)

可以看到,被声明为pure_initcall的最先加载。

      module_init除了初始化加载之外,还有后期释放内存的作用。linux kernel中有很大一部分代码是设备驱动代码,这些驱动代码都有初始化和反初始化函数,这些代码一般都只执行一次,为了有更有效的利用内存,这些代码所 占用的内存可以释放出来。

      linux就是这样做的,对只需要初始化运行一次的函数都加上__init属性,__init 宏告诉编译器如果这个模块被编译到内核则把这个函数放到(.init.text)段,module_exit的参数卸载时同__init类似,如果驱动被 编译进内核,则__exit宏会忽略清理函数,因为编译进内核的模块不需要做清理工作,显然__init和__exit对动态加载的模块是无效的,只支持 完全编译进内核。

      在kernel初始化后期,释放所有这些函数代码所占的内存空间。连接器把带__init属性的函数放在同一个section里,在用完以后,把整个section释放掉。当函数初始化完成后这个区域可以被清除掉以节约系统内存。Kenrel 启动时看到的消息“Freeing unused kernel memory: xxxk freed ”同它有关。 

      我们看源码,init/main.c中start_kernel是进入kernel()的第一个c函数,在这个函数的最后一行是rest_init();

static void rest_init(void)
{
     .....

     kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
     unlock_kernel();
     cpu_idle();

     .....
}
创建了一个内核线程,主函数kernel_init末尾有个函数:

 /*
  * Ok, we have completed the initial bootup, and
  * we're essentially up and running. Get rid of the
  * initmem segments and start the user-mode stuff..
  */
 init_post();

这个init_post中的第一句就是free_initmem();就是用来释放初始化代码和数据的。

void free_initmem(void)
{
    if (!machine_is_integrator() && !machine_is_cintegrator()) {
    free_area((unsigned long)(&__init_begin),
     (unsigned long)(&__init_end),
     "init");
     }
}

接下来就是kernel内存管理的事了。

参考地址:http://blog.csdn.net/citytramper/archive/2006/02/16/600708.aspx

http://blog.csdn.net/citytramper/archive/2006/04/15/664930.aspx

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

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

相关文章

数据结构之堆:堆的排序,Python代码实现——13

堆的排序&#xff0c;使用Python代码实现 上一节对堆进行了简单的实现&#xff0c;但是实现的堆只是部分有序&#xff08;父结点大于子结点&#xff0c;子结点之间无序&#xff09; 接下来我们实现对堆的所有元素进行升序排序 排序过程 实现步骤: 构造堆;得到堆顶元素,这个…

Anaconda 镜像源操作(查看配置删除)

一、Anaconda查看镜像配置 conda config --show channelschannels: https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/defaults二、添加清华大学镜像 conda config --add channels https://mirrors.tuna.t…

multi-line comment In file

写注释引起的编译问题&#xff1a; //s3c_gpio_cfgpin(pin, GTP_INT_CFG); \//s3c_gpio_cfgpin(pin, GTP_INT_CFG); \ 如果向上面那样写注释的话&#xff0c;就会引起问题&#xff0c;GCC&#xff0c;警告&#xff0c;有可能编译不通过&#xff0c;我遇到的问题就是编译不通过…

资治通鉴

本书于2017年1月15日开始看并于2017年1月17日看完&#xff0c;基本上只是culver看了一遍&#xff0c;只了解了故事而并没有分析&#xff0c;故事中每个人的思想和可能的想法&#xff0c;而且司马光对于宋朝以前的历史是截取了很多的片段记载的&#xff0c;并不能完整的了解历史…

【完美解决方案】module ‘cv2.cv2‘ has no attribute ‘xfeatures2d‘

一、问题描述 在学习openCV的过程中使用了SIFT的时候&#xff0c;发现书上的代码用不了&#xff0c;报错&#xff1a; module cv2.cv2 has no attribute xfeatures2d 二、问题原因 算法被申请了专利&#xff0c;将opencv版本退到3.4.2即可解决&#xff0c;必须小于等于Python…

数据结构之优先队列:优先队列的介绍与基础操作实现,Python代码实现——14

优先队列(Priority queue)的介绍 优先队列是计算机中一种抽象的数据结构类&#xff0c;它有着一个类似和队列或者堆的结构&#xff0c;但是其中每个元素额外有一个优先级别在一个优先队列中&#xff0c;一个高优先顺序的元素会先执行与低优先顺序的元素。在它的执行过程中&…

初识--百年孤独

转载于:https://www.cnblogs.com/xmyun/articles/6306290.html

OpenCV_09 模版匹配和霍夫变换:霍夫线检测+霍夫圆检测

1 模板匹配 1.1 原理 所谓的模板匹配&#xff0c;就是在给定的图片中查找和模板最相似的区域&#xff0c;该算法的输入包括模板和图片&#xff0c;整个任务的思路就是按照滑窗的思路不断的移动模板图片&#xff0c;计算其与图像中对应区域的匹配度&#xff0c;最终将匹配度最…

UICollectionView下拉使header放大模糊

模糊主要使用UIVisualEffectView&#xff0c;这只在ios8以后适用 //模糊的遮罩view property(nonatomic,strong) UIVisualEffectView *effectView; property(nonatomic,strong) CollectionviewLayout *layout;CollectionviewLayout *layout [[CollectionviewLayout alloc]init…

数据结构之优先队列:最小索引优先队列,Python代码实现——15

最小索引优先队列(Min index priority queue) 在之前实现的最大优先队列和最小优先队列,他们可以分别快速访问到队列中最大元索和最小元素,但是他们有一 个缺点,就是没有办法通过索引访问已存在于优先队列中的对象,并更新它们。 为了实现这个目的,在优先队列的基础上,学习一种…

OpenCV_10 傅里叶变换:频域滤波+CV的应用

1 傅里叶变换的理解 傅里叶变换是由法国的一位数学家Joseph Fourier在18世纪提出来的&#xff0c;他认为&#xff1a;任何连续周期的信号都可以由一组适当的正弦曲线组合而成。 傅里叶变换是描述信号的需要&#xff0c;它能够反映信号的特征&#xff0c;并可以使用特征值进行量…

extern 详解

在C环境下使用C函数的时候&#xff0c;常常会出现编译器无法找到obj模块中的C函数定义&#xff0c;从而导致链接失败的情况&#xff0c;应该如何解决这种情况呢&#xff1f; 答案与分析&#xff1a; C语言在编译的时候为了解决函数的多态问题&#xff0c;会将函数名和参数联合起…

OpenCV_11 轮廓检测:图像的轮廓+绘制轮廓+轮廓近似+边界矩形+椭圆拟合+直线拟合

1 图像的轮廓 轮廓可以简单认为成将连续的点&#xff08;连着边界&#xff09;连在一起的曲线&#xff0c;具有相同的颜色或者灰度。轮廓是图像目标的外部特征&#xff0c;这种特征对于我们进行图像分析&#xff0c;目标识别和理解等更深层次的处理都有很重要的意义。 轮廓提…

数据结构之平衡树:2-3查找树的介绍——16

平衡树&#xff08;AVL tree&#xff09; 引入 之前学习的树&#xff0c;都不是平衡的&#xff0c;查找时需要一个一个往内比较&#xff0c;一个结点只储存一个值&#xff0c;数据量存储较大&#xff0c;树的深度会非常的深&#xff0c;导致数据查询时效率会十分的低&#xf…

感谢CSDN管理员

感谢CSDN管理员&#xff0c;帮我重新找到了博客。 可恶的盗号者&#xff01;

OpenCV_12 图像分割:全阈值分割+自适应阈值分割+Otsu 阈值(大津法)+分水岭算法+GraphCut+GrabCut

1 图像分割 所谓图像分割指的是根据灰度、颜色、纹理和形状等特征把图像划分成若干互不交迭的区域&#xff0c;并使这些特征在同一区域内呈现出相似性&#xff0c;而在不同区域间呈现出明显的差异性。我们先对目前主要的图像分割方法做个概述&#xff0c;后面再对个别方法做详…

Android中的IPC机制

Android IPC简介 IPC是Inter-Process Communication的缩写&#xff0c;含义就是进程间通信或者跨进程通信&#xff0c;是指两个进程之间进行数据交换的过程。那么什么是进程&#xff0c;什么是线程&#xff0c;进程和线程是两个截然不同的概念。在操作系统中&#xff0c;线程是…

数据结构之平衡树:红黑树的介绍与Python代码实现——17

红黑树的介绍与Python代码实现 红黑树的介绍 红黑树(Red-Black Tree)是一种平衡二叉查找树&#xff0c;它是一种以比较简单的方式实现的2-3查找树 红黑树基于2-3查找树的表现 红链接:将两个2-结点连接起来构成一个3-结点 ;黑链接:则是2-3树中的普通链接。 红黑树的定义&a…

Python键鼠自动化函数

自动化之图形界面库pyautogui_jgdabc的博客-CSDN博客 https://blog.csdn.net/jgdabc/article/details/121952632

转:绝对干货--WordPress自定义查询wp_query所有参数详细注释

1 <?php2 /**3 * WordPress 查询综合参考4 * 编译&#xff1a;luetkemj - luetkemj.com5 *6 * 官方文档: http://codex.wordpress.org/Class_Reference/WP_Query7 * 源代码: http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/query.php8 */9 10 $args arra…