Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекція № 4_МЗКІТ (10 ТП).docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2 Мб
Скачать
☆

7.5. Завершення процесу

Для завершення процесу в UNIX-системах використовують системний виклик

_exit( ). Розглянемо реалізацію цього системного виклику в Linux. Під час його виконання відбуваються такі дії.

1. Стан процесу стає TASK Z0MBIE (зомбі, про цей стан див. нижче).

2. Процес повідомляє предків і нащадків про те, що він завершився (за допомогою спеціальних сигналів).

3. Звільняються ресурси, виділені під час виклику fork( ).

4.Планувальника повідомляють про те, що контекст можна перемикати.

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

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

7.7. Запуск програми

Запуск нових програм в UNIX відокремлений від створення процесів і реалізований за допомогою системних викликів сімейства еxeс( ). На практиці звичайно реалізують один виклик (у Linux це — execve( )),

У Linux підтримують концепцію оброблювачів двійкових форматів (binary format handlers). Формати виконуваних файлів заздалегідь реєструють в ядрі, при цьому їхній набір може динамічно змінюватися. З кожним форматом пов’язаний оброблювач — спеціальна структура даних linux_binfmt, що містить покажчики на процедури завантаження виконуваного файла (1oad_binary) і динамічної бібліотеки (load_shlib) для цього формату.

Тепер зупинимося на послідовності кроків виконання execve( ) у Linux. Вхідними параметрами цього виклику є рядок з ім’ям виконуваного файла програми, масив аргументів командного рядка (до яких у коді процесу можна буде дістати доступ за допомогою масиву argv) і масив змінних оточення (що є парами ім’я=значення). Виклик execve( ) відбувається так.

1. Відкривають виконуваний файл програми.

2. Використовуючи вміст цього файла, ініціалізують спеціальну структуру даних bprm, що містить інформацію, необхідну для виконання файла, зокрема відомості про його двійковий формат.

3. Виконують дії для забезпечення безпеки виконання коду.

4. На базі параметрів виклику формують командний рядок і набір змінних оточення програми (це спеціальні поля структури bprm).

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

а) у разі коректного завантаження оброблювач починає виконувати код нової програми;

б) якщо жоден з оброблювачів не зміг коректно завантажити код, повертають помилку.

Детальному розгляду процесу завантаження програмного коду в пам’ять і форматів виконуваних файлів буде присвячено окрема лекція.

Запуск виконуваних файлів у прикладних програмах

Розглянемо приклад запуску виконуваного файла за допомогою системного виклику execve( ). Синтаксис цього виклику такий:

Останнім елементом argv і envp має бути нульовий покажчик.

Повернення з виклику буде тільки тоді, коли програму не вдалося завантажити (наприклад, файл не знайдено). Тоді буде повернено - 1.

Наведемо приклад формування параметрів і виклику (зазначимо, що першим елементом argv задане ім’я виконуваної програми):

Реалізація технології fork+exec

Наведемо приклад коду, що реалізує технологію fork+exec: