Як Linux "вбиває" процес?


91

Мене часто бентежить те, що, хоча я впродовж кількох десятиліть професійно працюю з комп’ютерами та Linux, я фактично трактую більшість функцій ОС як чорну скриньку, не на відміну від магії.

Сьогодні я подумав про killкоманду, і хоча я використовую її кілька разів на день (і в її «нормальному», і в -9смаковому), я повинен визнати, що я абсолютно не маю уявлення, як це працює за кадром.

З моєї точки зору, якщо запущений процес "завис", я закликаю killйого PID, і він раптом більше не працює. Магія!

Що там насправді відбувається? Manpages говорять про "сигнали", але, безумовно, це лише абстракція. Надіслати kill -9процес не вимагає співпраці процесу (як, наприклад, обробка сигналу), він просто знищує його.

  • Як Linux зупиняє процес продовження зайняття часу процесора?
  • Чи його видаляють із планування?
  • Чи відключається процес від його відкритих ручок файлів?
  • Як вивільняється віртуальна пам'ять процесу?
  • Чи є щось на зразок глобальної таблиці в пам’яті, де Linux зберігає посилання на всі ресурси, зайняті процесом, і коли я «вбиваю» процес, Linux просто проходить через цю таблицю і звільняє ресурси один за одним?

Я дуже хотів би це все знати!


Відповіді:


72

Надіслати kill -9 до процесу не вимагає співпраці процесу (наприклад, обробка сигналу), це просто вбиває його.

Ви припускаєте, що через те, що деякі сигнали можуть бути захоплені та проігноровані, усі вони передбачають співпрацю. Але відповідно до цього man 2 signal, " сигнали SIGKILL і SIGSTOP не можна вловлювати або ігнорувати". SIGTERM може бути спійманий, тому звичайний killне завжди ефективний - як правило, це означає, що в обробнику процесу пішло не так. 1

Якщо процес не (або не може) визначити обробник для даного сигналу, ядро виконує дію за замовчуванням. У випадку SIGTERM і SIGKILL це припинення процесу (якщо його PID не дорівнює 1; ядро ​​не закінчиться init) 2, що означає, що його файлові ручки закриті, пам'ять повернута в системний пул, його батько отримує SIGCHILD, його сироту діти успадковуються інітом і т. д. так само, як ніби він покликав exit(див. man 2 exit). Процес більше не існує - якщо тільки він не закінчується зомбі, в цьому випадку він все ще перерахований в таблиці процесора ядра з деякою інформацією; це відбувається, коли його батько цього не робитьwaitі правильно поводитися з цією інформацією. Однак у зомбі-процесах більше немає виділеної їм пам’яті, і тому вони не можуть продовжувати виконувати.

Чи є щось на зразок глобальної таблиці в пам'яті, де Linux зберігає посилання на всі ресурси, зайняті процесом, і коли я "вбиваю" процес, Linux просто проходить через цю таблицю і звільняє ресурси один за одним?

Я думаю, що це досить точно. Фізична пам’ять відстежується за сторінками (одна сторінка зазвичай дорівнює шмату в 4 КБ), і ці сторінки беруться з і повертаються в глобальний пул. Трохи складніше те, що деякі звільнені сторінки кешуються у випадку, якщо дані, які вони містять, знову потрібні (тобто дані, які були прочитані з ще існуючого файлу).

Manpages говорять про "сигнали", але, безумовно, це лише абстракція.

Звичайно, всі сигнали - це абстракція. Вони концептуальні, як і "процеси". Я трохи граю в семантику, але якщо ви маєте на увазі, що SIGKILL якісно відрізняється від SIGTERM, то так і ні. Так, у тому сенсі, що його не можна зловити, але ні в тому сенсі, що вони є обома сигналами. За аналогією, яблуко не є апельсином, але яблука та апельсини, згідно заздалегідь визначеного визначення, є і фруктами. SIGKILL здається більш абстрактним, оскільки ви не можете його зловити, але це все-таки сигнал. Ось приклад поводження з системою SIGTERM, я впевнений, що ви їх бачили і раніше:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sighandler (int signum, siginfo_t *info, void *context) {
    fprintf (
        stderr,
        "Received %d from pid %u, uid %u.\n",
        info->si_signo,
        info->si_pid,
        info->si_uid
    );
}

int main (void) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = sighandler;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGTERM, &sa, NULL);
    while (1) sleep(10);
    return 0;
}

Цей процес просто спатиме вічно. Ви можете запустити його в терміналі і надіслати його SIGTERM kill. Він випльовує такі речі, як:

Received 15 from pid 25331, uid 1066.

1066 - мій UID. PID - це оболонка оболонки, з якої killвиконується, або PID вбивства, якщо ви розщедрили його ( kill 25309 & echo $?).

