近几日睡眠质量不佳,脑袋一困就没法干活,今天总算时补完了.LAB5难度比LAB4要高,想要理解所有细节时比较困难.但毕竟咱不是要真去写一个OS,所以一些个实现细节就当成黑箱略过了.

这节加上了用户进程,主要逻辑是:idle_proc内核线程--子进程-->init_proc内核线程--子进程-->user_main内核线程--load_icode-->exit用户进程--子进程-->新的用户进程,然后再逐级释放

init_main: 在init内核线程中创建user_main内核线程

user_mem_check: 顾名思义.

copy_mm: 把当前进程的mm和对应的物理内存全部做拷贝,添加到指定进程的mm中.使用了dup_mmap

dup_mmap: 把mm从from拷贝到to,使用了copy_range

copy_range: 把pde_t的对应物理内存从from拷贝到to

接下来就是各种状态的转换:

/*
process state changing: alloc_proc RUNNING
+ +--<----<--+
+ + proc_run +
V +-->---->--+
PROC_UNINIT -- proc_init/wakeup_proc --> PROC_RUNNABLE -- try_free_pages/do_wait/do_sleep --> PROC_SLEEPING --
A + +
| +--- do_exit --> PROC_ZOMBIE +
+ +
-----------------------wakeup_proc----------------------------------
*/

do_wait: 如果指定子进程为僵尸态,则释放子进程资源(线程表,PCB,内核栈);否则自身进入等待态

do_execve: 释放当前进程的mm,调用load_icode载入指定的程序

do_fork: 创建当前进程的子进程,并拷贝对应内存区域.trapframe,stack可以单独指定

do_exit:

释放当前进程资源

如果当前进程的父进程为WT_CHILD状态,则唤醒之

把当前进程的所有子进程都过继给initproc,如果哪个子进程是个ZOMBIE,则唤醒initproc

do_kill: 将指定进程的flags设为PF_EXITING,等待被exit

do_yield: 将当前进程的need_resched置一

load_icode: 当前进程的mm为空时,将内存中指定的ELF程序文件进行展开并作为当前进程的新内容,并更新为用户态特权级

syscall巧妙的运用了函数指针数组便于用户态使用

static int (*syscalls[])(uint32_t arg[]) = {
[SYS_exit] sys_exit,
[SYS_fork] sys_fork,
[SYS_wait] sys_wait,
[SYS_exec] sys_exec,
[SYS_yield] sys_yield,
[SYS_kill] sys_kill,
[SYS_getpid] sys_getpid,
[SYS_putc] sys_putc,
[SYS_pgdir] sys_pgdir,
}; #define NUM_SYSCALLS ((sizeof(syscalls)) / (sizeof(syscalls[0]))) void
syscall(void) {
struct trapframe *tf = current->tf;
uint32_t arg[5];
int num = tf->tf_regs.reg_eax;
if (num >= 0 && num < NUM_SYSCALLS) {
if (syscalls[num] != NULL) {
arg[0] = tf->tf_regs.reg_edx;
arg[1] = tf->tf_regs.reg_ecx;
arg[2] = tf->tf_regs.reg_ebx;
arg[3] = tf->tf_regs.reg_edi;
arg[4] = tf->tf_regs.reg_esi;
tf->tf_regs.reg_eax = syscalls[num](arg);
return ;
}
}
print_trapframe(tf);
panic("undefined syscall %d, pid = %d, name = %s.\n",
num, current->pid, current->name);
}

承接LAB4,当执行到init_main时,会创建user_main内核线程,并使init_main进入等待态调度user_main

调度完成后的函数调用栈为:

kernel_thread_entry->user_main->__alltraps->trap->trap_dispatch->syscall->sysexec->do_execve

这一过程最终将user/exit.c的代码载入到了user_main内核线程中,并将其转化为了用户进程exit,且拥有独立的mm

载入完成后输出信息:

kernel_execve: pid = 2, name = "exit".

因为载入代码这一过程是运行时发生的,所以GDB无法跟踪调试

通过分析可知,ELF程序的入口代码位于user/libs/initcode.S中,主要功能是调用了umain

umain.c功能是调用main函数,并在返回后exit()

main函数则位于exit.c中

int
main(void) {
int pid, code;
cprintf("I am the parent. Forking the child...\n");
if ((pid = fork()) == 0) {
cprintf("I am the child.\n");
yield();
yield();
yield();
yield();
yield();
yield();
yield();
exit(magic);
}
else {
cprintf("I am parent, fork a child pid %d\n",pid);
}
assert(pid > 0);
cprintf("I am the parent, waiting now..\n"); assert(waitpid(pid, &code) == 0 && code == magic);
assert(waitpid(pid, &code) != 0 && wait() != 0);
cprintf("waitpid %d ok.\n", pid); cprintf("exit pass.\n");
return 0;
}

首先输出信息:

I am the parent. Forking the child...

调用fork()创建子进程,调用栈为:

user/exic.c::main->fork->sys_fork->syscall(SYS_fork)->触发中断SYS_CALL,参数为SYS_fork

以上部分都在user/文件夹下,即在用户态下运行,触发系统调用类型的中断后切换到内核态(对应kern/文件夹)继续执行,__alltraps->trap->dispatch_trap->syscall->sys_fork

