2007年7月29日星期日

操作系统内核的中神奇的代码

最近free download一个Linux kernel 2.6.22。由于工作的原因,大概有2年没有碰触Linux了,这些天又有生活无目标的感觉。花了2年时间才大概弄清楚WinCE整体的结构,基本能够理解微软的设计思想,也尝试看WinCE5的内核代码,但是有时候会很不爽,一个函数跟着跟着就丢失了。尤其是GWES,我最想知道的部分,完全没有代码。内核代码很多类似的部分,其中几乎都是C语言构成,C语言的组织基本架构就是函数,我们平时写应用程序时,也经常用函数,可是内核中的函数有时充满了玄机,有的是不归路,有的切换,有的是交错运行,对了,此时让我突然想起硬件文境切换代码,有空大家一定要看看绝对长见识。不过今天不看那些东西,我随便读,代码到哪里就说到哪里。看内核启动时,初始化终端的函数

void __init console_init(void)

{

initcall_t *call;

/* Setup the default TTY line discipline. */

(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

/*

* set up the console device so that later boot sequences can

* inform about problems etc..

*/

call = __con_initcall_start;

while (call <>

(*call)();

call++;

}

}

__con_initcall_start这个变量你就是找遍所有C和汇编代码你也找不到它的原型。它是出现在内核编译的链接阶段,是一个编程语言中的标记,或者说是一个地址,在这里也确实表现为地址,__con_initcall_start__con_initcall_end一起前后界定了了代码段中.con_initcall.init

#define console_initcall(fn) \

static initcall_t __initcall_##fn \

__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn

搞这个macro声明了很多已赋值的函数指针,如32CPU那么就占用4个字节,console_init就是循环运行这些函数指针多对应的函数。这个架构真是太好了,很多驱动程序只要用这个macro就可以声明自己,而内核初始化部分就无须直接关心有多少console驱动程序做这样的声明,靠着强大的编译器就可以帮助你了解到。还是GCCLD厉害,微软的编译器功能太少,灵活度不高(至少微软对外放出的编译器是这样,说不定他们内部有很高级的)。不过毕竟微软不希望你利用他们的操作系统再去开发别的系统。呵呵。

所以分析内核代码是一定要想象这段代码的运行环境,否则你很难理解作者到底要干什么。文境切换代码更是如此,经过schedule函数直接就到另外一个进程去了,很神奇。还有在SMP环境下,一个函数直接会分叉,编程同时在多个CPU运行。今天就看了这点东西,以后再遇到什么好玩的东西,再和大家分享。

没有评论: