进程:
从进程的结构看:进程是一个应用程序运行时刻的实例;
从进程的功能看:进程是应用程序运行时所需资源的容器;
从操作系统对进程的实现角度看:进程是一堆数据结构;
进程的结构:
进程必须要有一个地址空间:这个地址空间包括至少两部分:一部分是内核,一部分是用户的应用程序;
每个进程拥有x86 CPU的整个虚拟地址空间,这个虚拟地址空间被分成两部分,上半部分是进程共享的内核部分,里面放着一份内核代码和数据;下半部分是应用程序,各自独立;
R0特权级运行在内核地址空间,R3特权级运行在下半部分的应用程序中;
应用程序和内核的关系:应用程序需要内核提供相关的资源,内核需要控制应用程序的运行,并且内核必须能够命令应用程序能够随时中断,进入内核地址空间,也能恢复执行,这就需要保存应用程序的机器上下文以及运行时刻的栈;
内核提供服务的机制:内核是这样提供服务的,通过停止应用程序代码运行,进入内核地址空间运行内核代码,随后返回结果;同时,内核还需要记录一个应用程序都访问了哪些资源,用资源描述符表示;其中带*号的是每个进程各自一份;
实现进程:
thread_t 结构表示一个进程;其中包括权限,分为用户进程和系统进程;优先级分64个;objnode_t 结构代表进程打开资源的描述符;
进程的地址空间:
thread_t 结构中有个mmadrsdsc_t 结构的指针,是一个进程的完整的地址空间;
进程的机器上下文:
包括CPU寄存器、内核函数调用路径;进程调度器函数会调用进程i切换函数,切换进程,而在进程切换函数中会保存栈寄存器的值;
context_t 结构,负责保存这些信息;其中有一个x64tss_t 结构指针,这个结构本身的地址存放在一个GDT表项中,由CPU的tr寄存器指向,tr寄存器中的值是GDT中x64tss_t 结构项对应的索引;
切换流程:CPU 在发生中断时,会根据中断门描述里的目标段选择子,进行必要的特权级切换,特权级的切换就必须要切换栈,CPU 硬件会自己把当前 rsp 寄存器保存到内部的临时寄存器 tmprsp;然后从 x64tss_t 结构体中找出对应的栈地址,装入 rsp 寄存器中;接着,再把当前的 ss、tmprsp、rflags、cs、rip,依次压入当前 rsp 指向的栈中。
建立进程:
包括进程的应用程序栈和进程的内核栈、进程的地址空间等;
建立进程接口:
krlnew_thread 接口函数,进程应用程序栈、进程内核栈大小检查,然后根据参数是创建内核进程还是用户进程;
1、内核进程:
以进程的方式执行一段内核代码,可以随时暂停或者运行、并发运行,但不会回到进程的应用程序地址空间中,只在内核地址空间中;
krlnew_kern_thread_core 函数:先分配内核栈空间,然后建立thread_t 结构体的实例变量,再设置进程权限、进程优先级、进程的内核栈顶和内核栈开始地址,并初始化进程的内核栈,加入进程调度系统;返回进程指针;
创建thread_t 结构:
就是分配一块内存用于存放thread_t 结构,krlnew_thread_dsc 接口函数,调用thread_t_init 函数初始化分配 thread_t 结构;进程id为thread_t 结构的地址;CPU的id也设置为0(只有一个);
初始化内核栈:
在进程的内核栈中放置一份CPU的寄存器数据,这份CPU寄存器数据就是一个进程机器上下文的一部分;又因为寄存器有位置关系,定义结构体来初始化;
intstkregs_t 结构,每个字段都是8字节的;krlthread_kernstack_init 函数实现处理栈顶16字节对齐,内核栈顶减去intstkregs_t结构的大小,段选择子指向内核代码段选择子,接着返回进程的内核栈,设置进程下一次运行的栈地址;
该结构最后定义的字段放在栈顶位置,最先定义的放在栈底位置;
然后初始化返回进程应用程序空间的内核栈;krlthread_userstack_init 函数 实现,与上述初始化相同,只不过段选择子指向了应用程序的代码段和数据段;CPU根据这个代码段、数据段选择子切换特权级;就能返回进程的应用程序空间了;
2、用户进程:
krlnew_user_thread_core 函数:分配应用程序栈空间,分配内核栈空间,建立thread_t 结构体的实例变量,与建立内核进程相比,建立用户进程两点不同:一是多分配了一个应用程序栈,内核进程不会返回到进程的应用程序空间,所以不需要应用程序栈,用户进程需要;二是 在最后调用了krlthread_userstack_init 函数 ,初始化返回进程应用程序空间的内核栈;
标签:13,thread,应用程序,地址,内核,进程,CPU From: https://www.cnblogs.com/xuan01/p/17363161.html