此时创建出了3号进程,二者都运行到了if ((pid = fork()) == 0) {这行代码.

对于父进程:fork()返回值为子进程PID

对于子进程:fork()返回值为0

输出信息:

I am parent, fork a child pid 3

I am the parent, waiting now..

父进程调用wait(pid,&code),以fork()类似的形式触发系统调用,最终进入等待态

子进程被调度,输出信息:

I am the child.

然后子进程调用exit()触发系统调用,释放自身资源,并进入僵尸态.

因为父进程处于WT_CHILD状态,所以被唤醒,有如下信息:

waitpid 3 ok.

exit pass.

main()返回到umain()中,调用exit回收进程资源,并重新调度到init_proc,输出如下信息:

all user-mode processes have quit.

init check memory pass.

kernel panic at kern/process/proc.c:447:

initproc exit.

至此整个LAB 5分析完毕

ucore lab5 用户进程管理 学习笔记的更多相关文章

  1. ucore操作系统学习(五) ucore lab5用户进程管理

    1. ucore lab5介绍 ucore在lab4中实现了进程/线程机制,能够创建并进行内核线程的调度.通过上下文的切换令线程分时的获得CPU,使得不同线程能够并发的运行. 在lab5中需要更进一步 ...

  2. ucore lab4 内核线程管理 学习笔记

    越学越简单,真是越学越简单啊 看视频的时候着实被那复杂的函数调用图吓到了.看代码的时候发现条理还是很清晰的,远没有没想象的那么复杂. 这节创建了俩内核线程,然后运行第一个线程,再由第一个切换到第二个. ...

  3. MYSQL用户权限管理学习笔记

    MYSQL 用户管理 1.权限表 MYSQL是一个多用户的数据库,MYSQL的用户可以分为两大类: (1)       超级管理员用户(root),拥有全部权限 (2)       普通用户,由roo ...

  4. C++内存管理学习笔记(5)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

  5. C++内存管理学习笔记(6)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

  6. C++内存管理学习笔记(7)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

  7. Docker Image管理学习笔记,ZT

    Docker Image管理学习笔记 http://blog.csdn.net/junjun16818/article/details/38423391

  8. Linux进程线程学习笔记:运行新程序

    Linux进程线程学习笔记:运行新程序                                         周银辉 在上一篇中我们说到,当启动一个新进程以后,新进程会复制父进程的大部份上下 ...

  9. Linux内存管理学习笔记 转

    https://yq.aliyun.com/articles/11192?spm=0.0.0.0.hq1MsD 随着要维护的服务器增多,遇到的各种稀奇古怪的问题也会增多,要想彻底解决这些“小”问题往往 ...

随机推荐

  1. 什么是 CAS?

    CAS 是 compare and swap 的缩写,即我们所说的比较交换. cas 是一种基于锁的操作,而且是乐观锁.在 java 中锁分为乐观锁和悲观锁.悲观锁是将资源锁住,等一个之前获得锁的线程 ...

  2. (转载) MOS管区分NP沟道

    三极管是流控型器件,MOS管是压控型器件,两者存在相似之处.三极管机可能经常用,但MOS管你用的可能较少.对于MOS管先抛出几个问题: 如何区分P-MOS和N-MOS:   如何区分MOS的G.D.S ...

  3. C语言之基本组成(知识点6)

    一.C程序基本组成 C程序是由语句组成的,通常包括一个或多个函数,其中有且只有一个函数称为 主函数,其函数名为main. 二.C程序的组成特点: 1.每个C程序由一个或多个函数组成.每个C程序有且仅有 ...

  4. python学习笔记(三)——函数

    函数定义 def 函数名(形参 . . . ) 函数体 1. 函数参数 返回值:可以有一个或多个 形参:支持默认形参.关键字形参.可变参数形参等 1.1 必须参数 调用时传入的参数必须与定义时相同. ...

  5. c语言中的字面量

    在计算机科学中,字面量(literal)是用于表达源代码中一个固定值的表示法(notation). 几乎所有计算机编程语言都具有对基本值的字面量表示,诸如:整数.浮点数以及字符串: 而有很多也对布尔类 ...

  6. js多线程worker

    参考地址:https://blog.csdn.net/huang100qi/article/details/89303555?utm_source=app https://www.cnblogs.co ...

  7. 前端框架小实验-在umi框架中以worker线程方式使用SQL.js的wasm

    总述:在Win7环境下配置umijs框架,在框架中用worker线程方式使用SQL.js的wasm,在浏览器端实现数据的增删改查以及数据库导出导入. 一.安装node.js 1.Win7系统只支持no ...

  8. Python入门-正则表达式

    正则匹配函数 # 需要先导入re模块 import re #字符串,匹配查找 info = "www baidu com" print("=======字符串自带find ...

  9. Struts2-拦截器原理

    拦截器原理包含Aop思想和责任链模式 1.Aop思想 aop是面向切面编程,有基本功能,扩展功能,不通过修改源代码方式扩展功能.(动态代理) 2.责任链模式,Java有23种设计模式,责任链模式是其中 ...

  10. Win下GCC报错 error: ‘for’ loop initial declarations are only allowed in C99 mode

    ##报错## 用GCC编译for循环会出现以下错误 error: 'for' loop initial declarations are only allowed in C99 mode 如图所示: ...