Разработка ядра 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 устанавливается в ненулевое значение (начинает указывать на определенный адрес).

• После того как порожденный процесс в первый раз запущен, родительский процесс, вместо того чтобы возвратиться из функции