在上了Linux内核这门课后,我对Linux内核开始有了初步的了解,关于Linux内核,我觉得最重要的部分还是进程的创建以及切换,这是整个内核的核心部分。以下是一些我在学习Linux内核过程中的总结:

1、计算机是如何解读高级语言的

2、操作系统是怎么进行任务操作的

3、Linux内核的启动过程

4、系统调用的工作机制

5、系统调用system_call的处理过程

6、Linux系统是如何创建一个新进程的

7、Linux内核如何装载和启动一个可执行程序

8、Linux进程调度时机和进程切换

纵观整个过程,最让我觉得难学的是操作系统是怎么进行任务操作的以及进程的调度时机和切换。有一点始终不是很明白,就是这段代码 

"movl $1f,%1\n\t"       /* save eip */

为何每次将当前进程的eip保存为$1f,那样每次任务切换回来时都会从1f开始,如果此时出现嵌套的话会不会引起紊乱等等。而关于进程之间的切换则需要内核堆栈的配合才能完成,堆栈是整个多任务运行的基础,中断的实现也是依靠堆栈实现的,所以堆栈是计算机多任务运行的核心,学习好堆栈的运行机制是学习Linux内核的基础。

对于进程的创建,我是这么理解的,先是有start_kernel这个函数通过init_task创建了0号进程,再由函数kernel_thread通过变量kernel_init和kthreadd又生成了1号和2号进程,而1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先,继而可以创建更多的进程了。

而对于系统调用,我任务系统调用首先需要通过中断向量与指令int $0x80匹配起来进入到内核态,再由内核态中以system_call为起点的一段汇编代码进行系统调用,其中需要用到系统调用号,然后进入系统调用函数sys_xyz(),系统调用完成后会查看有无其他挂起的任务,有就转入syscall_exit_work,没有就返回系统调用。

而关于Linux内核是怎么创建进程的,我的总结是Linux系统创建一个新进程的全过程,创建一个新进程需要通过内核调用sys_clone来完成,大体的过程便是先对父进程的数据和环境进行复制,然后修改新进程的一些属性,比如pid号等,之后通过do_fork函数和ret_from_fork函数完成对新进程的创建以及运行。但是进程又是怎么装载的,首先是通过sys_execve将函数的命令行参数和环境变量传递到内核堆栈中去,再由load_elf_binary将二进制文件加载到内核中去,再通过start_thread修改内核堆栈,创建新堆栈,然后将命令行参数和环境变量拷贝到新程序堆栈中,再进行任务调度,运行新程序。而新程序的起始入口为elf_entry。

关于进程的切换,我的理解是内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;而用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。

系统通过调用schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换。
实验总结:
学习完这个课程之后,我觉得最大的收获就是我了解到了Linux内核强大的工作机制以及它对进程的管理,但是也有部分的遗憾,就是关于任务切换的某些细节不是很了解。但是因为这门课,我对Linux内核产生了浓厚的兴趣,我希望在以后的学习中能更加深入的去了解Linux内核,包括那些我还不是很清楚的细节。
  叶涛
 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

Logo

更多推荐