实验五:用户进程管理
练习0:填写已有实验
使用meld
可以简单地将前几个lab的代码填入lab5中,但是要注意在这次实验中,部分代码需要做出修改,如下,主要是idt_init
、trap_dispatch
、alloc_proc
、do_fork
这四个函数
kern/trap/trap.c
中lab1的部分代码
/* LAB5 YOUR CODE */
//you should update your lab1 code (just add ONE or TWO lines of code), let user app to use syscall to get the service of ucore
//so you should setup the syscall interrupt gate in here
extern uintptr_t __vectors[];
for(int i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i++){
SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
}
SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER); //设置系统调用的中断门,特权级为用户级,则允许用户进程通过系统调用来完成不同的系统调用服务
lidt(&idt_pd);
...
/* LAB5 YOUR CODE */
/* you should upate you lab1 code (just add ONE or TWO lines of code):
* Every TICK_NUM cycle, you should set current process's current->need_resched = 1
*/
ticks++;
if(ticks % TICK_NUM == 0){
assert(current != NULL); //注意,LAB1中这里还有一行print_ticks(),必须去掉,否在在make grade中会由于spin和waitkill函数耗时过长导致这里print_ticks()输出的信息被当作错误处理
current->need_resched = 1; //每当时钟走过TICK_NUM次,就将当前进程切换掉(设置被需要被调度),意为时间片已用完
}
kern/process/proc.c
中lab4的部分代码
//LAB5 YOUR CODE : (update LAB4 steps)
/*
* below fields(add in LAB5) in proc_struct need to be initialized
* uint32_t wait_state; // waiting state
* struct proc_struct *cptr, *yptr, *optr; // relations between processes
*/
proc->wait_state = 0; //初始化等待状态为0
proc->cptr = proc->yptr = proc->optr = NULL; //相关进程设置为NULL,cptr为子线程children,yptr和optr为兄弟线程younger/older
...
//LAB5 YOUR CODE : (update LAB4 steps)
/* Some Functions
* set_links: set the relation links of process. ALSO SEE: remove_links: lean the relation links of process
* -------------------
* update step 1: set child proc's parent to current process, make sure current process's wait_state is 0
* update step 5: insert proc_struct into hash_list && proc_list, set the relation links of process
*/
proc->parent = current; //设置进程为当前进程的子进程
assert(current->wait_state == 0); //确保当前进程在等待
bool intr_flag; //锁的作用参考lab4实验报告
local_intr_save(intr_flag);
{
proc->pid = get_pid();
hash_proc(proc);
set_links(proc); //单独的计数不满足调度的要求,使用set_links来设置进程关系(父子/兄弟)并加入到链表中
}
local_intr_restore(intr_flag);
练习1:加载应用程序并执行
1、应用程序的组成和编译
由于文件系统尚未实现,在本实验中make
的最后一步通过一个ld
命令将应用程序的执行码在生成kernel时直接链接到kernel的末端,并且将程序的位置和大小记录在两个全局变量中,供内核后续通过全局变量加载并执行应用程序
2、虚拟地址空间
tools/user.ld
中记录了用户虚拟空间的执行入口虚拟地址,tools/kernel.ld
中记录了内核虚拟空间的起始入口虚拟地址,kern\mm\memlayout.h
中描述了虚拟地址空间的分配
SECTIONS {
/* Load programs at this address: "." means the current address */
. = 0x800020;
SECTIONS {
/* Load the kernel at this address: "." means the current address */
. = 0xC0100000;
/* *
* Virtual memory map: Permissions
* kernel/user
*
* 4G ------------------> +---------------------------------+
* | |
* | Empty Memory (*) |
* | |
* +---------------------------------+ 0xFB000000
* | Cur. Page Table (Kern, RW) | RW/-- PTSIZE
* VPT -----------------> +---------------------------------+ 0xFAC00000
* | Invalid Memory (*) | --/--
* KERNTOP -------------> +--------------------