fork()函数的主要实现(1)

 
  1. // 复制进程。
  2. int
  3. copy_process (int nr, long ebp, long edi, long esi, long gs, long none,
  4.           long ebx, long ecx, long edx,
  5.           long fs, long es, long ds,
  6.           long eip, long cs, long eflags, long esp, long ss)
  7. {
  8.   struct task_struct *p;
  9.   int i;
  10.   struct file *f;
  11.   p = (struct task_struct *) get_free_page ();  // 为新任务数据结构分配内存。
  12.   if (!p)           // 如果内存分配出错,则返回出错码并退出。
  13.     return -EAGAIN;
  14.   task[nr] = p;         // 将新任务结构指针放入任务数组中。
  15. // 其中nr 为任务号,由前面find_empty_process()返回。
  16.   *p = *current;        /* NOTE! this doesn't copy the supervisor stack */
  17. /* 注意!这样做不会复制超级用户的堆栈 */ (只复制当前进程内容)。
  18.     p->state = TASK_UNINTERRUPTIBLE;    // 将新进程的状态先置为不可中断等待状态。
  19.   p->pid = last_pid;        // 新进程号。由前面调用find_empty_process()得到。
  20.   p->father = current->pid; // 设置父进程号。
  21.   p->counter = p->priority;
  22.   p->signal = 0;        // 信号位图置0。
  23.   p->alarm = 0;
  24.   p->leader = 0;        /* process leadership doesn't inherit */
  25. /* 进程的领导权是不能继承的 */
  26.   p->utime = p->stime = 0;  // 初始化用户态时间和核心态时间。
  27.   p->cutime = p->cstime = 0;    // 初始化子进程用户态和核心态时间。
  28.   p->start_time = jiffies;  // 当前滴答数时间。
  29. // 以下设置任务状态段TSS 所需的数据(参见列表后说明)。
  30.   p->tss.back_link = 0;
  31.   p->tss.esp0 = PAGE_SIZE + (long) p;   // 堆栈指针(由于是给任务结构p 分配了1 页
  32. // 新内存,所以此时esp0 正好指向该页顶端)。
  33.   p->tss.ss0 = 0x10;        // 堆栈段选择符(内核数据段)[??]。
  34.   p->tss.eip = eip;     // 指令代码指针。
  35.   p->tss.eflags = eflags;   // 标志寄存器。
  36.   p->tss.eax = 0;
  37.   p->tss.ecx = ecx;
  38.   p->tss.edx = edx;
  39.   p->tss.ebx = ebx;
  40.   p->tss.esp = esp;
  41.   p->tss.ebp = ebp;
  42.   p->tss.esi = esi;
  43.   p->tss.edi = edi;
  44.   p->tss.es = es & 0xffff;  // 段寄存器仅16 位有效。
  45.   p->tss.cs = cs & 0xffff;
  46.   p->tss.ss = ss & 0xffff;
  47.   p->tss.ds = ds & 0xffff;
  48.   p->tss.fs = fs & 0xffff;
  49.   p->tss.gs = gs & 0xffff;
  50.   p->tss.ldt = _LDT (nr);   // 该新任务nr 的局部描述符表选择符(LDT 的描述符在GDT 中)。
  51.   p->tss.trace_bitmap = 0x80000000;
  52.   (高16 ?挥行В?
  53. // 如果当前任务使用了协处理器,就保存其上下文。
  54.     if (last_task_used_math == current)
  55.     __asm__ ("clts ; fnsave %0"::"m" (p->tss.i387));
  56. // 设置新任务的代码和数据段基址、限长并复制页表。如果出错(返回值不是0),则复位任务数组中
  57. // 相应项并释放为该新任务分配的内存页。
  58.   if (copy_mem (nr, p))
  59.     {               // 返回不为0 表示出错。
  60.       task[nr] = NULL;
  61.       free_page ((long) p);
  62.       return -EAGAIN;
  63.     }
  64. // 如果父进程中有文件是打开的,则将对应文件的打开次数增1。
  65.   for (i = 0; i < NR_OPEN; i++)
  66.     if (f = p->filp[i])
  67.       f->f_count++;
  68. // 将当前进程(父进程)的pwd, root 和executable 引用次数均增1。
  69.   if (current->pwd)
  70.     current->pwd->i_count++;
  71.   if (current->root)
  72.     current->root->i_count++;
  73.   if (current->executable)
  74.     current->executable->i_count++;
  75. // 在GDT 中设置新任务的TSS 和LDT 描述符项,数据从task 结构中取。
  76. // 在任务切换时,任务寄存器tr 由CPU 自动加载。
  77.   set_tss_desc (gdt + (nr << 1) + FIRST_TSS_ENTRY, &(p->tss));
  78.   set_ldt_desc (gdt + (nr << 1) + FIRST_LDT_ENTRY, &(p->ldt));
  79.   p->state = TASK_RUNNING;  /* do this last, just in case */
  80. /* 最后再将新任务设置成可运行状态,以防万一 */
  81.   return last_pid;      // 返回新进程号(与任务号是不同的)。
  82. }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值