源码分析报告——字符终端设备
字符终端设备的打开操作
当我们需要使用一个字符终端设备的时候,首先需要打开它。而打开这一动作,在下面通常是由一些守护进程所发起的,比如当我们在登录到一个虚终端的时候,通常是由一个进
程来打开这个虚终端(从 的的版本开始,开始改用另一个较小的程序来实现相同的功能) ,是被进程所发起的进程,它完成以下的操作:
. 打开行设备并设置它们的模式;
.打印出的提示符,并得到用户名;
.为用户发起一个进程为用户进行登录
()流程:
我们从程序调用函数打开一个终端设备开始。
() ("");
()
()
很简单,得到一个空闲,设置一些参数,然后调用():
(, )
()
() ;
先获得一个空闲结构;
填充这个结构;
调用获得设备文件的;
继续填充结构;
这之中调用了 >>() 来执行下层的打开操作,下面才真正涉及到终端的()
()
(* ,* )
、首先通过取得
;
>;
注:即先取得所指向的设备的设备号;再根据当前的终端类型生成新的主、从设备号;
、调用 ()函数得到结构。把它赋给>
(, );
()
1 / 6
;
;
、调用检查 >是否真正表示了内存中打开该的。大概是出于完整性的考虑。
、调用 >的 ()函数。
>(, );
具体说来,每一个不同的,有不同的执行相应操作的函数,详见附录。
、将赋给结构。
>;
>;
>>;
>>;
()
( ,**)
本函数包括主要的的操作。
本函数使用了一个来互斥操作。; 在函数的开始调用() 进入临界区在函数的结尾调用()
退出临界区。
为了实现干净操作,本函数先分配内存,再进行关键操作,若出现错误,则先到: 区,释放出
所有分配的内存,再退出。
现在讲述程序的操作流程。
、根据设备号得到设备的结构。
();
、进入临界区
();
、若该不是第一次打开,转到( ). 否则,继续。
>[];
();
、第一次打开的操作比较复杂。
主要为申请设置结构,值得注意的是 > []; 表明所有的开始都用相同的结构。而最终都调用的读写函数,体现了只是一个虚拟终端的思想。
、调用 >中的 ()函数。
、 >,计数。
、退出临界区
();
;
、返回。
()
这个函数在 >中被调用。
(*)
设置的底层读写参数(大多与读写有关)。如:读写缓冲,结构的参数。
>()
2 / 6
如前文所示: ( )在第四步会调用>( ),对于不同类型的来说,这里相应的>( )当然也会有所不
同,下面列举了一些对应于不同类型的不同操作,同时我们也看到在()中会调用 >() ;下面
是面向不同行设备的相应操作。
对应于不同的类型的>():
;
;
;
;
;
;
;
;
对应于不同类型的>();
如果是,则有;
;
若为则为:的初始化详见后面的说明。
;
;
如果是串行的设备则为:
;
;
在里面:
;
;
字符终端设备的写操作
程序中的两个重要数据结构
{
*(*)();
(*)(
*, );
(*)(
*);
(*)(
*, , , , );
(*)(
*, , , );
(*)(
*,
*, , , );
(*)(
*, );
(*)(
*, , , , );
(*)(
*, , , , , , );
(*)(
*);
3 / 6
(*)(
*, );
(*)(
*,
*);
(*)(
*,
*);
(*)(
*, );
(*)(
*);
(*)(
*);
(*)(
*, , , , , );
(*)(
*,
*, );
};
{
;**
;* , ... *
;
;
;
*;
} *[];
()的流程
我们从程序调用()开始。
调用 ()函数。
()
()
此函数中调用具体的() 函数。
(>);
>>();
(>);
()
(* ,* ,* ,)
首先从 >里面取出一个结构,得到相关的的信息,
此函数中调用 ()
(>,
, , ,
(*),
( ));
(>, , 最后调用 ()
注:大概考虑到一次不能写太多字符中将字符分批输出。
反复调用传来的函数:(, , , );
4 / 6
这个函数其实就是>,即 ()
()
(* ,* ,
* ,)
注:此函数先在的写等待队列上等待,等它被唤醒后,然后再进行写操作。而这一函数,
最后实际上是会调用>(, , , ); 而在此处在对应的控制台是时,>()对应的就是里的:
(* ,,*,)
而如果对应的是的话,那么>() 对应的应该是:()
(* ,,*,)
如果对应的是串行设备的话,那么>()对应的应该是:()
(* ,*,)
或者里面的 () ;
在此处,我们以到的输出的分析为重点:
()
里面直接调用:
(, , , );