ucore操作系统实验lab4 -- 内核线程管理
来源:互联网 发布:linux 根目录清理 编辑:程序博客网 时间:2024/06/06 02:25
练习一:分配并初始化一个进程控制块(需要编码)
alloc_proc函数(位于kern/process/proc.c中)负责分配并返回一个新的struct proc_struct结构,用于存储新建立的内核线程的管理信息。ucore需要对这个结构进行最基本的初始化,完成这个初始化过程。
【提示】在alloc_proc函数的实现中,需要初始化的proc_struct结构中的成员变量至少包括:state/pid/runs/kstack/need_resched/parent/mm/context/tf/cr3/flags/name。
请说明proc_struct中struct context context和struct trapframe *tf成员变量含义和在本实验中的作用是啥?(提示通过看代码和编程调试可以判断出来)
1、实现:
static struct proc_struct *alloc_proc(void) { struct proc_struct *proc = kmalloc(sizeof(struct proc_struct)); if (proc != NULL) { //LAB4:EXERCISE1 YOUR CODE /* * below fields in proc_struct need to be initialized * enum proc_state state; // Process state * int pid; // Process ID * int runs; // the running times of Proces * uintptr_t kstack; // Process kernel stack * volatile bool need_resched; // bool value: need to be rescheduled to release CPU? * struct proc_struct *parent; // the parent process * struct mm_struct *mm; // Process's memory management field * struct context context; // Switch here to run process * struct trapframe *tf; // Trap frame for current interrupt * uintptr_t cr3; // CR3 register: the base addr of Page Directroy Table(PDT) * uint32_t flags; // Process flag * char name[PROC_NAME_LEN + 1]; // Process name */proc->state = PROC_UNINIT; //设置进程为“初始”态 proc->pid = -1; //设置进程pid的未初始化值 proc->runs = 0;//初始化时间片 proc->kstack = 0;//内核栈的地址 proc->need_resched = 0;//是否需要调度 proc->parent = NULL;//父节点为空 proc->mm = NULL; //内存管理初始化 memset(&(proc->context), 0, sizeof(struct context));//进程上下文初始化 proc->tf = NULL; //中断帧指针置为空,总是能够指向中断前的trapframe proc->cr3 = boot_cr3;//设置内核页目录表的基址 proc->flags = 0; //标志位初始化 memset(proc->name, 0, PROC_NAME_LEN); //进程名初始化} return proc;}
2、struct context context和struct trapframe *tf的作用分析:
①context:进程的上下文,用于进程切换。主要保存了前一个进程的现场(各个寄存器的状态)。在 uCore中,所有的进程在内核中也是相对独立的(例如独立的内核堆栈以及上下文等等)。使用 context 保存寄存器的目的就在于在内核态中能够进行上下文之间的切换。实际利用context进行上下文切换的函数是在kern/process/switch.S中定义switch_to。
②tf:中断帧的指针,总是指向内核栈的某个位置:当进程从用户空间跳到内核空间时,中断帧记录了进程在被中断前的状态。当内核需要跳回用户空间时,需要调整中断帧以恢复让进程继续执行的各寄存器值。除此之外,uCore内核允许嵌套中断。因此为了保证嵌套中断发生时tf 总是能够指向当前的trapframe,uCore 在内核栈上维护了 tf 的链。
练习二:为新创建的内核线程分配资源
创建一个内核线程需要分配和设置好很多资源。kernel_thread函数通过调用do_fork函数完成具体内核线程的创建工作。do_kernel函数会调用alloc_proc函数来分配并初始化一个进程控制块,但alloc_proc只是找到了一小块内存用以记录进程的必要信息,并没有实际分配这些资源。ucore一般通过do_fork实际创建新的内核线程。do_fork的作用是,创建当前内核线程的一个副本,它们的执行上下文、代码、数据都一样,但是存储位置不同。在这个过程中,需要给新内核线程分配资源,并且复制原进程的状态。完成在kern/process/proc.c中的do_fork函数中的处理过程。
1、思路:
①调用alloc_proc,首先获得一块用户信息块。
②为进程分配一个内核栈。
③复制原进程的内存管理信息到新进程(但内核线程不必做此事)
④复制原进程上下文到新进程
⑤将新进程添加到进程列表
⑥唤醒新进程
⑦返回新进程号(设置子进程号为返回值)
2、实现:
intdo_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) { int ret = -E_NO_FREE_PROC; struct proc_struct *proc; if (nr_process >= MAX_PROCESS) { goto fork_out; } ret = -E_NO_MEM; //LAB4:EXERCISE2 YOUR CODE /* * Some Useful MACROs, Functions and DEFINEs, you can use them in below implementation. * MACROs or Functions: * alloc_proc: create a proc struct and init fields (lab4:exercise1) * setup_kstack: alloc pages with size KSTACKPAGE as process kernel stack * copy_mm: process "proc" duplicate OR share process "current"'s mm according clone_flags * if clone_flags & CLONE_VM, then "share" ; else "duplicate" * copy_thread: setup the trapframe on the process's kernel stack top and * setup the kernel entry point and stack of process * hash_proc: add proc into proc hash_list * get_pid: alloc a unique pid for process * wakup_proc: set proc->state = PROC_RUNNABLE * VARIABLES: * proc_list: the process set's list * nr_process: the number of process set */ // 1. call alloc_proc to allocate a proc_struct // 2. call setup_kstack to allocate a kernel stack for child process // 3. call copy_mm to dup OR share mm according clone_flag // 4. call copy_thread to setup tf & context in proc_struct // 5. insert proc_struct into hash_list && proc_list // 6. call wakup_proc to make the new child process RUNNABLE// 7. set ret vaule using child proc's pid//第一步:申请内存块,如果失败,直接返回处理 if ((proc = alloc_proc()) == NULL) { goto fork_out; }//将子进程的父节点设置为当前进程 proc->parent = current;//第二步:为进程分配一个内核栈 if (setup_kstack(proc) != 0) { goto bad_fork_cleanup_proc;}//第三步:复制父进程的内存信息到子进程 if (copy_mm(clone_flags, proc) != 0) { goto bad_fork_cleanup_kstack; } //第四步:复制父进程相关寄存器信息(上下文)copy_thread(proc, stack, tf);//第五步:将新进程添加到进程列表(此过程需要加保护锁) bool intr_flag; local_intr_save(intr_flag); { proc->pid = get_pid();//建立散列映射方便查找 hash_proc(proc);//将进程链节点加入进程列表 list_add(&proc_list, &(proc->list_link));//进程数加1 nr_process ++; } local_intr_restore(intr_flag);//第六步:一切准备就绪,可以叫醒子进程了 wakeup_proc(proc);//第七步:别忘了设置返回的子进程号 ret = proc->pid;fork_out: return ret;bad_fork_cleanup_kstack: put_kstack(proc);bad_fork_cleanup_proc: kfree(proc); goto fork_out;}
2、ucore是否做到给每个新fork的线程一个唯一的id的?
在使用 fork 或 clone 系统调用时产生的进程均会由内核分配一个新的唯一的PID值。
具体来说,就是在分配PID时,设置一个保护锁,暂时不允许中断,这样在就唯一地分配了一个PID。
练习三:理解 proc_run 函数和它调用的函数如何完成进程切换的。
1、代码:
// proc_run - make process "proc" running on cpu// NOTE: before call switch_to, should load base addr of "proc"'s new PDTvoidproc_run(struct proc_struct *proc) {if (proc != current) { bool intr_flag; struct proc_struct *prev = current, *next = proc; local_intr_save(intr_flag);//不允许中断保护进程 { current = proc; load_esp0(next->kstack + KSTACKSIZE);//加载内核堆栈 lcr3(next->cr3);//切换页目录表基址 switch_to(&(prev->context), &(next->context));//根据上下文切换进程 } local_intr_restore(intr_flag); }}
2、在本实验的执行过程中,创建且运行了几个内核线程?
idleproc:ucore第一个内核进程,完成内核中各个子系统的初始化,之后立即调度,执行其他进程。
initproc:用于完成实验的功能而调度的内核进程
3、语句local_intr_save(intr_flag);....local_intr_restore(intr_flag);在这里有何作用?
保护进程切换不会被中断,以免进程切换时其他进程再进行调度。
实验结果:
- ucore操作系统实验lab4 -- 内核线程管理
- 操作系统ucore lab4实验报告
- ucore操作系统lab4实验报告(理论部分)
- ucore lab4
- ucore lab4
- 操作系统 lab4 实验报告
- 操作系统实验报告 lab4
- 操作系统ucore实验_lab2_debug
- 操作系统实验报告:ucore-lab1
- ucore操作系统lab2实验报告
- 操作系统ucore lab1实验报告
- 操作系统ucore lab2实验报告
- 操作系统ucore lab3实验报告
- 操作系统ucore lab5实验报告
- 操作系统ucore lab6实验报告
- 操作系统ucore lab7实验报告
- 操作系统ucore lab8实验报告
- # 操作系统实验报告:ucore-lab1
- [Java]学习笔记,随笔【四】
- Web 开发的 JavaScript 框架资料收集(15款)
- Java文件 File练习-递归删除带内容的目录
- 用make编译多个.c文件
- JavaScript语法 (顺序+判断+选择+循环+其他=五种语句)演示
- ucore操作系统实验lab4 -- 内核线程管理
- 题目1152:点菜问题
- Android LayoutInflater原理分析,带你一步步深入了解View(一)
- java中OutofMemoryError和JVM内存结构
- 字符编码
- 机器视觉学习系列四:身份证识别
- Ubuntu12.04下eclipse提示框黑色背景色的修改方法
- Unity 自定义字体 Custom Font 原理 二
- ASP.NET 5 简介