操作系统 ucore lab4实验报告

ucore lab4(内核线程管理)

一、实验目的

1.1了解内核线程创建/执行的管理过程
1.2了解内核线程的切换和基本调度过程

二、实验内容

   实验2/3完成了物理和虚拟内存管理,这给创建内核线程(内核线程是一种特殊的进程)打下了提供内存管理的基础。当一个程序加载到内存中运行时,首先通过ucore OS的内存管理子系统分配合适的空间,然后就需要考虑如何分时使用CPU来“并发”执行多个程序,让每个运行的程序(这里用线程或进程表示)“感到”它们各自拥有“自己”的CPU。
   本次实验将首先接触的是内核线程的管理。内核线程是一种特殊的进程,内核线程与用户进程的区别有两个:
	·内核线程只运行在内核态
	·用户进程会在在用户态和内核态交替运行
	·所有内核线程共用ucore内核内存空间,不需为每个内核·线程维护单独的内存空间
	·而用户进程需要维护各自的用户内存空间

三、实验步骤及流程

3.0 练习0:填写已有实验

本实验依赖实验1/2/3。请把你做的实验1/2/3的代码填入本实验中代码中有“LAB1”,“LAB2”,“LAB3”的注释相应部分。

3.1 练习1:分配并初始化一个进程控制块(需要编码)

3.1.1实验要求

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成员变量含义和在本实验中的作用是啥?(提示通过看代码和编程调试可以判断出来)

3.1.2关键数据结构及知识点

我们需要实现的alloc_proc()函数它主要定义了一个结构体proc_struct,我们需要初始化这样一个结构体的一个对象并返回它。这个函数的返回语句是“return proc”,其中proc就是这个proc_struct结构体的一个对象。
这里我们需要初始化的一个东西就是proc_struct的一个对象,分配的是一个内核线程的PCB,它通常只是内核中的一小段代码或者函数,没有用户空间。而由于在操作系统启动后,已经对整个核心内存空间进行了管理,所以内核中的所有线程都不需要再建立各自的页表,只需共享这个核心虚拟空间就可以访问整个物理内存了。
proc_struct结构体如下(kern/process/proc.h):

struct proc_struct {
   
   //进程控制块
    enum proc_state state;                      // 进程状态
    int pid;                                    // 进程ID
    int runs;                                   // 运行时间
    uintptr_t kstack;                           // 内核栈位置
    volatile bool need_resched;                 // 是否需要调度
    struct proc_struct *parent;                 // 父进程
    struct mm_struct *mm;                       // 进程的虚拟内存
    struct context context;                     // 进程上下文
    struct trapframe *tf;                       // 当前中断帧的指针
    uintptr_t cr3;                              // 当前页表地址
    uint32_t flags;                             // 进程
    char name[PROC_NAME_LEN + 1];               // 进程名字
    list_entry_t list_link;                     // 进程链表    
    list_entry_t hash_link;                    
};

**(1)state:**进程所处的状态,在proc.h有定义,具体如下:

enum proc_state {
   
   //进程状态
    PROC_UNINIT = 0,  // 未初始状态 
    PROC_SLEEPING,    //睡眠(阻塞)状态  
    PROC_RUNNABLE,    //运行与就绪态 
    PROC_ZOMBIE,      //僵死状态
};

**(2)pid:**进程id号。
**(3)runs:**进程运行的时间。
**(4)kstack:**记录了分配给该进程/线程的内核桟的位置。这里记录的是分配给该进程在内存中的栈位置,相关操作应该和lab2和lab3有关。
**(5)need_resched:**是否需要调度,目前实验未涉及这一部分,可以暂时搁置不作处理。
**(6)parent:**用户进程的父进程,这是一个指针变量,记录它的父进程是谁。在所有进程中,只有一个进程没有父进程,就是内核创建的第一个内核线程。
**(7)mm:**负责管理进程的虚拟内存,其实就是内存管理的信息,包括内存映射列表、页表指针等。mm成员变量在lab3中用于虚存管理。但在实际OS中,内核线程常驻内存,不需要考虑替换页问题,mm应该和lab2和lab3有关。
**(8)context:**进程的上下文,用于进程切换。使用Switch.S汇编文件中的定义。
**(9)tf:**中断帧的指针,指导书上说,它是中断帧的指针,总是指向内核栈的某个位置:当进程从用户空间跳到内核空间时,中断帧记录了进程在被中断前的状态。当内核需要跳回用户空间时,需要调整中断帧以恢复让进程继续执行的各寄存器值。除此之外,uCore内核允许嵌套中断。
**(10)cr3:**记录了当前使用的页表的地址。
**(11)name[PROC_NAME_LEN + 1]:**这是内核线程(进程)的名称。

3.1.3代码实现(alloc_proc(kern/process/proc.c))
static struct proc_struct *
alloc_proc(void) {
   
   
    struct proc_struct *proc = kmalloc(sizeof(struct proc_struct));
    if (proc != NULL) {
   
   
        proc->state = PROC_UNINIT;//给进程设置为未初始化状态
        proc->pid = -1;//未初始化的进程,其pid为-1
        proc->runs = 0;//初始化时间片,刚刚初始化的进程,运行时间一定为零	
        proc->kstack = 0;//内核栈地址,该进程分配的地址为0,因为还没有执行,也没有被重定位,因为默认地址都是从0开始的。
        proc->need_resched = 0;//不需要调度
        proc->parent = NULL;//父进程为空
        proc->mm = NULL;//虚拟内存为空
        memset(&(proc->context), 0, sizeof(struct context));//初始化上下文
        proc->tf 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值