今天在看内核中无线的实现时,发现一个调用 subsys_initcall(cfg80211_init);搜索一些资料:

subsys_initcall 的定义在 include/linux/init.h 中,定义如下:

#define core_initcall(fn)       __define_initcall(fn, 1)
#define core_initcall_sync(fn)    __define_initcall(fn, 1s)
#define postcore_initcall(fn)        __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn)       __define_initcall(fn, 3)
#define arch_initcall_sync(fn)      __define_initcall(fn, 3s)
#define subsys_initcall(fn)     __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)  __define_initcall(fn, 4s)
#define fs_initcall(fn)         __define_initcall(fn, 5)
#define fs_initcall_sync(fn)        __define_initcall(fn, 5s)
#define rootfs_initcall(fn)          __define_initcall(fn, rootfs)
#define device_initcall(fn)          __define_initcall(fn, 6)
#define device_initcall_sync(fn)  __define_initcall(fn, 6s)
#define late_initcall(fn)             __define_initcall(fn, 7)
#define late_initcall_sync(fn)     __define_initcall(fn, 7s)

查看宏定义 _define_initcall 定义在同一个文件中(include/linux/init.h)

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

定义了一个函数指针赋值的实现,    __initcall_##fn##id  函数的实现为  fn函数;编译的时候需要把这个函数指针变量放置到名称为 ".initcall" level ".init"的section中。

明确了__define_initcall的含义,就知道了是分别将这些初始化标号修饰的函数指针放到各自的section中的。

SECTION“.initcall”level”.init”被放入INIT_CALLS(include/asm-generic/vmlinux.lds.h)(内核3.10.14)

#define INIT_CALLS       \
  VMLINUX_SYMBOL(__initcall_start) = .;   \
  *(.initcallearly.init)     \
  INIT_CALLS_LEVEL(0)     \
  INIT_CALLS_LEVEL(1)     \
  INIT_CALLS_LEVEL(2)     \
  INIT_CALLS_LEVEL(3)     \
  INIT_CALLS_LEVEL(4)     \
  INIT_CALLS_LEVEL(5)     \
  INIT_CALLS_LEVEL(rootfs)    \
  INIT_CALLS_LEVEL(6)     \
  INIT_CALLS_LEVEL(7)     \
  VMLINUX_SYMBOL(__initcall_end) = .;

__initcall_start和__initcall_end以及INITCALLS中定义的SECTION都是在arch/xxx/kernel/vmlinux.lds.S中放在.init段的。

  1. SECTIONS
  2. {
  3. .init : {
  4. __initcall_start = .;
  5. INITCALLS
  6. __initcall_end = .;
  7. }
  8. }

而这些SECTION里的函数在初始化时被顺序执行(init内核线程->do_basic_setup()[main.c #778]->do_initcalls())。

程序(init/main.c文件do_initcalls()函数)如下,do_initcalls()把.initcallXX.init中的函数按顺序都执行一遍。

for (call = __early_initcall_end; call < __initcall_end; call++) 
        do_one_initcall(*call);

参考文档  :  http://blog.csdn.net/thl789/article/details/6581146#

内核中 subsys_initcall 以及初始化标号的更多相关文章

  1. Linux2.6 内核中结构体初始化(转载)

    转自:http://hnniyan123.blog.chinaunix.net/uid-29917301-id-4989879.html 在Linux2.6版本的内核中,我们经常可以看到下面的结构体的 ...

  2. 如何查看linux内核中驱动的初始化顺序?

    答:通过生成的System.map可以查看到,主要关注__initcall_<module_entry_function>_init<level>,如: __initcall_ ...

  3. 嵌入式C语言自我修养 02:Linux 内核驱动中的指定初始化

    2.1 什么是指定初始化 在标准 C 中,当我们定义并初始化一个数组时,常用方法如下: ] = {,,,,,,,,}; 按照这种固定的顺序,我们可以依次给 a[0] 和 a[8] 赋值.因为没有对 a ...

  4. linux内核中网络文件系统的注册初始化

    针对内核3.9 系统开启时,会使用init/main.c,然后再里面调用kernel_init(),在里面会再调用do_basic_setup(),调用do_initcalls(),调用do_one_ ...

  5. linux-3.2.36内核启动2-setup_arch中的内存初始化1(arm平台 分析高端内存和初始化memblock)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/17093307 上一篇微博留下了这几个函数,现在我们来分析它们         sanity_c ...

  6. Linux内核中流量控制

    linux内核中提供了流量控制的相关处理功能,相关代码在net/sched目录下:而应用层上的控制是通过iproute2软件包中的tc来实现, tc和sched的关系就好象iptables和netfi ...

  7. Linux内核中SPI/I2c子系统剖析

    Linux内核中,SPI和I2C两个子系统的软件架构是一致的,且Linux内核的驱动模型都以bus,driver,device三种抽象对象为基本元素构建起来.下文的分析将主要用这三种抽象对象的创建过程 ...

  8. 详解Linux2.6内核中基于platform机制的驱动模型 (经典)

    [摘要]本文以Linux 2.6.25 内核为例,分析了基于platform总线的驱动模型.首先介绍了Platform总线的基本概念,接着介绍了platform device和platform dri ...

  9. linux-2.6.26内核中ARM中断实现详解(转)

    转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJ ...

随机推荐

  1. C++ 虚函数表解析 继承

    C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父 ...

  2. centos6.5安装jdk(解压tar.gz)

    0.说明 下载jdk文件包jdk-7u79-linux-x64.tar.gz. 1.环境清理(系统自带的OpenJDK) 1.1 查看OpenJDK的安装包 $ rpm -qa |grep java ...

  3. springboot 读取 resource文件

    文件位置信息如图: import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import ...

  4. C++11并发——多线程std::mutex (二)

    https://www.cnblogs.com/haippy/p/3237213.html Mutex 又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 <mute ...

  5. img标签浏览器缓存图片问题

    问题:项目中用的img标签及其src属性,但是发现浏览器会缓存图片,这样每次如果修改了图片,再重新打开预览发现图片还是原来的. 原因:因为src后面的请求路径不变,所以浏览器就认为是同一个图片,就不会 ...

  6. go 基础(二)

    strings和strconv使用 1.strings使用 strings.HasPrefix(s string, prefix string) bool:判断字符串s是否以prefix开头. str ...

  7. 利用guava来实现本地的cache缓存

    guava是谷歌提供的工具类,功能强大,举个例子,我我想把数据存到本地,该咋办?我们想到的只有是全局的Map和session中.如果我们想实现这个容器的大小呢?时间呢?不好搞吧. guava就有这样的 ...

  8. jcaptcha和kaptcha验证码使用入门【转】

    jcaptcha和kaptcha验证码使用入门 一.jcaptcha验证码使用 jcaptcha使用默认样式生成的验证码比较难以识别,所以需要自定义验证码的样式,包括,背景色.背景大小.字体.字体大小 ...

  9. Bellman-Ford算法:POJ No.3169 Layout 差分约束

    #define _CRT_SECURE_NO_WARNINGS /* 4 2 1 1 3 10 2 4 20 2 3 3 */ #include <iostream> #include & ...

  10. fffmgg

    翻译: 一.GOALS 你应该学习: 基本概念 安装ffmpeg和工具 编码视频 应用过滤器 分析视频 二.要求 这些幻灯片ffmpeg,ffprobe和ffplay的安装一些示例视频,例如:Big ...