Знову ж таки, немає сенсу встановлювати обробник для SIGKILL, оскільки він не працюватиме. 3 Якщо я kill -9 25309процес закінчуватимуться. Але це все-таки сигнал; в ядрі є інформація про те, хто подав сигнал , який це сигнал тощо.


1. Якщо ви не переглянули список можливих сигналів , див kill -l.

2. Інший виняток, як згадує Тім Пост нижче, стосується процесів у режимі безперебійного сну . Їх неможливо прокинути, поки не буде вирішено основну проблему, і таким чином не буде відкладено ВСІ сигнали (включаючи SIGKILL) на тривалість. Однак процес не може створити цю ситуацію спеціально.

3. Це не означає, що використання kill -9на практиці краще робити. Мій обробник прикладу поганий у тому сенсі, до якого він не призводить exit(). Справжня мета обробника SIGTERM - надати процесу можливість виконувати такі дії, як очищення тимчасових файлів, а потім добровільно вийти. Якщо ви користуєтеся kill -9, це не дає цього шансу, тому робіть це лише тоді, якщо частина "виходу добровільно", здається, не вдалася.


Гаразд, але що вбиває процес, -9тому що це справжня проблема, як хто хоче, що цей повинен померти! ;)
Ківі

@Kiwy: Ядро. IPC, включаючи сигнали, проходять через нього; ядро реалізує дії за замовчуванням.
золотинки

12
Можливо, варто згадати, що сон (D) випереджає всі сигнали, поки процес знаходиться в такому стані. Отже, спроба kill -9певних процесів, пов'язаних введення-виводу, не спрацює, принаймні, не відразу.
Тім Пост

7
Я додам, що оскільки його kill -9неможливо зловити, процес його отримання не може виконати будь-яку очистку (наприклад, видалення тимчасових файлів, звільнення спільної пам'яті тощо) до її виходу. Отже, використовувати kill -9(ака kill -kill) лише в крайньому випадку. Почніть з kill -hupа / або kill -termспочатку, а потім використовуйте kill -killяк заключний удар.
JRFerguson

"Процес більше не існує - якщо він не закінчується зомбі, і в цьому випадку він все ще перерахований в таблиці процесора ядра з деякою інформацією", насправді всі процеси переходять у стан зомбі, коли вони вмирають, а зомбі зникає, коли батьків не чекає на дитину, як правило, це відбувається занадто швидко, щоб ви побачили це
розумний

3

Кожен процес працює за запланованим часом, а потім переривається апаратним таймером, щоб дати йому ядро ​​CPU для інших завдань. Ось чому можливо мати набагато більше процесів, ніж ядер процесора, або навіть запустити всю операційну систему з великою кількістю процесів на одному ядрі процесора.

Після того як процес буде перервано, елемент керування повертається до коду ядра. Цей код може потім прийняти рішення не продовжувати виконання перерваного процесу без будь-якої співпраці з боку процесу. kill -9 може призвести до виконання у будь-якому рядку вашої програми.


0

Ось ідеалізований опис того, як працює процес убивства. На практиці будь-який варіант Unix матиме багато додаткових ускладнень та оптимізацій.

Ядро має структуру даних для кожного процесу, яка зберігає інформацію про те, яку пам’ять воно відображає, які потоки у нього є і коли вони заплановані, які файли у нього відкриті і т. Д. Якщо ядро ​​вирішить вбити процес, він робить помітку в структура даних процесу (і, можливо, в структурі даних кожного з потоків), яку слід вбити.

Якщо один з потоків процесу запланований в іншому процесорі, ядро ​​може спровокувати перерву в іншому процесорі, щоб змусити цей потік швидше припинити виконання.

Коли планувальник помічає, що нитка знаходиться в процесі, який потрібно вбити, він більше не планує її.

Коли жоден з потоків процесу вже не запланований, ядро ​​починає звільняти ресурси процесу (пам'ять, дескриптори файлів,…). Кожен раз, коли ядро ​​звільняє ресурс, воно перевіряє, чи є у його власника ще живі ресурси. Після того, як у процесу немає більше живого ресурсу (відображення пам’яті, дескриптор відкритого файлу,…), структуру даних самого процесу можна звільнити і відповідну запис можна видалити з таблиці процесів.

Деякі ресурси можна негайно звільнити (наприклад, оперативна пам'ять, яка не використовується операцією вводу / виводу). Інші ресурси повинні зачекати, наприклад, дані, що описують операцію вводу / виводу, не можуть бути звільнені, поки операція вводу / виводу виконується (поки DMA виконується, використовується пам'ять, до якої вона звертається, а для скасування DMA потрібна контактуючи з периферією). Драйвер про такий ресурс повідомляється і може спробувати поспішити скасування; як тільки операція більше не виконується, драйвер завершить звільнення цього ресурсу.

(Запис у таблицю процесів - це насправді ресурс, що належить до батьківського процесу, який звільняється, коли процес гине, і батьків визнає подію .)

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