Чому дитина vfork або fork повинен викликати _exit () замість exit ()?


12

З чоловічої сторінки vfork():

vfork () відрізняється від fork () тим, що батько призупиняється, поки дитина не викличе виконувати (2) або _exit (2). Дитина ділиться всією пам’яттю зі своїм батьком, включаючи стек, доки дитина не видасть execve (). Дитина не повинна повертатися з поточної функції або виклику виходу (), але може викликати _exit ().

Чому дитина повинна _exit()скоріше використовувати просто дзвінки exit()? Я сподіваюся, що це стосується і обох, vfork()і fork().


2
якщо ви зацікавлені в більш ранньому обговоренні онтоп-ності викликів API Unix C
xenoterracide

Відповіді:


11

Як було показано раніше , vforkне дозволяє дочірньому процесу отримати доступ до пам'яті батьків. exit- це функція бібліотеки С (тому її часто записують як exit(3)). Він виконує різні завдання очищення, такі як промивання та закриття потоків С (файли відкриваються через функції, оголошені в stdio.h) та виконання визначених користувачем функцій, зареєстрованих у atexit. Усі ці завдання включають читання та запис у пам'ять процесу.

_exitвиходить без очищення. Це безпосередньо системний виклик (саме тому він записаний як _exit(2)), як правило, реалізований шляхом розміщення номера системного виклику в регістрі процесора та виконання певної інструкції процесора (розгалуження на обробник системного виклику). Для цього не потрібно отримувати доступ до оперативної пам’яті, тому це безпечно робити після vfork.

Після forkцього такого обмеження не існує: процес батьків і дитини зараз повністю автономний.


vfork не дозволяє дочірньому процесу отримати доступ до пам'яті батьків ? Але я думав, що вони мають однаковий адресний простір, тому дитина може отримати доступ до адресного простору батьків. Чи було це розуміння неправильним?
Сен

Після роздрібнення такого обмеження не існує: процес батьків і дітей тепер повністю автономний. Чи означає це, що я можу викликати вихід () від дитини з вилки?
Сен

1
@Sen: Дитині заборонено отримувати доступ до пам'яті батьків. Якщо ви спробуєте це, це може спрацювати, тому що ядро ​​не захистить вас. Але ефект може бути не таким, який ви маєте намір; наприклад, якщо ваш компілятор вирішить залишити якесь значення в реєстрі, його батьківський процес не побачить.
Жил "ТАК - перестань бути злим"

@Sen: Після розщелки ви можете зробити вихід дзвінка або будь-яку іншу функцію. Кожен процес запускається після вилки (в Linux навіть початковий процес initроздвоєний ядром).
Жил "ТАК - перестань бути злим"

3

exitзробити додаткове очищення, як-от виклику функцій, зареєстрованих таким atexitчином, він отримує доступ до даних поза скопійованою частиною. _exitвиконує syscall безпосередньо без будь-якого очищення, крім внутрішнього ядра.


... і слід зазначити, що fork () копіює все, тому ви, можливо, зможете викликати exit (), і ви точно зможете повернутися з поточної функції.
дероберт

3

У вас є дочірній дзвінок _exit (), щоб уникнути промивання stdio (або інших) буферів, коли дочірній процес закінчується. Оскільки дочірній процес являє собою точну копію батьківського процесу, у дочірнього процесу все ще є те, що було у батьків у "stdout" або "stderr", буфери з <stdio.h>. Ви можете (і будете в невідповідний час) отримати подвійні результати, зателефонувавши до виходу (), одного з дочірнього обробника «atexit» і одного від батьківського, коли буфери в батьківському процесі заповнюються і розмиваються.

Я розумію, що наведена відповідь зосереджена на специфіці stdio.h, але ця ідея, ймовірно, переноситься на інші буферизовані введення-виведення, як вказує одна з наведених вище відповідей.


1

exit(): - виконує певну задачу очищення, наприклад, закриття потоків вводу-виводу та багатьох, а потім повертається до ядра. _exit(): - безпосередньо надходить до ядра (не виконайте жодного завдання очищення).

fork() : і батько, і дочірка мають різні файлові таблиці, тому зміни, здійснені дитиною, не впливають на параметри середовища батьків, і навпаки.

vfork(): і батько, і дочірка використовують однакову таблицю файлів, тому зміна, здійснена дитиною, впливає на параметри середовища батьків. наприклад, якась змінна var=10, тепер запущена var++дочірньою, а потім запущеною батьківською, ви також можете побачити ефект var++у висновку батьків.

Як я вже говорив , якщо ви використовуєте exit()в vfork()тому всім I / O вже закритий. Тож, навіть якщо батьків працює правильно, ви не зможете отримати належний вихід, тому що всі змінні змиваються, а всі потоки закриті.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.