首先,.section .data
表示定义了一个数据段,在这个段中定义了一系列的全局变量。其中,_app_num
是一个标签,表示一个 64 位的整数,初始值为 23。接下来是一系列的标签,分别代表了应用程序的起始地址,每个标签都是 64 位的整数。
接着,.section .data
后面又出现了一个标签 _app_names
,它是一个字符串数组,包含了一组字符串,分别命名为 “ch2b_exit”、“ch2b_hello_world”、“ch2b_power” 等等。这些字符串名字对应了前面定义的应用程序的起始地址。
再往下,出现了一个标签 INIT_PROC
,它是一个字符串,表示初始化进程的名称,值为 “usershell”。
之后,每个应用程序都有自己的标签和段名,比如 app_0_start
、app_1_start
等等。每个标签都包含一个指令 .incbin
,它用于将一个二进制文件(以字符串形式指定文件路径)插入到当前段中。
进程初始化分析
scheduler()
fetch_task() // 获取下一个要执行的进程
swtch(&curenv->context, nextenv->context) // 切换到下一个进程上下文
// Per-process state
struct proc {
enum procstate state; // 进程状态
int pid; // 进程 ID
uint64 ustack; // 进程用户栈虚拟地址 (用户页表)
uint64 kstack; // 进程内核栈虚拟地址 (内核页表)
struct trapframe *trapframe; // 进程中断帧
struct context context; // 用于保存进程内核态的寄存器信息,进程切换时使用
pagetable_t pagetable; // User page table
uint64 max_page;
uint64 program_brk;
uint64 heap_bottom;
struct proc * parent; // Parent process
uint64 exit_code;
struct file * files[FD_BUFFER_SIZE];
uint32 syscall_times[MAX_SYSCALL_NUM]; // 系统调用次数统计
uint64 start_time; // 进程开始运行时间
struct vma vmas[NVMA]; // 虚拟内存区域
};
wait 系统调用的功能
wait
系统调用是用于处理子进程终止状态的系统调用。其主要功能是等待子进程的终止,并获取子进程的退出状态信息。在操作系统中,当一个父进程创建了一个子进程后,通常会使用 wait
来等待子进程的终止,以便进行后续的处理,如回收子进程的资源或获取其运行结果。
以下是 wait
系统调用的主要功能:
等待子进程终止:父进程调用
wait
系统调用后,会进入阻塞状态,等待子进程终止。如果子进程已经终止,那么wait
立即返回,否则父进程会一直等待直到子进程终止。获取子进程的退出状态:
wait
系统调用会获取子进程的退出状态信息,包括子进程的退出码(通常是一个整数)。这个退出码可以告诉父进程子进程的终止情况,例如是否成功执行等。回收子进程资源:一旦子进程终止,其占用的系统资源(如内存、文件描述符等)通常需要由父进程来回收,以避免资源泄漏。
wait
系统调用在等待子进程终止后,会自动回收这些资源。处理僵尸进程:在某些情况下,子进程可能会在终止后成为僵尸进程,即已经终止但其进程描述符仍然存在。父进程可以使用
wait
来回收这些僵尸进程,释放相关资源。
exec
、fork
和 spawn
是操作系统中常见的进程管理系统调用,各自具有不同的功能和用途:
exec
系统调用:- 功能:
exec
系统调用用于在当前进程的上下文中加载并执行一个新的程序。 - 用途:通常在一个进程需要替换自身的执行映像时使用。它会加载一个新的可执行文件,覆盖当前进程的地址空间和代码段,然后开始执行新的程序。这个新程序可以是完全不同的程序,从而允许进程动态切换到不同的应用程序,而不需要创建新的进程。
- 功能:
fork
系统调用:- 功能:
fork
系统调用用于创建一个与当前进程几乎完全相同的新进程,包括代码、数据和上下文等。 - 用途:通常用于创建新的进程,新进程称为子进程,它从父进程继承了大部分状态,然后可以在独立的地址空间中执行不同的操作。
fork
创建的子进程是父进程的副本,可以并行执行不同的任务。
- 功能:
spawn
系统调用:- 功能:
spawn
系统调用通常用于创建新的进程并执行指定的程序。 - 用途:类似于
fork
,它也创建了一个新的进程,但不像fork
那样完全复制父进程。相反,spawn
允许你指定一个新程序的路径和参数,而不是完全复制当前进程的状态。这使得它更适合用于启动新程序,而不是简单地创建一个进程副本。
- 功能:
总结:
exec
用于替换当前进程的执行映像,允许加载和执行新程序。fork
用于创建一个几乎与父进程相同的新进程,新进程成为父进程的副本。spawn
通常用于创建一个新进程并执行指定的程序,允许指定不同的程序路径和参数。
附录
本章任务: 在次 -> 在此