转自:http://blog.chinaunix.net/uid-12567959-id-161015.html

在内核代码里到处都能看到这个subsys_initcall(),而它到底是干什么的呢?让我们来揭开它的神秘面纱。

先来看一段代码:

---------------------------------------------------------------------

include/linux/init.h

174 /*

175  * Early initcalls run before initializing SMP.

176  *

177  * Only for built-in code, not modules.

178  */

179 #define early_initcall(fn)    __define_initcall("early",fn,early)

180

181 /*

182  * A "pure" initcall has no dependencies on anything else, and purely

183  * initializes variables that couldn't be statically initialized.

184  *

185  * This only exists for built-in code, not for modules.

186  */

187 #define pure_initcall(fn)              __define_initcall("",fn,0)

188

189 #define core_initcall(fn)             __define_initcall("1",fn,1)

190 #define core_initcall_sync(fn)      __define_initcall("1s",fn,1s)

191 #define postcore_initcall(fn)         __define_initcall("2",fn,2)

192 #define postcore_initcall_sync(fn)  __define_initcall("2s",fn,2s)

193 #define arch_initcall(fn)             __define_initcall("3",fn,3)

194 #define arch_initcall_sync(fn)      __define_initcall("3s",fn,3s)

195 #define subsys_initcall(fn)           __define_initcall("4",fn,4)

196 #define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)

197 #define fs_initcall(fn)               __define_initcall("5",fn,5)

198 #define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)

199 #define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)

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

201 #define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)

202 #define late_initcall(fn)             __define_initcall("7",fn,7)

203 #define late_initcall_sync(fn)      __define_initcall("7s",fn,7s)

---------------------------------------------------------------------

类似于subsys_initcall()还有很多,但它们都依赖于__define_initcall(),再来看__define_initcall()的定义:

---------------------------------------------------------------------

include/linux/init.h

131 typedef int (*initcall_t)(void);

165  *

