FreeBSD kernel是一个膨大的系统, 对于这样一个大系统, 里面往往包含了大量的子系统和模块,当系统初始化时这些模块就需要初始化, 按照通常的思路,这些初始化过程必须在某处被显式地调用,这样一来,当你新增某个模块,你必须再修改那个系统初始化的地方来调用这个新增模块的初始化过程, 而且由于ANSI C语言的限制,调用某个函数最好先声明,这样当系统的初始化过程开始增加时, 那个调用初始化过程的文件开始大量包含那些本来不相关的头文件, 偶合度就增加了, 这是一种不好的设计.
FreeBSD为了应付这种情况, 使用一种叫做SYSINIT的机制. 我们知道FreeBSD使用一种叫做 ELF的二进制目标执行文件格式. 这种文件格式允许文件内部组织成结构化的方式, 文件内部可以由不同的组成部分(section), FreeBSD正是利用了这种机制.
FreeBSD使用GNU GCC作为其C语言编译器, 这种编译器允许在C源程序中嵌入汇编语言代码, FreeBSD通过在C源程序中加入汇编指令来在目标文件中增加额外的section, 在文件 /sys/sys/linker_set.h中定义如下:
#ifdef __alpha__
#define MAKE_SET(set, sym) static void const * const __set_##set##_sym_##sym = &sym; __asm(".align 3"); __asm(".section .set." #set ",\"aw\""); __asm(".quad " #sym); __asm(".previous")
#else
#define MAKE_SET(set, sym)
#define MAKE_SET(set, sym) static void const * const __set_##set##_sym_##sym = &sym; __asm(".section .set." #set ",\"aw\""); __asm(".long " #sym); __asm(".previous")
#endif
#define TEXT_SET(set, sym) MAKE_SET(set, sym)
#define DATA_SET(set, sym) MAKE_SET(set, sym)
程序一旦在某处调用DATA_SET宏指令, 就会将相应的汇编符号加入到目标文件. 例如: int myint;DATA_SET(myset, myint);
这两句话将导致在目标文件中创建一个myset section, 并且myint的地址将被放入这个 section中.
系统的初始化必须按严格的顺序进行, 为此FreeBSD定义了很多子系统的顺序号, 这些顺序连同SYSINIT的许多相关定义在/sys/sys/kernel.h头文件中:
enum sysinit_sub_id {
SI_SUB_DUMMY = 0x0000000, /* not executed; for linker*/
SI_SUB_DONE = 0x0000001, /* processed*/
SI_SUB_CONSOLE = 0x0800000, /* console*/
SI_SUB_COPYRIGHT = 0x0800001, /* first use of console*/
SI_SUB_TUNABLES = 0x0700000, /* establish tunable values */
SI_SUB_VM = 0x1000000, /* virtual memory system init*/
SI_SUB_KMEM = 0x1800000, /* kernel memory*/
SI_SUB_KVM_RSRC = 0x1A00000, /* kvm operational limits*/
SI_SUB_CPU = 0x1e00000, /* CPU resource(s)*/
SI_SUB_KLD = 0x1f00000, /* KLD and module setup */
SI_SUB_INTRINSIC = 0x2000000, /* proc 0*/
SI_SUB_VM_CONF = 0x2100000, /* config VM, set limits*/
SI_SUB_RUN_QUEUE = 0x2200000, /* the run queue*/
SI_SUB_CREATE_INIT = 0x2300000, /* create the init process */
SI_SUB_DRIVERS = 0x2400000, /* Let Drivers initialize */
SI_SUB_CONFIGURE = 0x3800000, /* Configure devices */
SI_SUB_VFS = 0x4000000, /* virtual file system*/
SI_SUB_CLOCKS = 0x4800000, /* real time and stat clocks*/
SI_SUB_MBUF = 0x5000000, /* mbufs*/
SI_SUB_CLIST = 0x5800000, /* clists*/
SI_SUB_SYSV_SHM = 0x6400000, /* System V shared memory*/
SI_SUB_SYSV_SEM = 0x6800000, /* System V semaphores*/
SI_SUB_SYSV_MSG = 0x6C00000, /* System V message queues*/
SI_SUB_P1003_1B = 0x6E00000, /* P1003.1B realtime */
SI_SUB_PSEUDO = 0x7000000, /* pseudo devices*/
SI_SUB_EXEC = 0x7400000, /* execve() handlers */
SI_SUB_PROTO_BEGIN = 0x8000000, /* XXX: set splimp (kludge)*/
...
};
子系统内还有顺序号:
enum sysinit_elem_order {
SI_ORDER_FIRST