Разработка ядра Linux | страница 38
Далее происходит возврат в функцию >do_fork()
. Если возврат из функции >copy_process()
происходит успешно, то новый порожденный процесс возобновляет выполнение. Порожденный процесс намеренно запускается на выполнение раньше родительского[16].
В обычной ситуации, когда порожденный процесс сразу же вызывает функцию >exec()
, это позволяет избежать накладных расходов, связанных с тем, что если родительский процесс начинает выполняться первым, то он будет ожидать возможности записи в адресное пространство посредством механизма копирования при записи.
>vfork()
Системный вызов >vfork()
позволяет получить тот же эффект, что и системный вызов >fork()
, за исключением того, что записи таблиц страниц родительского процесса не копируются. Вместо этого порожденный процесс запускается как отдельный поток в адресном пространстве родительского процесса и родительский процесс блокируется до того момента, пока порожденный процесс не вызовет функцию >exec()
или не завершится. Порожденному процессу запрещена запись в адресное пространство. Такая оптимизация была желанной в старые времена 3BSD, когда реализация системного вызова >fork()
не базировалась на технике копирования страниц памяти при записи. Сегодня, при использовании техники копирования страниц памяти при записи и запуске порожденного процесса перед родительским, единственное преимущество вызова >vfork()
— это отсутствие копирования таблиц страниц родительского процесса. Если когда-нибудь в операционной системе Linux будет реализовано копирование полей таблиц страниц при записи[17], то вообще не останется никаких преимуществ. Поскольку семантика функции >vfork()
достаточно ненадежна (что, например, будет, если вызов >exec()
завершится неудачно?), то было бы здорово, если бы системный вызов >vfork()
умер медленной и мучительной смертью. Вполне можно реализовать системный вызов >vfork()
через обычный вызов >fork()
, что действительно имело место в ядрах Linux до версии 2.2.
Сейчас системный вызов >vfork()
реализован через специальный флаг в системном вызове >clone()
, как показано ниже.
• При выполнении функции >copy_process()
поле >vfork_done
структуры >task_struct
устанавливается в значение >NULL
.
• При выполнении функции >do_fvork()
, если соответствующий флаг установлен, поле >vfork_done
устанавливается в ненулевое значение (начинает указывать на определенный адрес).
• После того как порожденный процесс в первый раз запущен, родительский процесс, вместо того чтобы возвратиться из функции