内核使用了大量不同的宏来标记具有不同作用的函数和数据结构。如宏__init、__devinit等。这些宏在include/linux/init.h头文件中定义。编译器通过这些宏可以把代码优化放到合适的内存位置,以减少内存占用和提高内核效率。

下面是一些常用的宏:

l  __init

标记内核启动时使用的初始化代码,内核启动完成后不再需要。以此标记的代码位于.init.text内存区域。

它的宏定义是这样的:

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

l  __exit

标记退出代码,如果驱动不是以模块存在的,则该用法无效。

l  __initdata

标记内核启动时使用的初始化数据结构,内核启动完成后不再需要。以此标记的代码位于.init.data内存区

域。

l  __devinit

用于标记:用于初始化设备的函数,例如:用于初始化的函数probe就是用此宏标识的。

l  __devexit

用于标记:设备卸载时被调用的函数。

l  __devexit_p

用于初始化由__devexit标记的函数的指针。

如果内核既支持模块也支持热拔插,则__devexit_p(fn)返回fn,否则返回NULL。

l  __devinitdata

标记初始化设备数据结构的函数。

l  __devexitdata与devinitdata 类似但与__devexit关联匹配

l  xxx_initcall,一系列的初始化代码,按降序优先级排列。

初始化代码的内存结构

_init_begin             ------------------

|  .init.text        | ----   __init

|-------------------|

|  .init.data        | ---- __initdata

_setup_start           |-------------------|

|  .init.setup      | ---- __setup_param

__initcall_start      |-------------------|

|  .initcall1.init  | ---- core_initcall

|-------------------|

|  .initcall2.init  | ---- postcore_initcall

|-------------------|

|  .initcall3.init  | ---- arch_initcall

|-------------------|

|  .initcall4.init  | ---- subsys_initcall

|-------------------|

|  .initcall5.init  | ---- fs_initcall

|-------------------|

|  .initcall6.init  | ---- device_initcall

|-------------------|

|  .initcall7.init  | ---- late_initcall

__initcall_end        |-------------------|

|                     |

|    ... ... ...    |

|                    |

__init_end              -------------------

初始化代码的特点是:

在系统启动运行,且一旦运行后马上退出内存,不再占用内存。

对于驱动程序模块来说,这些优化标记使用的情况如下:

通过module_init()module_exit()函数调用的函数就需要使用__init__exit宏来标记。

probe()remove()函数应该使用__devinit__devexit标记,且只能标记probe()remove()

l  如果remove()使用__devexit标记,则在设备驱动的数据结构中要用__devexit_p(remove)来引用remove()函数。

l  如果你不确定需不需要添加优化宏则不要随便添加。

上面谈到的内核初始化宏位于文件include/linux/init.h中:

#ifndef _LINUX_INIT_H

#define _LINUX_INIT_H

#include <linux/compiler.h>

/* These macros are used to mark some functions or

* initialized data (doesn't apply to uninitialized data)

* as `initialization' functions. The kernel can take this

* as hint that the function is used only during the initialization

* phase and free up used memory resources after

*

* Usage:

* For functions:

*

* You should add __init immediately before the function name, like:

*

* static void __init initme(int x, int y)

* {

*    extern int z; z = x * y;

* }

*

* If the function has a prototype somewhere, you can also add

* __init between closing brace of the prototype and semicolon:

*

* extern int initialize_foobar_device(int, int, int) __init;

*

* For initialized data:

* You should insert __initdata between the variable name and equal

* sign followed by value, e.g.:

*

* static int init_variable __initdata = 0;

* static const char linux_logo[] __initconst = { 0x32, 0x36, ... };

*

* Don't forget to initialize data not at file scope, i.e. within a function,

* as gcc otherwise puts the data into the bss section and not into the init

* section.

*

* Also note, that this data cannot be "const".

*/

/* These are for everybody (although not all archs will actually

discard it in modules) */

#define __init       __section(.init.text) __cold notrace

#define __initdata   __section(.init.data)

#define __initconst  __section(.init.rodata)

#define __exitdata   __section(.exit.data)

#define __exit_call  __used __section(.exitcall.exit)

