这几天身体不太好,进展不快.有时候突然发现在拼命的读代码的间隙里,停一会想一想,收获会更大.特别是对于这种非常庞大的
系统来说.把握整体的意义尤其重要.随着对linux整体的拆解,我对于整个系统,已经不想开始是那么模糊.好像已经度过了那个极点.不过我也应做好准备,因为一但我对整个细节解读时,肯定也会有同样的经历.
( ~8 \- Q- R+ E" f& n' D! m. [[color=#FFFFFF']
5 m! e( X: b. w! l
9 Y' S' z% _: z整个linux内核之所以这样艰涩,难懂就在于它的整体性.想我们这样很少写万行以上
程序的人来说,它就好像一个庞大的肉球.让你不知道如何下嘴.不过一但咬破.就非常香美了.毕竟,读这么优秀的代码也是一种享受.
1 x0 [7 ] z( I! O* G- S9 O
[color=#FFFFFF']
u1 p0 r) S# G X" V( F7 s# H
4 U3 a( U8 G2 X$ W7 t! x2 |我个人认为linux的内核难在这几点:1,系统庞大,太多的变量,
结构,以及
typedef定义的东西不容易找到.2,作为
操作系统,它的函数调用时动态的,读不懂大量的makefile你根本就不知道这50M的东西是怎么组织起来的,况且,你绝对不可以像跟踪程序一样用debug走一下.3,庞大的
数据结构,可能是比较简单的运算变得不容易读.
* X# ~0 V; V+ ], Z: a[color=#FFFFFF']
. j7 L4 {2 J/ ?: P+ l5 ~: R% |! D+ G5 M* N* ~# j! ~
因此在读核的初级阶段.我们应该善于
想象,善于将不容易理解的部分用伪码的理解方式走过,当我们对大局把握好了,将整个结构拆解清楚了,在读不迟.况且,虽内核本身来说,它所涉及到的运算,结构.本质上和课本上的没有差别.(可惜我不是
计算机系毕业的).只不过是内容多了一些罢了.
7 _/ q: b8 c' b o比如说进程调度这一部分,说白了,就是在调用fork()的时候,就产生一task_strut
类型的指针,它包含进程调度所用到的一切
信息.然后将这个指针插到队列中去就行了,然后cpu一次总队类中取出指针,分配给他们
时间片.
- Z: d3 a# m3 p/ p$ q
而这个指针如何插入呢?说白了就是看它的weight,weight的计算方法,有根据进程类型的不同由不同的
算法(实时进程,内核进程,普通进程).好了,这样我们想一下%26lt;%26lt;数据结构中%26gt;%26gt;关于队列的操作,插入,删除,插到队头,置于队尾.再想一下,这些操作如何同操作系统的应用结合在一块.例如;好队进程正在运行,突然,由于一
硬件中断.产生一进程,它必须马上处理.系统应把它插入到队头.
- X# @0 t' h3 i1 w/ O好了.你可以读一下/usr./src/linux/kenrel/sched.c,不要过那么多全局变量,现在数据结构上走过去,如下面的代码:
8 J- B: n# C: [+ l2 L W' J, Z
[color=#FFFFFF']
( t2 ?5 G/ v7 Z; }/ }* u+ s! `0 i5 {5 V- c" H* j" n5 d# s$ j' E: `
" R, c( q* A8 T8 n2 v
staticinlinevoidmove_last_runqueue(structtask_struct*p)
7 ]5 X3 {- K9 q- ]$ ^' r/ B
{
9 w' T/ b* k) r0 z2 m8 A+ M# }
structtask_struct*next=p-%26gt;next_run;
2 b* }7 z' n. x) K" c# {5 Istructtask_struct*prev=p-%26gt;prev_run;
/ K# V$ n/ n$ O# M% O
1 M; T; W2 r) {# h/*removefromlist*/
0 b% n8 E& J6 J& Y" h
[color=#FFFFFF']
* |* i' {! j8 ?; c( _
5 X, s; |) u. A, I ]" Dnext-%26gt;prev_run=prev;
5 t6 P. G" X+ uprev-%26gt;next_run=next;
9 j- l; A7 {7 `8 _! B
/*addbacktolist*/
2 f% m+ t: j: O z
p-%26gt;next_run=%26;amp;init_task;
7 A' Z: C9 T! W" Hprev=init_task.prev_run;
( y- v% ^: j4 }
[color=#FFFFFF']
4 y$ C7 y% z2 `2 p2 d# d& i
4 Z M/ S) L' }! `& p7 ginit_task.prev_run=p;
( E' X5 T' n5 F+ Ip-%26gt;prev_run=prev;
' |3 n6 e( G6 ^& S' F$ xprev-%26gt;next_run=p;
, a( A$ n) V* i2 Y) P) B9 [3 P[color=#FFFFFF']
; Z% k! l. J$ M0 M; w' J4 n- y3 }, L, `/ [' C6 j( v" J4 ^
}
\. J U* F, _8 O3 `
1 x: ~( v' ]: b0 T" ^staticinlinevoidmove_first_runqueue(structtask_struct*p)
4 o: D* m$ y* K$ d& E{
2 J/ f$ ]8 s N5 R+ |
[color=#FFFFFF']
' r7 y/ d8 c1 ]- C' [! g
( `3 R0 Z; c8 s1 H& @1 [structtask_struct*next=p-%26gt;next_run;
6 Y% d* }; }, S* ^9 E0 J
structtask_struct*prev=p-%26gt;prev_run;
. \- j8 i7 L9 t) y) i[color=#FFFFFF']
2 L# G: h0 b" ~6 c* R) T8 c J
1 ?% M! P' d5 s- y) t# W' c
/ ?& p" A F5 F# b, O' x P& c1 F' `
[color=#FFFFFF']
( W' {( a1 F# ^( s6 R
4 `$ c/ r }+ I. _9 J r/*removefromlist*/
, K+ c7 Q: u8 q; Tnext-%26gt;prev_run=prev;
$ H. z% g( K; M4 H0 {[color=#FFFFFF']
; l$ l P$ Q# }- |, O- x+ d: o5 E; N
) L( \4 i. i* l0 t0 xprev-%26gt;next_run=next;
% i, J" s7 j' u, C. C8 D/*addbacktolist*/
+ q. o( H# y# ]p-%26gt;prev_run=%26;amp;init_task;
- R ]" q$ G8 I( B9 O5 `' F1 u
[color=#FFFFFF']
8 R+ I0 B( _7 T A( ~6 `5 I
; d) q i7 x3 X. @$ o% l3 m
next=init_task.next_run;
- C$ ]& o0 y( iinit_task.next_run=p;
8 g7 [' P4 C( Z3 Y$ R5 Wp-%26gt;next_run=next;
3 _ o4 \" m Z( j `6 e- i- n, w: h$ P0 Ynext-%26gt;prev_run=p;
1 a& H, S8 l( Q( U _
}
- f& u& J- R8 _, m
如果你还不懂,你可能要先,在c语言和数据结构上下一点功夫.其他的模块,我想也是大同小异,不过,也修补会这么简单.如
内存管理中用到了好多平衡二叉树的排序,遍历等等.但总的结构时不变的.只要可以通栏全局,在不开定义的情况下,可以读懂全局变量的意思(其实,猜个八九不成问题),看懂是不成问题的.起码我是信心十足.
3 p: b0 e2 H7 M* B1 F6 b% B& R我应该在熟悉一下,计算机专业的
软件基础课!!