前边的 4 篇博文将进程 1 的创建以及执行阐述完毕,接下来几篇博文开始阐述进程 2 的创建及执行。
几个容易混淆的变量
在上篇博文中就碰到了这几个变量:
1 | // fs/super.c ---------------------------------- |
这四者的关系可用图表示如下:
打开标准输入设备文件
对于 Linux 而言,一切皆文件,打开设备文件跟打开一般文件的过程是一样的。在上一博文 Linux 内核学习笔记:进程 1 的创建及执行(第 4 部分)“文件目录项结构”部分,我们举了一个打开 /usr/bin/vi 文件的例子。打开设备文件的流程跟那个例子一样,不过那个例子比较简要,省略了好多细节,所以接下来就把这些细节都详细叙述一下。
在上一博文 Linux 内核学习笔记:进程 1 的创建及执行(第 4 部分)我们说到,进程 1 已经返回到 init 函数执行:
1 | // init/main.c --------------------------------- |
调用 sys_open
open 函数定义如下:
1 | // lib/open.c ---------------------------------- |
上述代码表明,open 函数实际还是通过 int 0x80 软中断调用系统调用总入口 _system_call,再经 call _sys_call_table(,%eax,4) 调用具体的服务程序 sys_open:
1 | // fs/open.c ----------------------------------- |
调用 open_namei
通过 open_namei 函数,能够最终获得标准输入设备 tty0 的 i 节点。open_namei 函数定义如下:
1 | // fs/namei.c ---------------------------------- |
调用 dir_namei
dir_namei 函数定义如下:
1 | // fs/namei.c ---------------------------------- |
find_entry
函数在 get_dir 函数中被调用,其定义如下:
1 | // fs/namei.c ---------------------------------- |
返回 open_namei
dir_namei 函数执行完毕就返回 open_namei 函数:
1 | // fs/namei.c ---------------------------------- |
返回 sys_open
open_namei 函数返回后,跳转到 sys_open 函数执行:
1 | // fs/open.c ----------------------------------- |
打开标准输出、标准错误输出设备文件
打开标准输入设备文件完毕后,跳转到 init 函数继续执行,打开标准输出、标准错误输出设备文件:
1 | // init/main.c --------------------------------- |
跟 open 函数类似,dup 通过系统调用总入口 _system_call 调用具体的服务程序 sys_dup:
1 | // fs/fcntl.c ---------------------------------- |
注:在 Linux 中,我们经常称文件句柄为文件描述符,其大小表示进程描述符中 file[20] 的下标。