/*

* modpost check for section mismatches during the kernel build.

* A section mismatch happens when there are references from a

* code or data section to an init section (both code or data).

* The init sections are (for most archs) discarded by the kernel

* when early init has completed so all such references are potential bugs.

* For exit sections the same issue exists.

*

* The following markers are used for the cases where the reference to

* the *init / *exit section (code or data) is valid and will teach

* modpost not to issue a warning.  Intended semantics is that a code or

* data tagged __ref* can reference code or data from init section without

* producing a warning (of course, no warning does not mean code is

* correct, so optimally document why the __ref is needed and why it's OK).

*

* The markers follow same syntax rules as __init / __initdata.

*/

#define __ref            __section(.ref.text) noinline

#define __refdata        __section(.ref.data)

#define __refconst       __section(.ref.rodata)

/* compatibility defines */

#define __init_refok     __ref

#define __initdata_refok __refdata

#define __exit_refok     __ref

#ifdef MODULE

#define __exitused

#else

#define __exitused  __used

#endif

#define __exit          __section(.exit.text) __exitused __cold notrace

/* Used for HOTPLUG */

#define __devinit        __section(.devinit.text) __cold notrace

#define __devinitdata    __section(.devinit.data)

#define __devinitconst   __section(.devinit.rodata)

#define __devexit        __section(.devexit.text) __exitused __cold notrace

#define __devexitdata    __section(.devexit.data)

#define __devexitconst   __section(.devexit.rodata)

/* Used for HOTPLUG_CPU */

#define __cpuinit        __section(.cpuinit.text) __cold notrace

#define __cpuinitdata    __section(.cpuinit.data)

#define __cpuinitconst   __section(.cpuinit.rodata)

#define __cpuexit        __section(.cpuexit.text) __exitused __cold notrace

#define __cpuexitdata    __section(.cpuexit.data)

#define __cpuexitconst   __section(.cpuexit.rodata)

/* Used for MEMORY_HOTPLUG */

#define __meminit        __section(.meminit.text) __cold notrace

#define __meminitdata    __section(.meminit.data)

#define __meminitconst   __section(.meminit.rodata)

#define __memexit        __section(.memexit.text) __exitused __cold notrace

#define __memexitdata    __section(.memexit.data)

#define __memexitconst   __section(.memexit.rodata)

/* For assembly routines */

#define __HEAD       .section   ".head.text","ax"

#define __INIT       .section   ".init.text","ax"

#define __FINIT      .previous

#define __INITDATA   .section   ".init.data","aw",%progbits

#define __INITRODATA .section   ".init.rodata","a",%progbits

#define __FINITDATA  .previous

#define __DEVINIT        .section   ".devinit.text", "ax"

#define __DEVINITDATA    .section   ".devinit.data", "aw"

#define __DEVINITRODATA  .section  ".devinit.rodata", "a"

#define __CPUINIT        .section   ".cpuinit.text", "ax"

#define __CPUINITDATA    .section   ".cpuinit.data", "aw"

#define __CPUINITRODATA  .section  ".cpuinit.rodata", "a"

#define __MEMINIT        .section   ".meminit.text", "ax"

#define __MEMINITDATA    .section   ".meminit.data", "aw"

#define __MEMINITRODATA  .section  ".meminit.rodata", "a"

/* silence warnings when references are OK */

#define __REF            .section       ".ref.text", "ax"

#define __REFDATA        .section       ".ref.data", "aw"

#define __REFCONST       .section       ".ref.rodata", "a"

#ifndef __ASSEMBLY__

/*

* Used for initialization calls..

*/

typedef int (*initcall_t)(void);

typedef void (*exitcall_t)(void);

extern initcall_t __con_initcall_start[], __con_initcall_end[];

extern initcall_t __security_initcall_start[], __security_initcall_end[];

/* Used for contructor calls. */

typedef void (*ctor_fn_t)(void);

/* Defined in init/main.c */

extern int do_one_initcall(initcall_t fn);

extern char __initdata boot_command_line[];

extern char *saved_command_line;

extern unsigned int reset_devices;

/* used by init/main.c */

void setup_arch(char **);

void prepare_namespace(void);

extern void (*late_time_init)(void);

extern int initcall_debug;

#endif

#ifndef MODULE

