一.mykernel实验指导(操作系统是如何工作的)
使用实验楼的虚拟机打开shell
然后 cd mykernel
可以看到 qemu 窗口输出的内容的代码 mymain.c
和 myinterrupt.c
内核不停的执行my_start_kernel(),每隔一段时间被my_timer_handler()中断,然后执行一条打印语句:
printk(KERN_NOTICE “ >>>>>>>>>>>>>>>>>my_timer_handler here<<<<<<<<<<<<<<<<<< ”)。
二. 完成一个简单的时间片轮转多道程序内核代码
2.1.打开mykernel中的mymain.c文件:
根据https://github.com/mengning/mykernel上的mypcb.h、mymain.c、myinterrupt.c对kernel中的代码进行修改
修改代码后重新进行make编译,结果如下:
三. mykernel内核源代码分析
3.1 myinterrupt.c
3.2 mymain.c
3.3 mypcb.h
五. 分析进程的启动和进程的切换机制
内核启动__init my_start_kernel(void)
,创建了4个进程,分别是0,1,2,3号,设置0号为运行态,其它3个进程为未运行态。0号进程的入口都被初始化为task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process
;即指向my_process()
。
0号进程的栈顶被初始化为 task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];
之后的进程也都是根据0号进程复制得到,所以它们的起始入口也是my_process()
,初始栈顶也是指向了自己的stack[KERNEL_STACK_SIZE-1]
;my_current_task = &task[pid]
;将当前进程设置为0号进程。然后从0号进程开始运行。“movl %1,%%esp
”
将0号进程的栈顶放入esp寄存器。“pushl %1
” /* push ebp */
当前esp指向了stack数组的末尾,也就是栈顶,由于栈是空的,故有esp==ebp
。“pushl %0
" /* push task[pid].thread.ip */
“ret
” /* pop task[pid].thread.ip to eip */
这里是切换到0号进程的入口地址开始执行。
切换到0号进程后,0号进程不断执行my_process()
。之后,my_timer_handler()
被内核调用,触发中断,my_need_sched = 1
;将全局变量my_need_sched
设置为了1。在程序当中,在0号进程执行到了if(my_need_sched == 1
)语句时就会进入这个if条件分支中,执行my_schedule()
;执行进程调度。
0号进程的next指针指向的是1号进程,所以在my_schedule()
中的next指针指向了1号进程,prev指针指向了0号进程。
由于1号进程还没被运行过,所以会执行else条件分支:next->state = 0;//将1号进程设置为运行状态
。my_current_task = next
;//当前进程切换为1号进程
-
“movl %2,%%esp ” /* restore esp */
-
“movl %2,%%ebp ” /* restore ebp */
进程的切换情况大致上就是如上所述。