Під час виклику vfork()
створюється новий процес, який новий процес запозичує зображення процесу батьківського процесу за винятком стека. Дочірньому процесу надається власна нова зірка стека, однак це не дозволяє виконувати return
функцію, яка викликала vfork()
.
Поки дитина працює, батьківський процес блокується, оскільки дитина запозичила адресний простір батьків.
Незалежно від того, що ви робите, все, що тільки отримує доступ до стека, змінює лише приватний стек дитини. Якщо ви змінюєте глобальні дані, це змінює загальні дані і, таким чином, впливає на батьків.
Речі, що змінюють глобальні дані, наприклад:
виклик malloc () або free ()
використовуючи stdio
зміни параметрів сигналу
модифікація змінних, які не є локальними для функції, що викликала vfork()
.
...
Після того, як ви телефонуєте _exit()
(важливо, ніколи не дзвоніть exit()
), дитина припиняється і контроль передається батькові.
Якщо ви викликаєте будь-яку функцію з exec*()
сім'ї, створюється новий адресний простір з новим програмним кодом, новими даними та частиною стека від батьків (див. Нижче). Після того, як це буде готово, дитина більше не запозичує адресний простір у дитини, а використовує власний адресний простір.
Елемент управління повертається батьківському, оскільки його адресний простір більше не використовується іншим процесом.
Важливо: На Linux немає реальної vfork()
реалізації. Linux, скоріше, реалізує vfork()
на основі fork()
концепції Copy on Write, запровадженої SunOS-4.0 у 1988 році. Для того, щоб змусити користувачів вважати, що вони користуються vfork()
, Linux просто налаштовує спільні дані та призупиняє батьків, поки дитина не дзвонила _exit()
чи одна з exec*()
функцій.
Отже, Linux не отримує користі від того, що реальному vfork()
не потрібно встановлювати опис адресного простору для дитини в ядрі. Це призводить до того, vfork()
що це не швидше, ніж fork()
. У системах, що реалізують реальне vfork()
, зазвичай це в 3 рази швидше fork()
та впливає на продуктивність оболонок, які використовують vfork()
- ksh93
, недавні Bourne Shell
та csh
.
Причина , чому ви ніколи не повинні викликати exit()
з vfork()
ед дитини є те , що exit()
флеші STDIO в разі , якщо є дані промиватися від часу перед викликом vfork()
. Це може спричинити дивні результати.
BTW: posix_spawn()
реалізується поверх vfork()
, тому vfork()
його не збирається видаляти з ОС. Згадано, що Linux не використовує vfork()
для posix_spawn()
.
Для стека є мало документації, ось що говорить сторінка Solaris man:
The vfork() and vforkx() functions can normally be used the
same way as fork() and forkx(), respectively. The calling
procedure, however, should not return while running in the
child's context, since the eventual return from vfork() or
vforkx() in the parent would be to a stack frame that no
longer exists.
Тож реалізація може робити все, що завгодно. Реалізація Solaris використовує спільну пам'ять для кадру стека виклику функції vfork()
. Жодна реалізація не надає доступу до старших частин стека від батьків.