Linux: процессы и сигналы
Процессы и fork/exec, состояния процессов, зомби и сироты и PID 1, сигналы, системные вызовы, файловые дескрипторы и поиск по PATH.
9 вопросов
JuniorТеорияОчень частоЧто такое сигнал и что делают SIGTERM, SIGKILL, SIGHUP и SIGSTOP?
Что такое сигнал и что делают SIGTERM, SIGKILL, SIGHUP и SIGSTOP?
Сигнал — это асинхронное уведомление, доставляемое ядром процессу. SIGTERM просит завершиться и может быть перехвачен для очистки; SIGKILL завершает принудительно и не перехватывается, не блокируется, не игнорируется; SIGHUP означает обрыв терминала и велит демонам перечитать конфиг; SIGSTOP ставит процесс на паузу (тоже неперехватываем), а SIGCONT возобновляет его.
Типичные ошибки
- ✗Думать, что
SIGKILLилиSIGSTOPможно перехватить или проигнорировать обработчиком - ✗Путать
SIGTERM(мягкий) сSIGKILL(принудительный) - ✗Читать
SIGSTOPкак завершение, а не сигнал паузы
Уточняющие вопросы
- →Какие два сигнала нельзя перехватить, заблокировать или проигнорировать и почему?
- →Почему многие демоны перечитывают конфиг по
SIGHUP, а не перезапускаются?
JuniorТеорияОчень частоЧто такое процесс и что делают fork и exec?
Что такое процесс и что делают fork и exec?
Процесс — это работающий экземпляр программы со своим PID, родительским PID (PPID), приватным виртуальным адресным пространством и таблицей открытых файловых дескрипторов. fork клонирует вызвавшего в почти идентичного потомка через copy-on-write; exec затем заменяет образ памяти этого потомка новой программой, сохраняя тот же PID.
Типичные ошибки
- ✗Считать
forkиexecодним вызовом, а не парой «клонировать, затем заменить» - ✗Думать, что
execзапускает новый PID, а не переиспользует PID вызвавшего - ✗Полагать, что потомок делит записываемую память родителя, а не copy-on-write
Уточняющие вопросы
- →Почему copy-on-write делает
forkдешёвым даже для крупного родительского процесса? - →Что потомок наследует от родителя при
forkпомимо памяти?
JuniorТеорияЧастоЧто такое файловый дескриптор и что такое дескрипторы 0, 1 и 2?
Что такое файловый дескриптор и что такое дескрипторы 0, 1 и 2?
Файловый дескриптор — это небольшое неотрицательное целое, которым процесс ссылается на открытый файл, сокет или канал — индекс в его таблице открытых хендлов. По соглашению дескриптор 0 — стандартный ввод, 1 — стандартный вывод, 2 — стандартный поток ошибок. Перенаправления и каналы просто перекоммутируют эти номера, поэтому 2>&1 шлёт stderr туда, куда указывает stdout.
Типичные ошибки
- ✗Менять местами роли дескриптора 1 (stdout) и 2 (stderr)
- ✗Думать, что дескриптор хранит строку пути, а не индекс в таблице
- ✗Считать дескрипторы глобальными, а не привязанными к процессу
Уточняющие вопросы
- →Что перенаправление
2>&1на самом деле делает с таблицей дескрипторов? - →Почему файл, удалённый при ещё открытом дескрипторе, продолжает занимать диск?
JuniorТеорияЧастоЧто означают состояния процессов Linux R, S, D, T и Z?
Что означают состояния процессов Linux R, S, D, T и Z?
R — выполняется или готов к выполнению (на CPU или в очереди). S — прерываемый сон: ждёт события и пробуждается сигналом. D — непрерываемый сон, обычно заблокирован в ядерном вызове ввода-вывода и не убиваемый, пока тот не вернётся. T — остановлен сигналом вроде SIGSTOP. Z — зомби: завершился, но ещё не собран родителем.
Типичные ошибки
- ✗Путать
D(непрерываемый сон) с обычным сномS, которому можно послать сигнал - ✗Думать, что зомби
Zвсё ещё работает и потребляет CPU - ✗Читать
T(остановлен) как завершённый, а не приостановленный сигналом
Уточняющие вопросы
- →Почему процесс в состоянии
Dнельзя убить даже черезSIGKILL? - →Чем зомби
Zотличается от процесса в состоянииT?
MiddleТеорияЧастоЧто такое зомби-процесс, кто его создаёт и как его убрать?
Что такое зомби-процесс, кто его создаёт и как его убрать?
Зомби — это процесс, который завершился, но его родитель ещё не сделал wait(), поэтому ядро держит крошечную запись лишь с PID и кодом выхода. Он уже мёртв — kill -9 зомби не работает. Он исчезает, когда родитель его собирает (часто после SIGCHLD); если родитель этого не делает, завершение родителя не оставляет ничего, но позволяет init собрать его.
Типичные ошибки
- ✗Пытаться
kill -9зомби, который уже мёртв и не может быть убит - ✗Думать, что зомби держит память, а не только PID и код выхода
- ✗Винить сбежавший процесс вместо родителя, который не собирает потомков
Уточняющие вопросы
- →Почему завершение родителя даёт init в итоге собрать зомби?
- →Чем зомби отличается от процесса-сироты?
MiddleТеорияИногдаЧто такое процесс-сирота и кто его усыновляет и собирает?
Что такое процесс-сирота и кто его усыновляет и собирает?
Сирота — это ещё живой процесс, родитель которого завершился. Ядро переусыновляет его к init (PID 1), который становится новым родителем и позже делает wait() при его выходе, поэтому сирота не превращается в зомби. Вот почему PID 1 обязан собирать потомков — наивный init контейнера, игнорирующий SIGCHLD, копит зомби из усыновлённых сирот.
Типичные ошибки
- ✗Путать сироту (жив, переусыновлён) с зомби (мёртв, не собран)
- ✗Думать, что сирота висит вечно, а не усыновляется к init
- ✗Упускать, что PID 1 обязан собирать
SIGCHLD, иначе контейнер копит зомби
Уточняющие вопросы
- →Почему контейнер работает лучше с настоящим init вроде
--initили tini? - →Что происходит с PPID сироты после переусыновления ядром?
MiddleДебаггингИногдаПроцесс в состоянии D игнорирует kill -9 — почему и что делать
Процесс в состоянии D игнорирует kill -9 — почему и что делать
D — это непрерываемый сон: процесс заблокирован внутри ядерного вызова — здесь dd ждёт отказывающий диск. SIGKILL ставится в очередь, но не доставляется, пока вызов не вернётся, поэтому kill -9 бездействует, пока он висит. Убить силой нельзя; почините ввод-вывод (больное устройство, NFS, хранилище), чтобы вызов разблокировался и процесс вышел — иначе перезагрузка хоста.
Типичные ошибки
- ✗Упорнее слать
kill -9, когда процесс вDпока не может его получить - ✗Принимать непрерываемый сон за зомби или перехват сигнала обработчиком
- ✗Игнорировать настоящую причину — застрявший диск, NFS или ввод-вывод устройства
Уточняющие вопросы
- →Как определить, на каком устройстве или монтировании процесс заблокирован?
- →Почему ядро вообще использует непрерываемый сон для части ввода-вывода?
JuniorТеорияРедкоЧто такое PATH и как шелл находит, какой бинарник запустить?
Что такое PATH и как шелл находит, какой бинарник запустить?
PATH — это переменная окружения со списком каталогов через двоеточие. Для простой команды вроде ls шелл ищет по этим каталогам слева направо и запускает первый подходящий исполняемый файл, поэтому порядок важен. Команда со слешем (./app, /usr/bin/ls) пропускает поиск целиком. which показывает, какой файл победит.
Типичные ошибки
- ✗Думать, что шелл ищет по
PATHкоманду, записанную со слешем - ✗Забывать, что
PATHсканируется слева направо, поэтому порядок решает - ✗Считать, что
PATHзадаёт один каталог, а не список через двоеточие
Уточняющие вопросы
- →Почему помещать
.в началоPATH— угроза безопасности? - →Чем различаются
which,typeи хеш-кеш шелла при разрешении команды?
JuniorТеорияРедкоЧто такое системный вызов и как программа переходит в ядро?
Что такое системный вызов и как программа переходит в ядро?
Системный вызов — это контролируемая точка входа, через которую программа просит у ядра что-то привилегированное — прочитать файл, открыть сокет, сделать fork. Программа не может трогать железо напрямую, поэтому она инициирует trap (специальную инструкцию вроде syscall), которая переключает CPU в режим ядра, выполняет обработчик и возвращает результат в пользовательский режим.
Типичные ошибки
- ✗Считать, что системный вызов выполняется в пользовательском режиме как обычная функция
- ✗Полагать, что программа может обращаться к железу минуя ядро
- ✗Упускать trap и смену режима CPU, которые выполняет системный вызов
Уточняющие вопросы
- →Почему смена режима делает системный вызов дороже обычного вызова?
- →Как библиотека C
libcвстаёт между вашим кодом и сырым системным вызовом?