code:newproc - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki

Table of Contents

Source

  • 为当前进程创建子进程
  • 父进程返回0
  • 子进程返回1

1800 #

1801 /*

1802  */

1803

1804 #include "../param.h"

1805 #include "../user.h"

1806 #include "../proc.h"

1807 #include "../text.h"

1808 #include "../systm.h"

1809 #include "../file.h"

1810 #include "../inode.h"

1811 #include "../buf.h"

1812 /* ------------------------- */

1813 /*

1814  * Create a new process-- the internal version of

1815  * sys fork.

1816  * It returns 1 in the new process.

1817  * How this happens is rather hard to understand.

1820  * in the same call to newproc as the parent;

1821  * but in fact the code that runs is that of swtch.

1822  * The subtle implication of the return value of swtch

1823  * (see above) is that this is the value that newproc's

1824  * caller in the new process sees.

1825  */

1826 newproc()

1827 {

1828     int a1, a2;

1829     struct proc *p, *up;

1830     register struct proc *rpp;

1831     register *rip, n;

1832

1833     p = NULL;

1834     /*

1835     * First, just locate a slot for a process

1837     * The panic "cannot happen" because fork already

1838     * checked for the existence of a slot.

1839     */

1840 retry:

1841     mpid++;

1842     if(mpid < 0) {

1843           mpid = 0;

1844           goto retry;

1845     }

  • 为要新建的进程分配一个独一无二的进程标识mpid
  • 若为负值,则循环+1,直到其不为负为止
1846     for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {

1847               if(rpp->p_stat == NULL && p==NULL)

1848                     p = rpp;

1849               if (rpp->p_pid==mpid)

1850                         goto retry;

1851     }

1852     if ((rpp = p)==NULL)

1853           panic("no procs");

1854

  • 遍历proc数组,将搜索到的第一个空位分配给新进程
    • 若遍历时发现有进程的标识等于要分配的标识符,则回到1840行重新分配一个新标识符
    • 若没能搜索到空位,则抛出错误
1855     /*

1856     * make proc entry for new proc

1857     */

1858

1859     rip = u.u_procp;

1860     up = rip;

1861     rpp->p_stat = SRUN;

1862     rpp->p_flag = SLOAD;

1863     rpp->p_uid = rip->p_uid;

1864     rpp->p_ttyp = rip->p_ttyp;

1865     rpp->p_nice = rip->p_nice;

1866     rpp->p_textp = rip->p_textp;

1867     rpp->p_pid = mpid;

1868     rpp->p_ppid = rip->p_pid;

1869     rpp->p_time = 0;

  • 置子进程的proc结构中的相关信息,部分从父进程直接拷贝
  • 1868行有笔误,原代码为rpp->p_ppid = rip->p_ppid
1870

1871     /*

1872     * make duplicate entries

1873     * where needed

1874     */

1875

1876     for(rip = &u.u_ofile[0]; rip < &u.u_ofile[NOFILE];)

1877               if((rpp = *rip++) != NULL)

1878                         rpp->f_count++;

1879     if((rpp=up->p_textp) != NULL) {

1880               rpp->x_count++;

1881               rpp->x_ccount++;

  • 父进程的打开文件结构中的f_count加1(因为子进程继承了父进程打开的文件),参见内存打开文件结构
  • 父进程的共享正文段中的共享进程数加1(因为子进程继承了父进程的共享正文段,且其proc结构中的textp指针指向该正文段)
1882     }

1883     u.u_cdir->i_count++;

  • 此处子进程应当申请新的file引用,而不是新的inode引用,未能解释,列入遗留问题
1884     /*

1885     * Partially simulate the environment

1887     * created (by copying) it will look right.

1888     */

1889     savu(u.u_rsav);

1890     rpp = p;
1891     u.u_procp = rpp;
1892     rip = up;
1893     n = rip->p_size;

1894     a1 = rip->p_addr;

1895     rpp->p_size = n;

  • n = 父进程图像大小
  • a1 = 父进程的ppda区首址
  • 子进程图像大小置为n
1896     a2 = malloc(coremap, n);
  • 在内存中为子进程分配一块大小为n的空间,并将该空间的首址赋给a2
1897     /*

1898     * If there is not enough core for the

1899     * new process, swap put the current process to

1900     * generate the copy.

1901     */

1902     if(a2 == NULL) {

1903               rip->p_stat = SIDL;

1904               rpp->p_addr = a1;

1905               savu(u.u_ssav);

1906               xswap(rpp, 0, 0);

1907               rpp->p_flag =| SSWAP;

1908               rip->p_stat = SRUN;

  • 若分配空间失败
    • 父进程置状态置为SIDL,接下来将会把父进程图像复制到盘交换区上,在此期间父进程不能被选中上台
    • 子进程ppda区指向父进程ppda区首址
    • 将R5,R6保存到u.u_ssav[2]数组中
    • 在盘交换区上复制一份父进程图像的副本
    • 子进程置SSWAP标识,恢复时直接从u.u_ssav[2]数组中恢复R5,R6
    • 将父进程置为就绪态,可以被调度进程选中上台
1909     } else {

1910     /*

1911     * There is core, so just copy.

1912     */

1913               rpp->p_addr = a2;

1914               while(n--)

1915                     copyseg(a1++, a2++);

  • 若分配空间成功
    • 则直接将父进程的图像拷贝一份到新分配的内存空间
1916     }

1917     u.u_procp = rip;

  • 恢复父进程上台
1918     return(0);
  • 此处为父进程的返回处,返回值为0
  • 子进程将会在swtch中被选中上台后直接从swtch中返回,返回值为1
1919 }

1920 /* ------------------------- */

Extend

附图

Ref

Caller

⚠️ **GitHub.com Fallback** ⚠️