Що таке безперебійний процес?


156

Іноді, коли я пишу програму в Linux, і вона виходить з ладу через якусь помилку, вона стане безперебійним процесом і продовжувати працювати назавжди, поки я не перезавантажую комп'ютер (навіть якщо я не вийду). Мої запитання:

  • Що змушує процес стати безперебійним?
  • Як я не можу це зробити?
  • Це, мабуть, німе питання, але чи є спосіб перервати його, не перезавантажуючи комп’ютер?

Чи можливо, що програма може бути написана для ініціювання процесу, який переходить у TASK_UNINTERUPTIBLEстан кожного разу, коли система не знаходиться в режимі очікування, тим самим примусово збираючи дані, чекаючи передачі, як тільки супер користувач вийде? Це було б золотим копачем для хакерів для отримання інформації, повернення до стану зомбі та передачі інформації через мережу в режимі очікування. Деякі можуть стверджувати, що це один із способів створити Blackdoorповноваження, що є, ввести та вийти з будь-якої системи за бажанням. Я впевнений, що цю лазівку можна запечатати назавжди, усунувши `TASK_UNINTERUPTIB
Nuuwski

2
Будь ласка, поділіться кодом?
знову

Відповіді:


198

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

Щоб зрозуміти, що це означає, вам потрібно зрозуміти поняття переривного системного виклику. Класичний приклад - це read(). Це системний виклик, який може зайняти тривалий час (секунди), оскільки може потенційно спричинити закручування жорсткого диска або переміщення головки. Протягом більшої частини цього часу процес буде спати, блокуючи апаратне забезпечення.

Поки процес спить у системному виклику, він може приймати асинхронний сигнал Unix (скажімо, SIGTERM), тоді відбувається таке:

  • Системні дзвінки завершуються передчасно і налаштовуються для повернення -EINTR до простору користувачів.
  • Обробник сигналу виконаний.
  • Якщо процес все ще працює, він отримує повернене значення від системного виклику, і він може зробити той самий виклик ще раз.

Повернення рано з системного виклику дозволяє коду простору користувача негайно змінити свою поведінку у відповідь на сигнал. Наприклад, чисто закінчуючи реакцію на SIGINT або SIGTERM.

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

LWN випустив приємну статтю, яка торкнулася цієї теми в липні.

Щоб відповісти на початкове запитання:

  • Як не допустити цього: з’ясуйте, який драйвер заподіює вам проблеми, або перестаньте використовувати, або станьте хакером ядра та виправте це.

  • Як вбити безперебійний процес без перезавантаження: якось змусити системний виклик припинити. Найчастіше найефективнішим способом зробити це без натискання на вимикач живлення - витягнути шнур живлення. Ви також можете стати хакером ядра та змусити драйвер використовувати TASK_KILLABLE, як пояснено у статті LWN.


31
Я витягнув шнур живлення на своєму ноутбуці, і він не працює, на жаль. ;-)
thecarpy

1
Це не EINTR замість EAGAIN? Також read () повертає -1 і errno встановлюється на помилку.
летальний

2
@Dexter: Ви справді не пропускаєте суть. Прочитайте статтю LWN: lwn.net/Articles/288056 . Ці проблеми викликані ледачими програмістами драйверів пристроїв, і їх потрібно зафіксувати в коді драйвера пристрою.
ddaa

4
@ddaa "Unix традиція (і, отже, майже всі програми) вважає, що файл зберігання файлів не є переривним сигналом. Змінити цю гарантію не було б безпечно чи практично". -> Це саме неправильна частина всього цього ІМО. Просто перервіть запит драйвера на читання / запис, і коли фактичний пристрій (жорсткий диск / мережева карта / тощо) доставить дані, ігноруйте його. Ядро ОС повинно бути зроблене таким чином, що розробник NO не може його викрутити.
Декстер

2
@ddaa Я знаю, що Linux не є мікроядром, хоча я не впевнений, яка частина мого коментаря пов'язана з цим ... І тоді, чи означає ваш коментар, що в операційній системі мікро-ядра немає проблем з тими "безперебійними" процесами? Тому що, якщо цього не відбувається, можливо, мені настав час стати шанувальником мікроядер ...: D
Dexter

49

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

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

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

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

  • TASK_INTERRUPTIBLE, переривчастий сон. Якщо завдання позначено цим прапором, воно спить, але його можна прокинути за сигналами. Це означає, що код, який позначив завдання як сплячий, очікує можливого сигналу, і після його пробудження перевірить його та повернеться із системного дзвінка. Після обробки сигналу системний виклик потенційно може бути автоматично перезапущений (і я не буду вникати в деталі про те, як це працює).
  • TASK_UNINTERRUPTIBLE, неперервний сон. Якщо завдання позначено цим прапором, воно не очікує, що його прокине щось інше, крім того, що його чекає, або тому, що його неможливо легко перезапустити, або тому, що програми очікують, що системний виклик буде атомним. Це також можна використовувати для сну, який, як відомо, дуже короткий.

TASK_KILLABLE (згадується у статті LWN, пов'язаної з відповіддю ddaa) - це новий варіант.

Це відповідає на ваше перше запитання. Що стосується вашого другого питання: ви не можете уникнути безперебійного сну, вони звичайна річ (це відбувається, наприклад, кожного разу, коли процес читає / записує з / на диск); однак вони повинні тривати лише частку секунди. Якщо вони тривають набагато довше, зазвичай це означає апаратну проблему (або проблему з драйвером пристрою, яка схожа на ядро), де драйвер пристрою чекає, щоб апаратне забезпечення зробило щось, чого ніколи не відбудеться. Це також може означати, що ви використовуєте NFS і сервер NFS працює (він чекає, коли сервер відновиться; ви також можете скористатися параметром "intr", щоб уникнути проблеми).

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


1
Помилка блокування файлової системи також є ймовірною причиною IME.
Тобу

3
Я не розумію всього цього. "ви не можете уникнути безперебійного сну" - хіба ОС може бути створена таким чином, що режим безперебійного сну просто не існує як стан? Тоді частина про корупцію - чи не може частина режиму ядра у самому процесі (або що-небудь МОЖЕ викликати пошкодження) не може бути припинена або просто його код змінено право в пам'яті, щоб просто повернутися? Поясніть, будь ласка, чому це так важко / неможливо зробити, що навіть Linux цього не зробив. (Я думав, ця проблема існує лише в Windows)
Dexter

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

@Dexter думає про ядро ​​так, ніби це єдиний багатопотоковий процес, де частина режиму ядра кожного процесу є потоком в ядрі. Ваша пропозиція була б такою ж поганою, як вбивство однієї нитки в багатопотоковій програмі: вона може залишати звисаючі блокування, структури даних тимчасово модифіковані або в середині модифіковані тощо.
CesarB

@CesarB добре, що ти маєш рацію вбити нитку ... Але чи не може "головний" потік (це було б ядро ​​ОС та інші потоки, наприклад, драйвери) якось впоратися з цим? Хоча ці структури "в середині модифікованих" здаються однією з справді важких проблем ... можливо, ми дійсно ніколи не побачимо ОС, де безперебійні процеси були б неможливі :(
Dexter

23

Процеси безперебійного використання НАЗВИЧНО чекають вводу / виводу після помилки сторінки.

Врахуйте це:

  • Потік намагається отримати доступ до сторінки, яка не є в ядрі (або виконуваного файлу, завантаженого попитом, сторінки анонімної пам'яті, яку було замінено, або файлу mmap (), завантаженого попитом, які значно більше однакові речі)
  • Ядро зараз (намагається) завантажити його
  • Процес не може тривати, поки сторінка не стане доступною.

Процес / завдання не можна перервати в цьому стані, оскільки він не може обробляти жодні сигнали; якби це сталося, сталася б інша помилка сторінки, і вона повернулася б там, де вона була.

Коли я кажу "обробляти", я дійсно маю на увазі "завдання", яке в Linux (2.6) приблизно перекладається на "потік", який може мати або не мати окремий запис "групи потоків" в / proc

У деяких випадках це може чекати довго. Типовим прикладом цього може бути те, коли виконуваний файл або файл mmap'd знаходиться в мережевій файловій системі, де сервер не вийшов з ладу. Якщо введення / виведення врешті-решт вдасться, завдання буде продовжено. Якщо це врешті-решт не вдасться, завдання, як правило, отримає SIGBUS або щось подібне.


1
Якщо це врешті-решт не вдасться, завдання, як правило, отримає SIGBUS або щось подібне. Зачекайте, чи не може бути створене ядро ​​так, що при знищенні цих "безперебійних" процесів він просто РОЗКАЄ їм операцію вводу / виводу? Тоді процес повернеться до режиму користувача і не піде? Існує спосіб безпечно вбити ці процеси "D". Я думаю, що це просто не просто, і тому ні Windows, ні Linux ще не мають такої можливості. З іншого боку, я хотів би мати можливість вбити ці процеси хоча б небезпечно. Мене не хвилює можливий збій системи чи що завгодно ...
Dexter

@Dexter Хм, я ніколи не відчував цієї проблеми з Windows. Який спосіб відтворити його там? Принаймні відповідно до цієї публікації , всі запити вводу / виводу можуть бути перервані в Windows.
Руслан

1

До вашого третього запитання: Я думаю, ви можете вбити безперебійні процеси, запустивши sudo kill -HUP 1. Він перезапустить init, не припиняючи запущених процесів, і після його запуску мої безперебійні процеси вже не було.


-3

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

Чи можете ви, будь ласка, описати, що таке "безперервний процес" для вас? Чи витримає він "вбивство -9" і радісно забиває? Якщо це так, то він застряг на деякому syscall, який застряг у якомусь драйвері, і ви застрягли в цьому процесі до перезавантаження (а іноді краще перезавантажити незабаром) або до вивантаження відповідного драйвера (що навряд чи станеться) . Ви можете спробувати використати "strace", щоб дізнатися, де ваш процес застряг, і уникнути цього в майбутньому.


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