• linux源码分析(一)


    前置:这里使用的linux版本是4.8,x86体系。

    其实linux的内核启动的入口文件还是非常好找的,init/main.c。

    static 和 extern

    首先理解的是static和extern的区别:

    static int kernel_init(void *);
    
    extern void init_IRQ(void);
    extern void fork_init(void);
    extern void radix_tree_init(void);
    

    这个代码说的是kernel_init函数的定义在这个文件中,extern说明init_IRQ函数的定义在其他文件中。
    这三个extern分别是对中断的初始化,对fork功能的初始化,对基数树的初始化。不过具体不知道为什么有的函数以init_xxx为风格,有的又以xxx_init的风格来做。

    main的第一行看到了这么个语句

    #define DEBUG
    

    感觉有点奇怪,原来还有#define <宏名> 而没有定义具体的值。其实这个可以当作已经有定义,且定义了空串来理解。
    http://bbs.csdn.net/topics/390960776?page=1

    继续往下面看,还会看到

    bool early_boot_irqs_disabled __read_mostly;

    这里最后的__read_mostly 是一个宏,它标记了前面这个变量是很经常被读取的。那么做了标记有什么用呢?

    如果在有缓存的平台上,它就能把这个变量存放到cache中,以保证后续读取的速度。这个宏定义在 arch/arm/include/asm/cache.h

    #define __read_mostly __attribute__((__section__(".data..read_mostly")))
    

    这里的意思是将这个数据结构链接进data.read_mostly段。

    EXPORT_SYMBOL

    EXPORT_SYMBOL(system_state);

    这个是和extern一起使用的,表示system_state这个方法在这个模块中定义了,提供给其他模块使用。

    在其他模块中,只需要使用extern 就可以使用这个方法。

    这里就涉及到模块的概念。

    模块是linux内核对外提供的一个插件机制,由于linux是单内核,这个单内核是相对微内核来说的。所以linux很大可能会非常庞大,这个模块机制就是对单内核的一种补充,把一些功能放给内核模块开发。比如像上面的那个代码,就是对内核提供了system_state的函数接口。

    __initdata

    下面代码:

    char __initdata boot_command_line[COMMAND_LINE_SIZE];

    这里的__initdata也是一个宏,定义在include/linux/init.h

    #define __init        __section(.init.text) __cold notrace
    #define __initdata    __section(.init.data)
    #define __initconst    __constsection(.init.rodata)
    #define __exitdata    __section(.exit.data)
    #define __exit_call    __used __section(.exitcall.exit)
    

    同上面__read_mostly一样,是用来把这个变量绑定在某个区里面。

    http://blog.csdn.net/beatbean/article/details/8448623

    这个图就说明了什么是__section。它的功能有点像是全局变量,只是这个全局变量是对汇编这个层次的表达,某个变量,我固定在某个内存段里面。这么做其实还有一个好处,段也是一种分类,比如这个段存储的是init函数的变量,那么等初始化结束之后,我把这个段的内存直接释放。里面的变量也一次性消除了。

    EXPORT_SYMBOL_GPL

    下面看到一个很奇怪的方法

    EXPORT_SYMBOL_GPL(static_key_initialized);

    这个和之前的EXPORT_SYMBOL不一样,多了一个GPL后缀。

    由于模块很有可能是第三方(非linux内核组成员)开发的。那么有人希望自己开发的模块是闭源的。它就会在自己开发的模块里面使用

    MODULE_LICENSE("Proprietary")

    来标记这个模块是闭源的。相对的,如果你的模块遵循GPL这个开源许可证规则,那么则增加下面的:

    MODULE_LICENSE("GPL");

    好了,linux对这两种许可证行为的模块开放的接口并不相同,本节的这个函数就是说明这个方法只对GPL的模块开放。

    http://www.ruanyifeng.com/blog/2010/02/why_gpl_is_a_better_choice.html

    __setup 和 early_param

    unsigned int reset_devices;
    EXPORT_SYMBOL(reset_devices);

    static int __init set_reset_devices(char *str)
    {
    reset_devices = 1;
    return 1;
    }

    __setup("reset_devices", set_reset_devices);

    这段代码,首先需要理解__setup,这个函数就理解为:启动时候如果有接收reset_devices参数,那么就调用set_reset_devices方法。而详细看了下set_reset_devices方法,里面只是把reset_devices变量设置为1,但是呢,这个reset_devices变量又是一个给所有模块使用的变量。

    所以这段代码能达到的功能是只要启动参数有包含reset_device,通过设置reset_devices通知给所有模块。

    与__setup相对应的还有一个叫做early_param。这两个宏函数的功能一样,区别就在于early_param定义的参数比__setup更早。

    http://www.linuxde.net/2013/02/12446.html

  • 相关阅读:
    【转载】Android应用框架及常用工具类总结
    【Android】Android开发规范的一点小体会
    【Android】解决Android的ListView控件滚动时背景变黑
    【Android】侧边栏SlidingMenu
    【Android】解决RadioButton+FragmentPagerAdapter+Fragment切换页面数据加载的问题
    【Android】ListView动态视图显示不全
    Android编码规范
    【Android】两个日期相差几天和两个日期比较大小
    Linux基础之快照克隆、Xshell优化、Linux历史
    Android APP打包时,出错:"XXX" is not translated in "af" (Afrikaans), "am" (Amharic)
  • 原文地址:https://www.cnblogs.com/yjf512/p/5992038.html
Copyright © 2020-2023  润新知