#ifndef __ASSEMBLY__

/* initcalls are now grouped by functionality into separate

* subsections. Ordering inside the subsections is determined

* by link order.

* For backwards compatibility, initcall() puts the call in

* the device init subsection.

*

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

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

*/

#define __define_initcall(level,fn,id) \

static initcall_t __initcall_##fn##id __used \

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

/*

* Early initcalls run before initializing SMP.

*

* Only for built-in code, not modules.

*/

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

/*

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

* initializes variables that couldn't be statically initialized.

*

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

*/

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

#define __initcall(fn) device_initcall(fn)

#define __exitcall(fn) \

static exitcall_t __exitcall_##fn __exit_call = fn

#define console_initcall(fn) \

static initcall_t __initcall_##fn \

__used __section(.con_initcall.init) = fn

#define security_initcall(fn) \

static initcall_t __initcall_##fn \

__used __section(.security_initcall.init) = fn

struct obs_kernel_param {

const char *str;

int (*setup_func)(char *);

int early;

};

/*

* Only for really core code.  See moduleparam.h for the normal way.

*

* Force the alignment so the compiler doesn't space elements of the

* obs_kernel_param "array" too far apart in .init.setup.

*/

#define __setup_param(str, unique_id, fn, early)        \

static const char __setup_str_##unique_id[] __initconst \

__aligned(1) = str; \

static struct obs_kernel_param __setup_##unique_id   \

__used __section(.init.setup)          \

__attribute__((aligned((sizeof(long)))))  \

