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. }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章