说些什么呢

操作系统给进程分配资源的过程

· Jahjah

先说我自己的理解,操作系统给进程分配资源的过程就是创建进程执行所需要的上下文,而这个上下文包含非常多的状态(CPU state,MMU state,communication states…), 所以要对这些状态进行初始化即复制寄存器,复制页表,复制打开的文件等等。 Linux kernel的task_struct已经800多行了😂,包含了茫茫多的状态。

首先,什么是进程,很多人会说,进程是资源分配的最小单位,这句话没问题,但也没意义。而linus在mail list里面提到的关于进程的描述是最入木三分的: Context Of Execution

A “context of execution”, hereby called COE, is just the conglomerate of all the state of that COE. That state includes things like CPU state (registers etc), MMU state (page mappings), permission state (uid, gid) and various “communication states” (open files, signal handlers etc)

CPU state

如果把cpu的行为简化一下,就是不断的在取指,译码,执行。

while(true) {
    fetch(char* pc); //从pc寄存器里存的内存地址处取指
    decode(); //译码
    execute(); //执行
}

所以进程需要维护这个状态,以便在进程被调度到cpu上的时候,知道之前的状态和这次要从那里开始执行,自然进程被调度出去的时候,也要把当前状态保存下来。

以下是不同操作系统对这个的实现
xv6: https://github.com/mit-pdos/xv6-riscv/blob/f8bd2f9739571a0d6b5f8b191bc058f53b4cc7bc/kernel/proc.c#L280

int
fork(void)
{
  int i, pid;
  struct proc *np;
  struct proc *p = myproc();

  // Allocate process.
  if((np = allocproc()) == 0){
    return -1;
  }

  // copy saved user registers.
  *(np->trapframe) = *(p->trapframe);

  // Cause fork to return 0 in the child.
  np->trapframe->a0 = 0;
}

**linux kernel: **https://github.com/torvalds/linux/blob/d74da846046aeec9333e802f5918bd3261fb5509/kernel/fork.c#L2118

__latent_entropy struct task_struct *copy_process(
					struct pid *pid,
					int trace,
					int node,
					struct kernel_clone_args *args) {

    retval = copy_thread(p, args);
	if (retval)
		goto bad_fork_cleanup_io;
}

MMU state

现代操作系统都是多进程的,大多都会使用页表(把虚拟内存和物理内存映射起来的数据结构)隔离每个进程的内存空间。所以每个进程都需要维护自己的页表(MMU state)

以下是不同操作系统对这个的实现
xv6: https://github.com/mit-pdos/xv6-riscv/blob/f8bd2f9739571a0d6b5f8b191bc058f53b4cc7bc/kernel/proc.c#L280

int
fork(void)
{
  // Copy user memory from parent to child.
  if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
    freeproc(np);
    release(&np->lock);
    return -1;
  }
}

**linux kernel: **https://github.com/torvalds/linux/blob/d74da846046aeec9333e802f5918bd3261fb5509/kernel/fork.c#L2118

__latent_entropy struct task_struct *copy_process(
					struct pid *pid,
					int trace,
					int node,
					struct kernel_clone_args *args) {
	retval = copy_mm(clone_flags, p);
	if (retval)
		goto bad_fork_cleanup_signal;   
}

communication states

进程还需要维护和I/O相关的state,例如open files,这样当写入文件的时候,知道对应的文件系统和设备

以下是不同操作系统对这个的实现
xv6: https://github.com/mit-pdos/xv6-riscv/blob/f8bd2f9739571a0d6b5f8b191bc058f53b4cc7bc/kernel/proc.c#L280

int
fork(void)
{
  // increment reference counts on open file descriptors.
  for(i = 0; i < NOFILE; i++)
    if(p->ofile[i])
      np->ofile[i] = filedup(p->ofile[i]);
}

**linux kernel: **https://github.com/torvalds/linux/blob/d74da846046aeec9333e802f5918bd3261fb5509/kernel/fork.c#L2118

__latent_entropy struct task_struct *copy_process(
					struct pid *pid,
					int trace,
					int node,
					struct kernel_clone_args *args) {

    retval = copy_files(clone_flags, p, args->no_files);
	if (retval)
		goto bad_fork_cleanup_semundo;
}