Коли процес перебуває в режимі користувача, його можна перервати в будь-який час (перехід у режим ядра). Коли ядро повертається в користувальницький режим, воно перевіряє, чи є якісь сигнали, що очікують (включаючи сигнали, які використовуються для вбивства процесу, таких як SIGTERM
і SIGKILL
). Це означає, що процес можна вбити лише після повернення в режим користувача.
Причина, по якій процес не може бути вбитий в режимі ядра, полягає в тому, що він може потенційно пошкодити структури ядра, використовувані всі інші процеси в тій же машині (той же спосіб вбивства потоку може потенційно пошкодити структури даних, використовувані іншими потоками в тому ж процесі) .
Коли ядро потрібно зробити щось, що може зайняти тривалий час (очікування на трубі, написаній іншим процесом, або очікування, наприклад, апаратне забезпечення щось зробить), воно спить, позначивши себе як сплячий і закликаючи планувальник перейти на інший процес (якщо немає неспального процесу, він переходить на "фіктивний" процес, який спонукає процесор трохи сповільнитись і сидить у циклі - циклі очікування).
Якщо сигнал надсилається до сплячого процесу, його потрібно розбудити до того, як він повернеться до простору користувача і таким чином обробить сигнал, що очікує. Тут ми маємо різницю між двома основними типами сну:
TASK_INTERRUPTIBLE
, переривчастий сон. Якщо завдання позначено цим прапором, воно спить, але його можна прокинути за сигналами. Це означає, що код, який позначив завдання як сплячий, очікує можливого сигналу, і після його пробудження перевірить його та повернеться із системного дзвінка. Після обробки сигналу системний виклик потенційно може бути автоматично перезапущений (і я не буду вникати в деталі про те, як це працює).
TASK_UNINTERRUPTIBLE
, неперервний сон. Якщо завдання позначено цим прапором, воно не очікує, що його прокине щось інше, крім того, що його чекає, або тому, що його неможливо легко перезапустити, або тому, що програми очікують, що системний виклик буде атомним. Це також можна використовувати для сну, який, як відомо, дуже короткий.
TASK_KILLABLE
(згадується у статті LWN, пов'язаної з відповіддю ddaa) - це новий варіант.
Це відповідає на ваше перше запитання. Що стосується вашого другого питання: ви не можете уникнути безперебійного сну, вони звичайна річ (це відбувається, наприклад, кожного разу, коли процес читає / записує з / на диск); однак вони повинні тривати лише частку секунди. Якщо вони тривають набагато довше, зазвичай це означає апаратну проблему (або проблему з драйвером пристрою, яка схожа на ядро), де драйвер пристрою чекає, щоб апаратне забезпечення зробило щось, чого ніколи не відбудеться. Це також може означати, що ви використовуєте NFS і сервер NFS працює (він чекає, коли сервер відновиться; ви також можете скористатися параметром "intr", щоб уникнути проблеми).
Нарешті, причина, яку ви не можете відновити, - це та сама причина, коли ядро чекає, поки повернеться в режим користувача, щоб подати сигнал або вбиває процес: це потенційно може пошкодити структури даних ядра (код, який чекає в режимі сну, може отримати помилку, яка говорить про це повернутися в простір користувача, де процес може бути вбитий; код, який чекає у режимі безперебійного сну, не очікує жодної помилки).
TASK_UNINTERUPTIBLE
стан кожного разу, коли система не знаходиться в режимі очікування, тим самим примусово збираючи дані, чекаючи передачі, як тільки супер користувач вийде? Це було б золотим копачем для хакерів для отримання інформації, повернення до стану зомбі та передачі інформації через мережу в режимі очікування. Деякі можуть стверджувати, що це один із способів створитиBlackdoor
повноваження, що є, ввести та вийти з будь-якої системи за бажанням. Я впевнений, що цю лазівку можна запечатати назавжди, усунувши `TASK_UNINTERUPTIB