166  * The `id' arg to __define_initcall() is needed so that multiple

167  * initcalls can point at the same handler without causing duplicate-symbol build errors.

168  */

169

170 #define __define_initcall(level,fn,id) \

171       static initcall_t __initcall_##fn##id __used \

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

173

---------------------------------------------------------------------

__define_initcall()宏只是定义一个initcall_t类型的静态变量,并且声明要把这个静态变量放在特定的段里而已。上面我们看到initcall_t即是指向一个无参数有int返回值的函数的指针。

许多的子系统都有自己的初始化函数,而这些初始化的函数又根据功能不同被分开在不同的子段里,子段的排列顺序则由链接决定。为了向后兼容,initcall()把调用,也就是一个个指向初始化函数的函数指针放进设备初始化子段里。

在各个平台的链接脚本文件arch/xxx/kernel/vmlinux.lds.S中,我们总能看到下面的语句:

INIT_CALLS

这个宏有如下的定义:

---------------------------------------------------------------------

include/asm-generic/vmlinux.lds.h

606 #define INIT_CALLS                                           \

607                 VMLINUX_SYMBOL(__initcall_start) = .;        \

608                 INITCALLS                                    \

609                 VMLINUX_SYMBOL(__initcall_end) = .;

---------------------------------------------------------------------

INIT_CALLS即是定义一个新的段,而定义段的字段的任务则由宏INITCALLS完成:

---------------------------------------------------------------------

include/asm-generic/vmlinux.lds.h

585 #define INITCALLS                                            \

586         *(.initcallearly.init)                               \

587         VMLINUX_SYMBOL(__early_initcall_end) = .;            \

588         *(.initcall0.init)                                   \

589         *(.initcall0s.init)                                  \

590         *(.initcall1.init)                                   \

591         *(.initcall1s.init)                                  \

592         *(.initcall2.init)                                   \

593         *(.initcall2s.init)                                  \

594         *(.initcall3.init)                                   \

595         *(.initcall3s.init)                                  \

596         *(.initcall4.init)                                   \

597         *(.initcall4s.init)                                  \

598         *(.initcall5.init)                                   \

599         *(.initcall5s.init)                                  \

600         *(.initcallrootfs.init)                              \

601         *(.initcall6.init)                                   \

602         *(.initcall6s.init)                                  \

603         *(.initcall7.init)                                   \

604         *(.initcall7s.init)

---------------------------------------------------------------------

而这些初始化函数又是在何时调用的呢?我们看到start_kernel()-> rest_init()-> kernel_init()-> do_basic_setup(void)-> do_initcalls(),而正是do_initcalls()处理了这些初始化函数,其定义为:

---------------------------------------------------------------------

init/main.c

765 extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

766

767 static void __init do_initcalls(void)

768 {

769         initcall_t *fn;

770

771         for (fn = __early_initcall_end; fn < __initcall_end; fn++)

772                 do_one_initcall(*fn);

773

774         /* Make sure there is no pending stuff from the initcall sequence */

775         flush_scheduled_work();

776 }

---------------------------------------------------------------------

do_initcalls()又调用do_one_initcall()函数类处理这些调用。

---------------------------------------------------------------------

init/main.c

715 static char msgbuf[64];

716 static struct boot_trace_call call;

717 static struct boot_trace_ret ret;

718

719 int do_one_initcall(initcall_t fn)

720 {

721      int count = preempt_count();

722      ktime_t calltime, delta, rettime;

723

724      if (initcall_debug) {

725         call.caller = task_pid_nr(current);

726         printk("calling  %pF @ %i\n", fn, call.caller);

727         calltime = ktime_get();

728         trace_boot_call(&call, fn);

729         enable_boot_trace();

730     }

731

732     ret.result = fn();

733

734     if (initcall_debug) {

735        disable_boot_trace();

736        rettime = ktime_get();

737        delta = ktime_sub(rettime, calltime);

738        ret.duration = (unsigned long long) ktime_to_ns(delta) >> 10;

739        trace_boot_ret(&ret, fn);

740        printk("initcall %pF returned %d after %Ld usecs\n", fn,

741        ret.result, ret.duration);

742     }

743

744     msgbuf[0] = 0;

745

746     if (ret.result && ret.result != -ENODEV && initcall_debug)

747        sprintf(msgbuf, "error code %d ", ret.result);

748

749     if (preempt_count() != count) {

750        strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));

751        preempt_count() = count;

752     }

753     if (irqs_disabled()) {

754        strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));

755        local_irq_enable();

756     }

757     if (msgbuf[0]) {

758        printk("initcall %pF returned with %s\n", fn, msgbuf);

759     }

760

761     return ret.result;

762 }

---------------------------------------------------------------------

神秘的subsys_initcall【转】相关推荐

  1. 仅需6步,教你轻易撕掉app开发框架的神秘面纱(1):确定框架方案

    遇到的问题   做游戏的时候用的是cocos2dx+lua,游戏开发自有它的一套框架机制.而现在公司主要项目要做android和iOS应用.本文主要介绍如何搭建简单易用的App框架. 如何解决   对 ...

  2. 了解黑客的关键工具---揭开Shellcode的神秘面纱

    2019独角兽企业重金招聘Python工程师标准>>> ref:  http://zhaisj.blog.51cto.com/219066/61428/ 了解黑客的关键工具---揭开 ...

  3. SQL性能优化没有那么神秘

    经常听说SQL Server最难的部分是性能优化,不禁让人感到优化这个工作很神秘,这种事情只有高手才能做.很早的时候我在网上看到一位高手写的博客,介绍了SQL优化的问题,从这些内容来看,优化并不都是一 ...

  4. 大数据背后的神秘定理:贝叶斯公式

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 引子 昨天下午趁着出去调研在湖滨银泰的星巴克做网易机器学习实习生岗 ...

  5. [Bzoj4408]神秘数(主席树)

    Description 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数. 例如S={1,1,1,4,13}, 1 = 1 2 = 1+1 3 = 1+1+1 4 = 4 5 = ...

  6. 神秘又强大的@SpringBootApplication注解

    作者:vivo 互联网服务器团队-Peng peng 一.前言 大部分的配置都可以用Java类+注解来代替,而在SpringBoot项目中见的最多的莫过于@SpringBootApplication注 ...

  7. 一个神秘URL酿大祸,差点让我背锅!

    神秘URL 我叫小风,是Windows帝国一个普通的上班族.上一回说到因为一个跨域请求,我差点丢了饭碗,好在有惊无险,我的职场历险记还在继续. "叮叮叮叮~~~~",闹钟又把我给吵 ...

  8. 飞书,助力字节跳动高效成长的神秘引擎

    字节跳动成立于2012年3月,在海内外推出了多款有影响力的产品,包括综合资讯类的今日头条.TopBuzz.News Republic,视频类的抖音.TikTok.西瓜视频.BuzzVideo.火山小视 ...

  9. 200 switching to ascii mode_王者荣耀:小伙200买V8号,146款皮肤还有1神秘道具,一封邮件哭了...

    阅读本文前,请您先点击上面蓝色字体"关注",这样您就可以继续免费收到最新文章了.每天都有分享,完全是免费订阅,请放心关注.                              ...

最新文章

  1. 从零开始_学_数据结构(六)——排序(冒泡、插入、希尔、简单选择、归并、快速)...
  2. apache+jk+tomcat集群+session同步
  3. .htaccess 后门
  4. 使用 System.Net.Http.Json 简化 HttpClient 的使用
  5. .NET Core开发日志——OData
  6. nyoj 题目5 Binary String Matching
  7. spring security oauth2 资源服务器配置
  8. 异常记录---Error creating bean with name ‘sqlSessionFactory‘
  9. NASA-TLX (Task Load Index)量表学习总结
  10. 数据库可视化工具(SQLyog安装教程)
  11. 安装PostgreSQL客户端
  12. 2019/7/31随笔
  13. POJ-2184 Cow Exhibition---01背包变形(负数偏移)
  14. 【教3妹学java】JVM调优有哪些工具?
  15. 用STM32F103C8芯片做流水灯
  16. Android 富文本编辑器 图文混排
  17. Python数据分析项目-共享单车骑行数据分析
  18. 中国科学院计算机博士好考吗,中科院考博难不难?亲身经历告诉你答案…
  19. 电脑上不去网的6点原因
  20. yolact模型DCNv2模块编译错误解决方法

热门文章

  1. linux 安装ubuntu-16.04-server-amd64
  2. python二十九:__name__
  3. centos7安装pyenv
  4. kubernetes 动态扩容pv
  5. Python面向对象程序设计之抽象工厂模式之二-一个更加pythonic的抽象工厂
  6. 【微职位公开课】老学长自述:如何成为年薪50W的技术工程师
  7. Binder机制(一)
  8. mysql主从库配置方法
  9. oracle实例无法启动也无法关闭
  10. 单臂路由实验-VTP