Реализация вилки - PullRequest
       39

Реализация вилки

9 голосов
/ 14 января 2012

Как пишется код системного вызова fork.Я хочу знать некоторые детали, как функция может возвращать два разных значения, а два разных процесса.Короче хотите узнать как реализован системный вызов fork?

Ответы [ 4 ]

10 голосов
/ 14 января 2012

Вы в значительной степени объяснили это, сказав, что это системный вызов.Работа всей операционной системы заключается в том, чтобы выполнять всю эту работу, и операционная система может в значительной степени делать все, что она хочет, вне контекста вашей программы или правил того языка, на котором вы ее реализуете. Вот простой пример того, как она можетслучается:

  1. Программные вызовы fork() системный вызов
  2. Системный вызов fork fork дублирует процесс, выполняющий программу
  3. Ядро устанавливает возвращаемое значение для системного вызовадля исходной программы и для дубликата (PID дубликата и 0 соответственно)
  4. Ядро помещает оба процесса в очередь планировщика
  5. Когда каждый процесс запланирован, ядро ​​"возвращает"к каждой из двух программ.
9 голосов
/ 21 августа 2014

Карл ответил великолепно. Я хотел бы добавить, что во многих операционных системах возвращаемые значения передаются в один из регистров. В архитектуре x86 этот регистр может быть eax, в архитектуре ARM этот регистр может быть R0 и т. Д.

Каждый процесс также имеет блок управления процессом (PCB), в котором хранятся значения регистров в тот момент, когда произошло какое-то прерывание, системный вызов или исключение, и управление было передано в ОС. В следующий раз, когда запланирован процесс, значения регистров восстанавливаются с печатной платы.

Теперь, когда происходит fork (), ОС может сделать:

 child_process->PCB[return_value_register] = 0;
 parrent_process->PCB[return_value_register] = child_pid;

Итак, когда процессы перепланированы, каждый из них видит различное возвращаемое значение.

В качестве примера вы можете увидеть реализацию xv6 для fork . Там родительский процесс все еще находится в рабочем состоянии, поэтому он возвращает возвращаемое значение родителя с помощью простого оператора возврата. Но он устанавливает значение регистра EAX для дочернего процесса равным 0, поэтому, когда дочерний процесс запланирован, он видит 0 в качестве возвращаемого значения:

// Clear %eax so that fork returns 0 in the child.
np->tf->eax = 0;

Обратите внимание, что return 0 также будет компилироваться во что-то вроде "mov eax, 0".

Обновление: Я только что реализовал fork () для хобби ОС, которой занимаюсь. Вы можете увидеть исходный код здесь .

3 голосов
/ 14 января 2012

В буклете с исходным кодом Unix V6 для университетов есть комментарий, который комментируют сами Кен Томпсон и Деннис Ритчи, описывающий, как на самом деле работает двойной возврат.Комментарий заканчивается следующим предложением:

Вы не должны понимать это.

0 голосов
/ 14 января 2012

Например, процесс клонируется в функции fork() с регистрацией Moving IP / EIP / RIP , чтобы пропустить некоторые инструкции в функциях, которые могут выглядеть следующим образом:

return pid;
return 0;

Первый процесс выполнит первую инструкцию и функцию pop из стека, второй процесс запустится, но из второй инструкции вернется 0.

...