= { __setup_str_##unique_id, fn, early }

#define __setup(str, fn)               \

__setup_param(str, fn, fn, 0)

/* NOTE: fn is as per module_param, not __setup!  Emits warning if fn

* returns non-zero. */

#define early_param(str, fn)                  \

__setup_param(str, fn, fn, 1)

/* Relies on boot_command_line being set */

void __init parse_early_param(void);

void __init parse_early_options(char *cmdline);

#endif /* __ASSEMBLY__ */

/**

* module_init() - driver initialization entry point

* @x: function to be run at kernel boot time or module insertion

*

* module_init() will either be called during do_initcalls() (if

* builtin) or at module insertion time (if a module).  There can only

* be one per module.

*/

#define module_init(x)   __initcall(x);

/**

* module_exit() - driver exit entry point

* @x: function to be run when driver is removed

*

* module_exit() will wrap the driver clean-up code

* with cleanup_module() when used with rmmod when

* the driver is a module.  If the driver is statically

* compiled into the kernel, module_exit() has no effect.

* There can only be one per module.

*/

#define module_exit(x)   __exitcall(x);

#else /* MODULE */

/* Don't use these in modules, but some people do... */

#define early_initcall(fn)      module_init(fn)

#define core_initcall(fn)       module_init(fn)

#define postcore_initcall(fn)      module_init(fn)

#define arch_initcall(fn)       module_init(fn)

#define subsys_initcall(fn)     module_init(fn)

#define fs_initcall(fn)         module_init(fn)

#define device_initcall(fn)     module_init(fn)

#define late_initcall(fn)       module_init(fn)

#define security_initcall(fn)      module_init(fn)

/* Each module must use one module_init(). */

#define module_init(initfn)               \

static inline initcall_t __inittest(void)     \

{ return initfn; }                 \

int init_module(void) __attribute__((alias(#initfn)));

/* This is only required if you want to be unloadable. */

#define module_exit(exitfn)               \

static inline exitcall_t __exittest(void)     \

{ return exitfn; }                 \

void cleanup_module(void) __attribute__((alias(#exitfn)));

#define __setup_param(str, unique_id, fn) /* nothing */

#define __setup(str, func)         /* nothing */

#endif

/* Data marked not to be saved by software suspend */

#define __nosavedata __section(.data..nosave)

/* This means "can be init if no module support, otherwise module load

may call it." */

#ifdef CONFIG_MODULES

#define __init_or_module

#define __initdata_or_module

#define __initconst_or_module

#define __INIT_OR_MODULE .text

#define __INITDATA_OR_MODULE    .data

#define __INITRODATA_OR_MODULE  .section ".rodata","a",%progbits

#else

#define __init_or_module __init

#define __initdata_or_module __initdata

#define __initconst_or_module __initconst

#define __INIT_OR_MODULE __INIT

#define __INITDATA_OR_MODULE __INITDATA

#define __INITRODATA_OR_MODULE __INITRODATA

#endif /*CONFIG_MODULES*/

/* Functions marked as __devexit may be discarded at kernel link time, depending

on config options.  Newer versions of binutils detect references from

retained sections to discarded sections and flag an error.  Pointers to

__devexit functions must use __devexit_p(function_name), the wrapper will

insert either the function_name or NULL, depending on the config options.

*/

#if defined(MODULE) || defined(CONFIG_HOTPLUG)

#define __devexit_p(x) x

#else

#define __devexit_p(x) NULL

#endif

#ifdef MODULE

#define __exit_p(x) x

#else

#define __exit_p(x) NULL

#endif

#endif /* _LINUX_INIT_H */

linux内核中经常用到的设备初始化宏的更多相关文章

  1. Linux内核中双向链表的经典实现

    概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核 ...

  2. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  3. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

  4. Linux内核中的GPIO系统之(3):pin controller driver代码分析

    一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...

  5. Linux内核中流量控制

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

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

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

  7. 【转】 Linux内核中读写文件数据的方法--不错

    原文网址:http://blog.csdn.net/tommy_wxie/article/details/8193954 Linux内核中读写文件数据的方法  有时候需要在Linuxkernel--大 ...

  8. Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质

    原文:Linux内核分析(六)----字符设备控制方法实现|揭秘系统调用本质 Linux内核分析(六) 昨天我们对字符设备进行了初步的了解,并且实现了简单的字符设备驱动,今天我们继续对字符设备的某些方 ...

  9. Linux内核分析(五)----字符设备驱动实现

    原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷, ...

随机推荐

  1. android之调用webservice 实现图片上传

    转:http://www.cnblogs.com/top5/archive/2012/02/16/2354517.html public void testUpload(){ try{ String ...

  2. HTML5 File API

    1.File API 一直以来,不能直接访问用户计算机中的文件都是web应用开发当中的一大障碍.File API的宗旨是为web开发人员提供一种安全的方式,以便在客户端访问用户计算机中的文件,并更好的 ...

  3. 列表字体css

    white-space: nowrap; text-overflow: ellipsis; -o-text-overflow: ellipsis; overflow: hidden;

  4. 使用Chrome DevTools的Timeline分析页面性能

    随着webpage可以承载的表现形式更加多样化,通过webpage来实现更多交互功能,构建web应用程序已经成为很多产品的首要选择.这种方式拥有非常明显的优势:跨平台.开发便捷.便于部署和维护等等,但 ...

  5. Swift(三.函数)

    一.swift中的函数分为以下几类吧 1>无参无返   2>无参有返 3>有参无返  4>有参有返  5>有参多返 二.看下面几个例子吧 1>无参无返 func a ...

  6. WEB架构师成长之路之三-架构师都要懂哪些知识

    Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...

  7. C语言中调用Lua

    C语言和Lua天生有两大隔阂: 一.C语言是静态数据类型,Lua是动态数据类型 二.C语言需要程序员管理内存,Lua自动管理内存 为了跨越世俗走到一起,肯定需要解决方案. 解决第一点看上去比较容易,C ...

  8. KVC - 键值编码

    [基本概念] 1.键值编码是一个用于间接访问对象属性的机制,使用该机制不需要调用存取方法和变量实例就可访问对象属性. 2.键值编码方法在OC非正式协议(类目)NSKeyValueCoding中被声明, ...

  9. Android使用SeekBar时动态显示进度且随SeekBar一起移动

    最近有做一个android项目,里面有使用到在播放视频时可以跳播,同时动态显示播放时间.类似于下图 的效果,我只是抽取其中的一部分做展示,刚接到这个事时也是在网上一通找,最后没找到!而且还碰到有些朋友 ...

  10. 【原创】如何构建MIPS交叉编译工具链

    运行环境:Ubuntu12.04PC提前安装库:flex,bison,libncureses5-dev,texinfo,这些库提前apt-get install.需要重新安装:gawk(先apt-ge ...