20169217《Linux内核原理与分析》第五周作业

   和往常一样,先总结分析实验。

   cd LinuxKernel/

 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

   内核启动后进入menu程序

  

   使用gdb跟踪调试内核:

   qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

  

    这里犯了一个错误,导致后续的实验没有顺利的进行。不过在后面进行了改正。

(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后

  

   这里我发现连接超时,这是我才发现之前的错误,并且进行了改正。

   接下来是运行到第一个断点start_kernel时的情形

  

   设置第二个断点rest_init,并且运行到第二个断点。

  

     这里我想吐槽一下实验里说的按“c”键运行到断点,在哪里键入c说的并不清楚,是在shell里还是在gdb里?当然尝试过后是在gdb里。

   下面我们来分析代码,

    start_kernel()的最后一条语句是rest_init(),我们知道start_kernel()是进行初始化,那么接下来就是rest_init()这个函数中产生了第一个用户态进程。

  

    我们可以看到第403行代码

  kernel_thread(kernel_init, NULL, CLONE_FS);

    产生了用户态进程,此进程也是linux启动以后的第一个用户态进程。

    用户态进程成功运行后,0号进程继续回到rest_init()中执行。

    总结一下 linux内核运行的过程:

   Linux一开始启动就通过start_kernel进行初始化,然后再到其最后一个函数调用rest_init()。在rest_init中,通过init_task产生pid=0的进程,即0号进程,它是内核状态下的进程,接着调用系统函数 kernel_thread 创建 1 号进程,即 init 进程,它是第一个用户态进程用户态进程运行成功后再通过 cpu_startup_entry 函数启动 0 号进程。

    第二部分补充一下通过看书和mooc的学习对于linux进程调度的总结。

    Linux的进程调度根据不同的版本也发生很大变化,不断优化,根据不同的优先级进行排队,linux的优先级的动态的,我们使用nice或者其他命令可以提高或者降低优先级。调度程序会根据进程的行为周期性的调整进程的优先级。较长时间未分配到CPU资源的进程会调高优先级,已经在CPU上运行较长时间的进程会降低优先级。我们还有很多系统调用可以用来设置优先级。我们在操作系统中介绍过很多调度算法,在linux中调度策略只是一个算法而已,并不能用来理解linux。对于理解整个系统比较关键的部分就是理解进程调度的时机,schedule用来控制进程的调度。那么schedule什么时候被调用,我们知道用户态进程无法直接调用schedule,因为schedule是一个内核函数,他又不是一个系统调用,我们只能间接的调用。间接的调用就是:

   中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule(),一般的用户态进程只能被动调用。

   内核线程是一个特殊的线程,只有内核态没有用户态,可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度。

   用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。

posted @ 2016-10-20 16:16  刘弘毅  阅读(305)  评论(1编辑  收藏  举报