1.1: xv6进程(xv6 process)
包含用户态存储(指令,数据和堆栈),内核中存储了每一个进程的相关状态
xv6是分时系统
进程间(对于用户看来是透明transparently,感受不到)切换使用CPU计算资源
当出现进程调度时,一般挂起的进程会保存CPU寄存器的状态(执行上下文),当下次恢复运行的时候再将执行上下文恢复到CPU寄存器中
内核态通过PID(process identifier)来关联进程
系统调用列表
System call |
Description |
---|---|
nt fork() |
Create a process, return child’s PID. |
int exit(int status) |
Terminate the current process; status reported to wait(). No return. |
int wait(int *status) |
Wait for a child to exit; exit status in *status; returns child PID. |
int kill(int pid) |
Terminate process PID. Returns 0, or -1 for error. |
int getpid() |
Return the current process’s PID. |
int sleep(int n) |
Pause for n clock ticks. |
int exec(char *file, char *argv[]) |
Load a file and execute it with arguments; only returns if error. |
char *sbrk(int n) |
Grow process’s memory by n zero bytes. Returns start of new memory. |
int open(char *file, int flags) |
Open a file; flags indicate read/write; returns an fd (file descriptor). |
int write(int fd, char *buf, int n) |
Write n bytes from buf to file descriptor fd; returns n. |
int read(int fd, char *buf, int n) |
Read n bytes into buf; returns number read; or 0 if end of file. |
int close(int fd) |
Release open file fd. |
int dup(int fd) |
Return a new file descriptor referring to the same file as fd. |
int pipe(int p[]) |
Create a pipe, put read/write file descriptors in p[0] and p[1]. |
int chdir(char *dir) |
Change the current directory. |
int mkdir(char *dir) |
Create a new directory. |
int mknod(char *file, int, int) |
Create a device file. |
int fstat(int fd, struct stat *st) |
Place info about an open file into *st. |
int link(char *file1, char *file2) |
Create another name (file2) for the file file1. |
int unlink(char *file) |
Remove a file. |
fork系统调用
一个进程可以通过系统调用fork来创建新的进程,fork会创建一个调用进程内存的完整拷贝(exact copy)包括指令集合(instructions),数据和堆栈,但是他们在隔离的内存空间和寄存器里执行的,变量之间不会相互影响。
fork系统调用执行的结果在原始进程中和在新的进程中都有返回
在原始的进程中,fork返回新的进程的PID(子进程pid)
在新产生的进程中,fork运行的结果返回0
原始的进程和新的进程通常也被称为父进程和子进程
虽然父进程和子进程在开始时具有相同的内存内容,但是他们在隔离的内存空间和寄存器里执行的,变量之间不会相互影响
fork系统调用示例
int pid = fork();
//父进程调用fork系统调用创建子进程,子进程拷贝一份完整的进程memory,同时fork在父进程和子进程里均有返回。
if(pid > 0){
printf("parent: child=%d\n", pid); //pid大于0,则为父进程满足的条件,这时输出子进程id并等待子进程执行结束,结束后返回子进程完成任务的状态输出
pid = wait((int *) 0);
//wait系统调用返回当前进程退出的或killed的子进程的PID,同时将退出的子进程的状态拷贝到传递给wait函数的内存地址。
//如果调用进程的所有子进程都没有退出,wait函数将会等待直到有一个子进程退出,如果调用的进程没有子进程,wait函数会立马返回-1。
//如果父进程不需要关注子进程退出的状态,则可以传一个0地址给wait函数。
printf("child %d is done\n", pid);
}
else if(pid == 0){//pid等于0,则为子进程内执行的代码,直接输出字符串后并退出
printf("child: exiting\n");
exit(0); //exit系统调用使得进程停止执行并开始释放资源如内存和打开的文件等,一般传递0表示正常退出,如果传递1表示出错
} else {//否则,fork创建失败
printf("fork error\n");
}
exec系统调用
exec系统调用和fork的不同在于
不创建新进程,而是让当前进程运行一个不同的程序,加载的程序镜像为满足ELF(ELF, Executable and Linkable Format)格式的可执行文件,一般通过源码编译而成
ELF包含文本区(代码指令),数据区(全局和静态变量),动态链接区等
支持动态链接和静态链接
方便调试,基于section和symbol tables的丰富结构使得方便进行调试和二进制分析
当调用exec后,当前进程的代码和数据都被新程序替换,但进程ID不变