- 浏览: 128787 次
- 性别:
- 来自: 北京
-
最新评论
-
yangtaoxf126.com:
public class SimpleJDBC {
publ ...
oracle的sys用户怎么通过jdbc连接
前言
宏定义__define_initcall(level,fn)对于内核的初始化很重要,他指示编译器在编译的时候,将一系列初始化函数的起始地址值按照一定的顺序放在一个section中。在内核初始化阶段,do_initcalls() 将按顺序从该section中以函数指针的形式取出这些函数的起始地址,来依次完成相应的初始化。由于内核某些部分的初始化需要依赖于其他某些部分的初始化的完成,因此这个顺序排列常常很重要。
下面将从__define_initcall(level,fn) 宏定义的代码分析入手,依次分析名称为initcall.init的section的结构,最后分析内核初始化函数do_initcalls()是如何利用宏定义__define_initcall(level,fn)及其相关的衍生的7个宏宏定义,来实现内核某些部分的顺序初始化的。
1、分析 __define_initcall(level,fn) 宏定义
1) 这个宏的定义位于inlclude\linux\init.h中:
#define __define_initcall(level,fn) \
static initcall_t __initcall_##fn \
__attribute__((__section__(".initcall" level ".init"))) \
= fn
其中 initcall_t 是个函数指针类型:
typedef int (*initcall_t)(void);
而属性 __attribute__((__section__())) 则表示把对象放在一个这个由括号中的名称所指代的section中。所以这个宏定义的的含义是:
1) 声明一个名称为__initcall_##fn的函数 指针(其中##表示替换连接,);
2) 将这个函数指针初始化为fn;
3) 编译的时候需要把这个函数指针变量放置到名称为 ".initcall" level ".init" 的section中(比如level="1",代表这个section的名称是 ".initcall1.init")。
2) 举例:__define_initcall(6, pci_init)
上述宏调用的含义是:
1) 声明一个函数指针__initcall_pic_init = pci_init; 且
2) 这个指针变量__initcall_pic_init 需要放置到名称为 .initcall6.init的section中( 其实质就是将 这个函数pic_init的首地址放置到了这个section中)。
3) 这个宏一般并不直接使用,而是被定义成下述其他更简单的7个衍生宏这些衍生宏宏的定义也位于 inlclude\linux\Init.h 中:
#define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)
因此通过宏 core_initcall() 来声明的函数指针,将放置到名称为.initcall1.init的section中,而通过宏 postcore_initcall() 来声明的函数指针,将放置到名称为.initcall2.init的section中,依次类推。
4) 举例:device_initcall(pci_init)
解释同上 1-2)。
2、和初始化调用有关section--initcall
.init被分成了7个子section
1) 他们依次是.initcall1.init、.initcall2.init、...、.initcall7.init
2) 按照先后顺序依次排列
3) 他们的定义在文档vmlinux.lds.S中
例如 对于i386+,在i386\kernel\vmlinux.lds.S中有:
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
而在makefile 中有 LDFLAGS_vmlinux += -T arch/$(ARCH)/kernel/vmlinux.lds.s
4) 在这7个section总的开始位置被标识为__initcall_start,而在结尾被标识为__initcall_end。
3、 内核初始化函数do_basic_setup():
do_initcalls() 将从.initcall.init中,也就是这7个section中依次取出任何的函数指针,并调用这些 函数指针所指向的函数,来完成内核的一些相关的初始化。这个函数的定义位于init\main.c中:
extern initcall_t __initcall_start, __initcall_end;
static void __init do_initcalls(void)
{
initcall_t *call;
....
for (call = &__initcall_start; call
假如您希望某个初始化函数在内核初始化阶段就被调用,那么您就应该使用宏__define_initcall(level,fn) 或 其7个衍生宏来把这个初始化函数fn的起始地址按照初始化的顺序放置到相关的section 中。 内核初始化时的do_initcalls()将从这个section中按顺序找到这些函数来执行。 假如您希望某个初始化函数在内核初始化阶段就被调用,那么您就应该使用宏__define_initcall(level,fn) 或 其7个衍生宏来
把这个初始化函数fn的起始地址按照初始化的顺序放置到相关的section 中。 内核初始化时的do_initcalls()将从这个section中按顺序找到这些函数来执行。
今天在做一个驱动的时候要用到另一个驱动(I2C)提供的API,在内核初始化时碰到了一个依赖问题。
我的驱动在I2C初始化之前就运行起来了,而这时I2C提供的API还处于不可用状态。查了很多资料,网上有人说任何使用module_init这个宏的驱动程式的起动顺序都是不确定的(我没有查到权威的资料)。
任何的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数指针,并在整个初始化完成后,释放整个init区段(包括.init.text,.initcall.init等)。
注意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,和1)中所述的这些函数本身在.init.text区段中的顺序无关。在 2.4内核中,这些函数指针的顺序也是和链接的顺序有关的,是不确定的。在2.6内核中,initcall.init区段又分成7个子区段,分别是
.initcall1.init
.initcall2.init
.initcall3.init
.initcall4.init
.initcall5.init
.initcall6.init
.initcall7.init
当需要把函数fn放到.initcall1.init区段时,只要声明core_initcall(fn);即可。
其他的各个区段的定义方法分别是:
core_initcall(fn) --->.initcall1.init
postcore_initcall(fn) --->.initcall2.init
arch_initcall(fn) --->.initcall3.init
subsys_initcall(fn) --->.initcall4.init
fs_initcall(fn) --->.initcall5.init
device_initcall(fn) --->.initcall6.init
late_initcall(fn) --->.initcall7.init
而和2.4兼容的initcall(fn)则等价于device_initcall(fn)。各个子区段之间的顺序是确定的,即先调用. initcall1.init中的函数指针,再调用.initcall2.init中的函数指针,等等。而在每个子区段中的函数指针的顺序是和链接顺序相关的,是不确定的。
在内核中,不同的init函数被放在不同的子区段中,因此也就决定了他们的调用顺序。这样也就解决了一些init函数之间必须确保一定的调用顺序的问题。按照include/linux/init.h文档所写的,我在驱动里偿试了这样两种方式:
__define_initcall("7", fn);
late_initcall(fn);
都能够把我的驱动调整到最后调用。实际上上面两个是一回事:
#define late_initcall(fn) __define_initcall("7", fn)
宏定义__define_initcall(level,fn)对于内核的初始化很重要,他指示编译器在编译的时候,将一系列初始化函数的起始地址值按照一定的顺序放在一个section中。在内核初始化阶段,do_initcalls() 将按顺序从该section中以函数指针的形式取出这些函数的起始地址,来依次完成相应的初始化。由于内核某些部分的初始化需要依赖于其他某些部分的初始化的完成,因此这个顺序排列常常很重要。
下面将从__define_initcall(level,fn) 宏定义的代码分析入手,依次分析名称为initcall.init的section的结构,最后分析内核初始化函数do_initcalls()是如何利用宏定义__define_initcall(level,fn)及其相关的衍生的7个宏宏定义,来实现内核某些部分的顺序初始化的。
1、分析 __define_initcall(level,fn) 宏定义
1) 这个宏的定义位于inlclude\linux\init.h中:
#define __define_initcall(level,fn) \
static initcall_t __initcall_##fn \
__attribute__((__section__(".initcall" level ".init"))) \
= fn
其中 initcall_t 是个函数指针类型:
typedef int (*initcall_t)(void);
而属性 __attribute__((__section__())) 则表示把对象放在一个这个由括号中的名称所指代的section中。所以这个宏定义的的含义是:
1) 声明一个名称为__initcall_##fn的函数 指针(其中##表示替换连接,);
2) 将这个函数指针初始化为fn;
3) 编译的时候需要把这个函数指针变量放置到名称为 ".initcall" level ".init" 的section中(比如level="1",代表这个section的名称是 ".initcall1.init")。
2) 举例:__define_initcall(6, pci_init)
上述宏调用的含义是:
1) 声明一个函数指针__initcall_pic_init = pci_init; 且
2) 这个指针变量__initcall_pic_init 需要放置到名称为 .initcall6.init的section中( 其实质就是将 这个函数pic_init的首地址放置到了这个section中)。
3) 这个宏一般并不直接使用,而是被定义成下述其他更简单的7个衍生宏这些衍生宏宏的定义也位于 inlclude\linux\Init.h 中:
#define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)
因此通过宏 core_initcall() 来声明的函数指针,将放置到名称为.initcall1.init的section中,而通过宏 postcore_initcall() 来声明的函数指针,将放置到名称为.initcall2.init的section中,依次类推。
4) 举例:device_initcall(pci_init)
解释同上 1-2)。
2、和初始化调用有关section--initcall
.init被分成了7个子section
1) 他们依次是.initcall1.init、.initcall2.init、...、.initcall7.init
2) 按照先后顺序依次排列
3) 他们的定义在文档vmlinux.lds.S中
例如 对于i386+,在i386\kernel\vmlinux.lds.S中有:
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
而在makefile 中有 LDFLAGS_vmlinux += -T arch/$(ARCH)/kernel/vmlinux.lds.s
4) 在这7个section总的开始位置被标识为__initcall_start,而在结尾被标识为__initcall_end。
3、 内核初始化函数do_basic_setup():
do_initcalls() 将从.initcall.init中,也就是这7个section中依次取出任何的函数指针,并调用这些 函数指针所指向的函数,来完成内核的一些相关的初始化。这个函数的定义位于init\main.c中:
extern initcall_t __initcall_start, __initcall_end;
static void __init do_initcalls(void)
{
initcall_t *call;
....
for (call = &__initcall_start; call
假如您希望某个初始化函数在内核初始化阶段就被调用,那么您就应该使用宏__define_initcall(level,fn) 或 其7个衍生宏来把这个初始化函数fn的起始地址按照初始化的顺序放置到相关的section 中。 内核初始化时的do_initcalls()将从这个section中按顺序找到这些函数来执行。 假如您希望某个初始化函数在内核初始化阶段就被调用,那么您就应该使用宏__define_initcall(level,fn) 或 其7个衍生宏来
把这个初始化函数fn的起始地址按照初始化的顺序放置到相关的section 中。 内核初始化时的do_initcalls()将从这个section中按顺序找到这些函数来执行。
今天在做一个驱动的时候要用到另一个驱动(I2C)提供的API,在内核初始化时碰到了一个依赖问题。
我的驱动在I2C初始化之前就运行起来了,而这时I2C提供的API还处于不可用状态。查了很多资料,网上有人说任何使用module_init这个宏的驱动程式的起动顺序都是不确定的(我没有查到权威的资料)。
任何的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数指针,并在整个初始化完成后,释放整个init区段(包括.init.text,.initcall.init等)。
注意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,和1)中所述的这些函数本身在.init.text区段中的顺序无关。在 2.4内核中,这些函数指针的顺序也是和链接的顺序有关的,是不确定的。在2.6内核中,initcall.init区段又分成7个子区段,分别是
.initcall1.init
.initcall2.init
.initcall3.init
.initcall4.init
.initcall5.init
.initcall6.init
.initcall7.init
当需要把函数fn放到.initcall1.init区段时,只要声明core_initcall(fn);即可。
其他的各个区段的定义方法分别是:
core_initcall(fn) --->.initcall1.init
postcore_initcall(fn) --->.initcall2.init
arch_initcall(fn) --->.initcall3.init
subsys_initcall(fn) --->.initcall4.init
fs_initcall(fn) --->.initcall5.init
device_initcall(fn) --->.initcall6.init
late_initcall(fn) --->.initcall7.init
而和2.4兼容的initcall(fn)则等价于device_initcall(fn)。各个子区段之间的顺序是确定的,即先调用. initcall1.init中的函数指针,再调用.initcall2.init中的函数指针,等等。而在每个子区段中的函数指针的顺序是和链接顺序相关的,是不确定的。
在内核中,不同的init函数被放在不同的子区段中,因此也就决定了他们的调用顺序。这样也就解决了一些init函数之间必须确保一定的调用顺序的问题。按照include/linux/init.h文档所写的,我在驱动里偿试了这样两种方式:
__define_initcall("7", fn);
late_initcall(fn);
都能够把我的驱动调整到最后调用。实际上上面两个是一回事:
#define late_initcall(fn) __define_initcall("7", fn)
发表评论
-
转载--Linux 2.6内核I/O端口资源管理
2010-11-02 15:39 854申明:本文章是对“Linux对I/O端口资源的管理”该文章进行 ... -
linux 2.6线程创建源码分析
2010-11-02 15:09 1133上章讲到线程,现在对线程创建的代码流程分析下。来一步一步揭开她 ... -
linux 2.6进程与线程
2010-11-02 15:09 12431 > 线程和进程的 ... -
linux中ELF加载过程分析
2010-10-19 11:16 1958linux中ELF加载过程分析 - 博青港湾-技术空间 - ... -
Linux设备模型 学习总结
2010-10-13 21:21 960看LDD3中设备模型一章,觉得思维有些混乱。这里从整体的角度来 ... -
linux软中断的实现
2010-10-13 21:12 1120中断服务程序往往都是在CPU关中断的条件下执行的,以避免中断 ... -
zImage / vmlinux / Image生成的流程图
2010-10-13 21:11 2447SRC_TREE :=./ HEADER_PATH ... -
执行程序时内存管理的情景
2010-10-13 21:07 1470do_execve ->open_exec->de ... -
Linux Kernel 2.6进程调度的分析(揭示了几乎所有2.6调度的东西)
2010-10-13 20:16 1921第一章 Kernel 2.4存在的 ... -
ibm developer blog
2010-10-10 10:05 888Linux slab 分配器剖析 http://www.ibm ... -
linux2.6.29 启动过程详细分析
2010-08-12 16:02 1374突然心血来潮,想自己写个模块,于是就把linux2.6.29的 ... -
Linux内存:内存管理的实质
2010-08-04 21:22 711<转 http://linux.chinaunix. ... -
container_of 解析
2010-07-29 22:50 986在学习Linux驱动的过程中,遇到一个宏叫做container ... -
高级IO操作——ioctl
2010-07-23 20:48 1464_IO, _IOR, _IOW, _IOWR 宏的用法与解析 ... -
主设备号、次设备号
2010-07-23 16:13 933主设备号、次设备号分 ... -
Linux在控制台下不同类型文件显示不同颜色
2010-07-20 23:47 2580# ~/.bashrc: executed by bash(1 ... -
linux 编译内核 选项出错 综合
2010-07-20 23:24 1015具体错误提示见最后面 ... -
ARM SDT下汇编到GNU汇编的转换
2010-07-16 08:52 897将ARM SDT下的汇编码移植到GCC for ARM编译器时 ... -
GNU ARM 汇编指令(转)
2010-07-16 08:50 1675第一部分 Linux下ARM汇编语法尽管在Linux下使用C或 ... -
arm 嵌入式LINUX启动过程
2010-07-11 00:44 3912一位大师级的人物写的,不看要后悔的哟!! ...
相关推荐
标题中的"object_envi_resize__define_IDl_"很可能是指一个使用IDL(Interactive Data Language)编写的ENVI(Environment for Visualizing Images)扩展程序,该程序专注于图像对象的重采样操作。ENVI是一款广泛...
动网格,DEFINE_CG_MOTION,DEFINE_GRID_MOTION,很好的模板
标题中的"Define_Grid_Motion.zip_DEFINE_GRID_MOTION_fluent udf_fluent变形_f" 提到了`Fluent`中的`Define Grid Motion`功能,这正是用来定义网格运动的一种方法,它允许用户自定义边界条件下的网格动态行为。...
标题中的"DEFINE_DPM_EROSION.rar_DEFINE DPM EROSION_DPM_UDF EROSION_fluent"指的是一款与 Fluent 模拟软件相关的用户定义函数(UDF),用于模拟颗粒动力学(DPM)过程中的侵蚀现象。Fluent 是一款广泛使用的计算...
为此,有两种常见的技术:`#ifndef _XXX_H_ #define _XXX_H_` 和 `#pragma once`。这两种方法都有其优势和局限性,下面将详细介绍它们的工作原理和差异。 首先,`#ifndef _XXX_H_ #define _XXX_H_` 是一种被称为...
《fsc_psconfig__define.rar_fsc_psconfig_defi_idl图像处理》是一个与IDL(Interactive Data Language)相关的图像处理程序。IDL是一种广泛应用于科学数据分析和可视化,尤其是天文学、地球科学以及医学成像领域的...
#define IDD_ABOUTBOX 100 #define IDR_MAINFRAME 128 #define IDR_SKYBLUTYPE 129 #define IDB_BITMAP1 130 #define IDB_BITMAP2 131 #define IDB_BITMAP3 132 #define IDB_BITMAP4 133 #define IDB_PIC1 136 #...
`DEFINE_CG_MOTION`和`DEFINE_GRID_MOTION`是UDF编程中用于定义网格运动的两个关键函数。它们是ANSYS Fluent内建的宏,用于在UDF中指定网格如何随时间变化。 1. `DEFINE_CG_MOTION`:这个宏主要用于定义中心点...
软件环境: vscode + platformio 接线针脚定义 ...#define TOUCH_XPT2046_MISO 13 #define TOUCH_XPT2046_MOSI 11 #define TOUCH_XPT2046_CS 17 #define TOUCH_XPT2046_INT 18 实时时钟 SDA 8 SCL 9
标题 "VIVUDF2_CG_MOTION_DEFINE_CG_MOTION_二维运动动网格_" 提供的信息表明,这个主题涉及到使用Fluent软件进行流体动力学(CFD)模拟时,利用CG_MOTION功能来定义二维物体的动态运动。描述中的 "fluent DEFINE_CG...
//#define LCD_CON5 (S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_HWSWP ) ] 替代: 复制代码 #elif defined(CONFIG_FB_S3C2410_T240320) #define LCD_...
#define cJSON_False 0 #define cJSON_True 1 #define cJSON_NULL 2 #define cJSON_Number 3 #define cJSON_String 4 #define cJSON_Array 5 #define cJSON_Object 6 #define cJSON_IsReference 256 #define cJSON...
#define IDM_ABOUTBOX 0x0010 #define IDD_ABOUTBOX 100 #define IDS_ABOUTBOX 101 #define IDD_TESTBMPCP_DIALOG 102 #define IDR_MAINFRAME 128 #define IDC_BUTTON1 1000 #define IDC_EDIT1 1001 #define IDC_...
#define GPIO_STEP_X_PORT GPIOB #define GPIO_STEP_Y_PORT GPIOB #define GPIO_STEP_Z_PORT GPIOB #define GPIO_STEP_A_PORT GPIOB #define GPIO_STEP_B_PORT GPIOB #define GPIO_STEP_C_PORT GPIOB #define ...
#define MAXLEN 201 #define LEN 1 #define SPEED1 50 #define SPEED2 100 #define SPEED3 200 #define FOOD1_S1 5 #define FOOD1_S2 10 #define FOOD1_S3 15 #define FOOD2_S1 10 #define FOOD2_S2 20 #define FOOD...
#define AFX_DQPLOT_H__0D536D37_5CF1_11D1_AED1_0060973A08A4__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // clPlot.h : header file // #define MAXLEGENDS 10 #define MAXSERIES...
fluent,UDF,DEFINE宏大全
`define OR1200_UPR_MP_BITS 5 `define OR1200_UPR_DUP_BITS 6 `define OR1200_UPR_PCUP_BITS 7 `define OR1200_UPR_PMP_BITS 8 `define OR1200_UPR_PICP_BITS 9 `define OR1200_UPR_TTP_BITS 10 `define OR...
#define SPACE 0x20 #define ESC 0x1b #define ANT_CHAR_EMPTY '+' #define ANT_CHAR_FOOD 153 #define HOME_CHAR 'H' #define FOOD_CHAR 'F' #define FOOD_CHAR2 'f' #define FOOD_HOME_COLOR 12 #define BLOCK_...