xv6--一个类Unix的教学用操作系统

第1.1节 进程和内存

2020-10-29  本文已影响0人  橡树人

1.1节 进程和内存

这一节涉及的系统调用有:

一个xv6进程由用户空间内存(指令、数据、栈)和内核专有的进程状态组成。

xv6分时共享进程,即xv6透明地在一组等待执行的进程间切换可用的CPU。

当一个进程不执行时,xv6保存该进程的CPU寄存器,当下次运行该进程时,恢复先前保存的CPU寄存器值。

内核给每个进程关联一个进程标识符或者PID。

理解系统调用fork

一个进程可使用fork系统调用来创建新的进程。

fork创建一个新的进程,即子进程:子进程跟父进程有着同样的内存内容。

fork在父进程和子进程中都会返回。

示例代码1

int pid = fork();
if (pid > 0) {
    printf("parent: child=%d\n", pid);
    pid = wait((int *) 0);
    printf("child %d is done\n", pid);
}else if (pid == 0) {
    printf("child: exiting\n");
    exit(0);
}else {
    printf("fork error\n");
}

输出:

parent: child=1234
child: exiting

parent: child 1234 is done

系统调用exit

系统调用wait

注意:

xv6系统使用的ELF格式。

系统调用exec

代码示例2

char *argv[3];

argv[0] = "echo";
argv[1] = "hello";
argv[2] = 0;
exec("/bin/echo", argv);
printf("exec error\n");

这段代码使用程序/bin/echo的运行实例来替换调用程序,参数列表是echo hello

大部分程序都忽略参数数组的第一个元素,因为约定第一个元素是程序的名字。

xv6的shell程序使用上面的系统调用来代表用户运行程序。

shell程序的主体结构很简单:

int
main(void)
{
  static char buf[100];
  int fd;

  // Ensure that three file descriptors are open.
  while((fd = open("console", O_RDWR)) >= 0){
    if(fd >= 3){
      close(fd);
      break;
    }
  }

  // Read and run input commands.
  while(getcmd(buf, sizeof(buf)) >= 0){
    if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
      // Chdir must be called by the parent, not the child.
      buf[strlen(buf)-1] = 0;  // chop \n
      if(chdir(buf+3) < 0)
        fprintf(2, "cannot cd %s\n", buf+3);
      continue;
    }
    if(fork1() == 0)
      runcmd(parsecmd(buf));
    wait(0);
  }
  exit(0);
}

解释:
主循环
首先,父进程使用getcmd从用户读取一行输入;
然后,父进程调用fork创建了shell进程的拷贝,即子进程;
最后,父进程调用wait,子进程运行命令。

比如,用户在shell上键入了"echo hello",则runcmd被调用使的参数是"echo hello"。

runcmd会运行实际的命令。对于"echo hello",runcmd会调用exec

如果exec成功了,则子进程将执行来自echo的指令而不是runcmd

在某个点处,echo会调用exit,会导致父进程从wait中返回。

为什么不将forkexec整个成一个调用?
shell使用forkexec的这种隔离来实现I/O重定向。

为了避免创建一个拷贝进程带来的浪费,然后立即用exec来替换子进程,内核通过使用诸如copy-on-write等的虚拟内存技术来优化fork的实现。

xv6都是隐式地分配大部分用户空间内存:

如果一个进程在运行时需要更多的内存,则该进程可调用sbrk(n)来使其数据内存增长n个字节。

注意:
sbrk的返回值是新的内存的地址。

上一篇 下一篇

猜你喜欢

热点阅读