操作系统ucore lab5实验报告

ucore实验五介绍了用户进程的生命周期,包括创建、执行、复制内存、等待和退出。练习涉及alloc_proc、do_fork、idt_init和trap_dispatch的改进,以及加载应用程序、复制内存、理解fork、exec、wait和exit的实现。实验通过系统调用实现进程间的交互,完成资源管理和调度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

操作系统lab5实验报告

到实验四为止,ucore还一直在核心态“打转”,没有到用户态执行。创建用户进程,让用户进程在用户态执行,且在需要ucore支持时,可通过系统调用来让ucore提供服务。而本实验将进程的执行空间扩展到了用户态空间,出现了创建子进程执行应用程序等。即实验五主要是分析用户进程的整个生命周期来阐述用户进程管理的设计与实现。

练习0 填写已有实验

这里和前几个实验一样,照样运用meld软件进行对比,大致的截图如下:


这里简单将我们需要修改的地方罗列如下:

proc.c
default_pmm.c
pmm.c
swap_fifo.c
vmm.c
trap.c

另外根据试验要求,我们需要对部分代码进行改进,这里讲需要改进的地方的代码和说明罗列如下:

alloc_proc函数

改进后的alloc_proc函数如下:

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;
        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;
        proc->cr3 = boot_cr3;
        proc->flags = 0;
        memset(proc->name, 0, PROC_NAME_LEN);
        proc->wait_state = 0;
        proc->cptr = proc->optr = proc->yptr = NULL;
    }
    return proc;
}

比起改进之前多了这两行代码:

        proc->wait_state = 0;//初始化进程等待状态  
        proc->cptr = proc->optr = proc->yptr = NULL;//进程相关指针初始化  

这里解释proc的几个新指针:

parent:           proc->parent  (proc is children)
children:         proc->cptr    (proc is parent)
older sibling:    proc->optr    (proc is younger sibling)
younger sibling:  proc->yptr    (proc is older sibling)

就像注释所写的,这两行代码主要是初始化进程等待状态、和进程的相关指针,例如父进程、子进程、同胞等等。

因为这里涉及到了用户进程,自然需要涉及到调度的问题,所以进程等待状态和各种指针需要被初始化。

do_fork函数

改进后的do_fork函数如下:

int
do_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;
    if ((proc = alloc_proc()) == NULL) {
        goto fork_out;
    }

    proc->parent = current;
    assert(current->wait_state == 0);//确保当前进程正在等待

    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);
        set_links(proc);//将原来简单的计数改成来执行set_links函数,从而实现设置进程的相关链接 

    }
    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;
}

改动主要是上述代码中含注释的两行,第一行是为了确定当前的进程正在等待,第二行是将原来的计数换成了执行一个set_links函数,因为要涉及到进程的调度,所以简单的计数肯定是不行的。

idt_init函数

改进后的idt_init函数如下:

void idt_init(void) {
    extern uintptr_t __vectors[];
    int i;
    for (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);
}

相比于之前,多了这一行代码:

SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);////这里主要是设置相应的中断门

trap_dispatch函数

改进后的部分函数如下:

 ticks ++;
        if (ticks % TICK_NUM == 0) {
            assert(current != NULL);
            current->need_resched = 1;
        }
        break;

相比与原来主要是多了这一行代码

current->need_resched = 1;

这里主要是将时间片设置为需要调度,说明当前进程的时间片已经用完了。

练习1 加载应用程序并执行

根据实验说明书,我们需要完善的函数是load_icode函数。

这里介绍下这个函数的功能:load_icode函数主要用来被do_execve调用,将执行程序加载到进程空间(执行程序本身已从磁盘读取到内存中),这涉及到修改页表、分配用户栈等工作。
该函数主要完成的工作如下:

  • 1、调用 mm_create 函数来申请进程的内存管理数据结构 mm 所需内存空间,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值