Перейти к содержимому

Как чаще всего процессы обрабатывают сигнал term

  • автор:

IgorKa — Информационный ресурс

Немного обо всем и все о немногом, или практический опыт системного администратора.

Ноябрь 2009

Пн Вт Ср Чт Пт Сб Вс
« Окт Дек »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30

Лекция №13 Сигналы в Linux

Calendar

11 ноября 2009, 11:36

Прошлая лекция была посвящена процессам в Linux. Сегодня мы поговорим о взаимодействии процессом между собой, а также о том как мы можем воздействовать на процессы. Сначала посмотрим как процессы могу взаимодействовать между собой. Мы уже писали в командной строке конструкции подобные этой: less /etc/group | grep user . В этом примере процесс less взаимодействует с процессом grep посредством механизма, который называется неименований канал или пайп (pipe — канал). Мы не будем вдаваться в подробности, просто запомните, что посредством символа |, который можно в данном случае называть “пайпом” информация (результат выполнения) процесса less идет на вход другого процесса — grep. Таким образом один процесс передал информацию другому процессу.

Еще один способ общения процессов — это именованные каналы. Изучение именованный каналов не входит в этот курс, но на практическом примере расскажу, что это. Именованный канал можно создать командой mkfifo:

igor@adm-ubuntu:~/linux$ mkfifo my_pipe
igor@adm-ubuntu:~/linux$ ls -l | grep my_pipe
prw-r–r– 1 igor igor 0 2009-11-09 17:59 my_pipe

Теперь в одной консоли выполните команду:

igor@adm-ubuntu:~/linux$ echo Hello > my_pipe

Как видите команда не завершает свою работу, а ждет. Зарегистрируйтесь еще в одной консоли и выполните команду:

igor@adm-ubuntu:~/linux$ cat my_pipe
Hello

Если вернуться на первую консоль, то вы увидите, что команда echo завершила свою работу. Таким образом через именованный канал my_pipe команда (процесс) echo передала информацию (слово Hello) процессу cat, который ее принял и вывел на экран.

Давайте теперь рассмотрим основной способ “общения” процессов — сигналы. Один процесс при помощи ядра может передать другому процессу специальное числовое значение сигнала. Процесс вызывает функцию передачи сигнала и передает необходимую информацию (код сигнала, PID процесса) ядру. Ядро передает сигнал процессу получателю и отслеживает как этот сигнал обрабатывается. Сигналы обозначаются цифрами или мнемоническими обозначениями. Перечень сигналов можно вывести командой kill -l.

Мнемонические имена которые вы видите (SIGTERM, SIGINT, SIGKILL) начинаются с приставки SIG. Имена в этом виде используются в языках программирования таких как С. В интерпретаторе bash используются или числа или мнемонические имена, но без приставки SIGTERM, INT, KILL.

Часть сигналов (INT, TERM) являются перехватываемыми. Это означает, что процесс при получении такого сигнала должен перейти на специальную подпрограмму, которая занимается обработкой сигнала. Если подпрограммы обработки нет (а ее написанием занимаются разработчики программы, которая выполняется в контексте процесса), то управление передается ядру, которое выполняет действия по умолчанию, описанные для каждого сигнала.

Часть сигналов являются такими которые можно заблокировать. Например, один процесс посылает сигнал TERM другому процессу, а он в свою очередь не закончил операции ввода/вывода. В таком случае второй процесс может заблокировать полученный сигнал (опять таки в обработчике сигнала) до момента выполнения необходимой операции ввода/вывода. Сигнал TERM — это сигнал корректного завершения работы процесса. Обработчик этого сигнала, должен выполнить все необходимые действия для правильного завершения работы.

И есть третья группа сигналов, которые не блокируются и для которых не нужны обработчики. Примером такого сигнала является сигнал KILL. Этот сигнал уничтожает процесс, так как для него нет обработчиков в процессах, то он будет обрабатываться ядром по умолчанию и так как он не блокируемый, то действия будут выполнятся немедленно.

Пока мы говорили о том как процессы “общаются” между собой с помощью сигналов. Но мы (пользователи) также можем посылать сигналы процессам. Например, комбинация клавиш Ctrl+C посылает процессу сигнал INT, который прерывает выполнение процесса. Если вы наберете в терминале команду sleep 100, то команда не вернет управление терминалу пока не завершится. Прервать выполнение этой команды можно нажав комбинацию клавиш Ctrl+C.

В чем же отличия между похожими сигналами INT, TERM, KILL (а также QUIT и HUP)? Несмотря на похожесть отличия есть:

Сигнал KILL не блокируется и не перехватывается и ведет к немедленному завершению процесса.
Сигнал INT в отличии от KILL является блокируемым сигналом и перехватываемым.
Сигнал TERM также является перехватываемым и блокируемым и предназначен для корректного (предпочтительного) завершения работы процесса.
Сигнал QUIT — похож на TERM, но позволяет сохранить дамп памяти.
Сигнал HUP — сейчас этот сигнал чаще всего интерпретируется процессами как “прочесть конфигурационные файлы”.

Рассмотрим два сигнала: STOP и CONT. Сигнал STOP останавливает процесс, то есть процесс переходит в состояние “остановленный“. В таком состоянии процесс будет до тех пор пока снова не получит сигнал. Если будет получен сигнал CONT, то процесс возобновит свою работу с того момента как он был остановлен. Практический пример:

Наберите в терминале команду sleep 1000 &.

Затем проверьте, что процесс находится в состоянии ожидания, о чем нам говорит буква S в столбце STAT:

igor@ubuntu:~$ ps x | grep [s]leep
PID TTY STAT TIME COMMAND
6301 pts/1 S 0:00 sleep 1000

Теперь пошлем процессу сигнал STOP. Для этого используем команду kill (kill -название процесса PID процесса):

igor@ubuntu:~$ kill -STOP 6301
[1]+ Stopped sleep 1000

Проверяем статус процесса:

igor@ubuntu:~$ ps x | grep [s]leep
PID TTY STAT TIME COMMAND
6301 pts/1 T 0:00 sleep 1000

Видим, что процесс действительно находится в состоянии “остановленный” (символ T в столбце STAT).

Теперь отправим процессу сигнал продолжения работы (CONT) и проверим состояние:

igor@ubuntu:~$ kill -CONT 6301
igor@ubuntu:~$ ps x | grep [s]leep
PID TTY STAT TIME COMMAND
6301 pts/1 S 0:00 sleep 1000

Если необходимо корректно завершить процесс, то необходимо послать ему сигнал TERM:

igor@ubuntu:~$ kill -TERM 6301
igor@ubuntu:~$ ps x | grep [s]leep
[1]+ Terminated sleep 1000
igor@ubuntu:~$ ps x | grep [s]leep

Если сразу же после посылки сигнала TERM выполнить команду ps x | grep [s]leep, то можно успеть увидеть сообщение о том, что процесс завершает работу, в при следующей попытке вывести информацию о нашем процессе sleep мы уже ничего не увидим — процесс прекратил существование. Команда kill без указания сигнала, по умолчанию передает процессу именно сигнал TERM. Поэтому можно было написать просто kill 6301.

Если необходимо срочно завершить процесс, или процесс не завершается по сигналу TERM, то тогда необходимо послать процессу сигнал KILL:

igor@ubuntu:~$ sleep 1000 &
[1] 6348
igor@ubuntu:~$ kill -KILL 6348
igor@ubuntu:~$ ps x | grep [s]leep
[1]+ Killed sleep 1000

Если необходимо послать один и тот же сигнал нескольким процессам, то можно перечислить их через пробел: kill -TERM 2345 3456 4567.

Команда kill довольно ограничена в возможностях и не позволяет выполнять более сложные действия. Поэтому рассмотрим еще одну команду — killall. Основное преимущество этой команды, то что она умеет посылать сигналы всем процессам с одинаковым именем или всем процессам одного пользователя. Запустите несколько раз подряд команду sleep 1000 &:

igor@ubuntu:~$ ps x | grep [s]leep
6460 pts/1 S 0:00 sleep 1000
6461 pts/1 S 0:00 sleep 1000
6462 pts/1 S 0:00 sleep 1000
6463 pts/1 S 0:00 sleep 1000
6464 pts/1 S 0:00 sleep 1000
6465 pts/1 S 0:00 sleep 1000
6466 pts/1 S 0:00 sleep 1000

Теперь, чтобы завершить все процессы с именем sleep, достаточно набрать команду killall sleep:

igor@ubuntu:~$ killall sleep
[1] Terminated sleep 1000
[2] Terminated sleep 1000
[3] Terminated sleep 1000
[4] Terminated sleep 1000
[6]- Terminated sleep 1000
[7]+ Terminated sleep 1000
[5]+ Terminated sleep 1000

Выполните команду sleep 1000 & еще несколько раз, а затем зарегистрируйтесь в другой консоли от имени другого пользователя (например, test) и также от его имени выполните команду sleep 1000 &. Теперь вернитесь в свою консоль и просмотрите процессы sleep всех пользователей:

igor@ubuntu:~$ ps aux | grep [s]leep
igor 6540 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000
igor 6541 0.0 0.0 2952 632 pts/1 S 22:30 0:00 sleep 1000
igor 6542 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000
test 6543 0.0 0.0 2952 632 pts/3 S 22:30 0:00 sleep 1000
test 6544 0.0 0.0 2952 628 pts/3 S 22:30 0:00 sleep 1000
test 6545 0.0 0.0 2952 628 pts/3 S 22:30 0:00 sleep 1000
test 6546 0.0 0.0 2952 632 pts/3 S 22:30 0:00 sleep 1000

Теперь для того, чтобы удалить процессы только пользователя test необходимо выполнить (от имени пользователя root) команду killall -u test:

igor@ubuntu:~$ sudo killall -u test
igor@ubuntu:~$ ps aux | grep [s]leep
igor 6540 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000
igor 6541 0.0 0.0 2952 632 pts/1 S 22:30 0:00 sleep 1000
igor 6542 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000

Команда выше удалит не только процессы sleep, но вообще все процессы пользователя test. Если необходимо удалить конкретно процессы sleep, то тогда команду нужно было записать так: killall -u test sleep.

Если запустить команду killall c ключом -i, то перед посылкой сигнала будет запрашиваться подтверждение:

igor@ubuntu:~$ killall -i sleep
Прибить sleep(6540) ? (y/N) n
Прибить sleep(6541) ? (y/N) n
Прибить sleep(6542) ? (y/N) n

Следующая лекция будет завершающей по теме процессов и сигналов Linux. Мы поговорим о заданиях (jobs), командах jobs, fg, bg, strong>nohup, и top.

8.4.4. Сигналы и команда kill

Сигналы — это средство, с помощью которого процессам можно передать сообщения о некоторых событиях в системе. Сами процессы тоже могут генерировать сигналы, с помощью которых они передают определенные сообщения ядру и другим процессам. С помощью сигналов можно осуществлять такие акции управления процессами, как приостановка процесса, запуск приостановленного процесса, завершение работы процесса. Всего в Linux существует 63 разных сигнала, их перечень можно посмотреть по команде

Сигналы принято обозначать номерами или символическими именами. Все имена начинаются на SIG, но эту приставку иногда опускают: например, сигнал с номером 1 обозначают или как SIGHUP, или просто как HUP.

Когда процесс получает сигнал, то возможен один из двух вариантов развития событий. Если для данного сигнала определена подпрограмма обработки, то вызывается эта подпрограмма. В противном случае ядро выполняет от имени процесса действие, определенное по умолчанию для данного сигнала. Вызов подпрограммы обработки называется перехватом сигнала. Когда завершается выполнение подпрограммы обработки, процесс возобновляется с той точки, где был получен сигнал.

Можно заставить процесс игнорировать или блокировать некоторые сигналы. Игнорируемый сигнал просто отбрасывается процессом и не оказывает на него никакого влияния. Блокированный сигнал ставится в очередь на выдачу, но ядро не требует от процесса никаких действий до разблокирования сигнала. После разблокирования сигнала программа его обработки вызывается только один раз, даже если в течение периода блокировки данный сигнал поступал несколько раз.

В табл. 8.1. приведены некоторые из часто встречающихся сигналов.

Таблица 8.1. Сигналы

N Имя Описание Можно перехватывать Можно блокировать Комбинация клавиш 1 HUP Hangup. Отбой Да Да 2 INT Interrupt. В случае выполнения простых команд вызывает прекращение выполнения, в интерактивных программах — прекращение активного процесса Да Да ‹Ctrl›+‹C› или ‹Del› 3 QUIT Как правило, сильнее сигнала Interrupt Да Да ‹Ctrl›+‹› 4 ILL Illegal Instruction. Центральный процессор столкнулся с незнакомой командой (в большинстве случаев это означает, что допущена программная ошибка). Сигнал отправляется программе, в которой возникла проблема Да Да 8 FPE Floating Point Exception. Вычислительная ошибка, например, деление на ноль Да Да 9 KILL Всегда прекращает выполнение процесса Нет Нет 11 SEGV Segmentation Violation. Доступ к недозволенной области памяти Да Да 13 PIPE Была предпринята попытка передачи данных с помощью конвейера или очереди FIFO, однако не существует процесса, способного принять эти данные Да Да 15 TERM Software Termination. Требование закончить процесс (программное завершение) Да Да 17 CHLD Изменение статуса порожденного процесса Да Да 18 CONT Продолжение выполнения приостановленного процесса Да Да 19 STOP Приостановка выполнения процесса Нет Нет 20 TSTR Сигнал останова, генерируемый клавиатурой. Переводит процесс в фоновый режим Да Да ‹Ctrl›+‹Z›

Как видите, некоторые сигналы можно сгенерировать с помощью определенных комбинаций клавиш. Но такие комбинации существуют не для всех сигналов. Зато имеется команда kill, которая позволяет послать заданному процессу любой сигнал. Как уже было сказано, с помощью этой команды можно получить список всех возможных сигналов, если указать опцию -l. Если после этой опции указать номер сигнала, то будет выдано его символическое имя, а если указать имя, то получим соответствующий номер.

Для посылки сигнала процессу (или группе процессов) можно воспользоваться командой kill в следующем формате:

[user]$ kill [-сигн] PID [PID..]

где сигн — это номер сигнала, причем если указание сигнала опущено, то посылается сигнал 15 (TERM — программное завершение процесса). Чаще всего используется сигнал 9 (KILL), с помощью которого суперпользователь может завершить любой процесс. Но сигнал этот очень «грубый», если можно так выразиться, поэтому его использование может привести к нарушению порядка в системе. Поэтому в большинстве случаев рекомендуется использовать сигналы TERM или QUIT, которые завершают процесс более «мягко».

Естественно, что наиболее часто команду kill вынужден применять суперпользователь. Он должен использовать ее для уничтожения процессов-зомби, зависших процессов (они показываются в листинге команды ps как ‹exiting›), процессов, которые занимают слишком много процессорного времени или слишком большой объем памяти и т. д. Особый случай — процессы, запущенные злоумышленником. Но обсуждение этого особого случая выходит за рамки данной книги.

Читайте также

Сигналы

Сигналы Сигналы являются способом передачи от одного процесса другому или от ядра операционной системы какому-либо процессу уведомления о возникновении определенного события. Сигналы можно рассматривать как простейшую форму межпроцессного взаимодействия. В то же

Сигналы

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

7.2 СИГНАЛЫ

7.2 СИГНАЛЫ Сигналы сообщают процессам о возникновении асинхронных событий. Посылка сигналов производится процессами — друг другу, с помощью функции kill, — или ядром. В версии V (вторая редакция) системы UNIX существуют 19 различных сигналов, которые можно классифицировать

5.8.2. Сигналы

5.8.2. Сигналы Демон syslogd реагирует на следующие сигналы: SYGTERM, SIGINT, SIGQUIT, SIGHUP, SIGUSR1, SIGCHLD. Реакция демона на сигналы описана в табл. 5.8.Реакция демона на сигналы Таблица 5.8 Сигнал Реакция SIGTERM Завершает работу демона SIGINT, SIGQUIT Завершает работу демона, если выключена отладка

3.3.2. Сигналы

3.3.2. Сигналы Механизм сигналов — это средство, позволяющее сообщать процессам о некоторых событиях в системе, а процессу-получателю — должным образом на эти сообщения реагировать. Послать сигнал может сам процесс (например, при попытке деления на ноль), ядро (при сбое

27.3.10. Сигналы и сокеты

27.3.10. Сигналы и сокеты С сокетами связаны три сигнала:? SIGIO — сокет готов к вводу/выводу. Сигнал посылается процессу, который связан с сокетом;? SIGURG — сокет получил экспресс-данные (мы их использовать не будем, поэтому особо останавливаться на них нет смысла);? SIGPIPE — запись

Завершение процесса с помощью команды KILL

Завершение процесса с помощью команды KILL В SQL Server администратор может удалить процесс, например пользовательское подключение или блокировку базы данных, с помощью команды KILL. Обычно эта команда применяется для чрезвычайного прекращения пользовательского сеанса,

7.2.6.2. Сигналы

7.2.6.2. Сигналы Самый простой и грубый способ сообщения между двумя процессами на одной машине заключается в том, что один из них отправляет другому какой-либо сигнал (signal). Сигналы в операционной системе Unix представляют собой форму программного прерывания. Каждый сигнал

7.2.6.2. Сигналы

7.2.6.2. Сигналы Самый простой и грубый способ сообщения между двумя процессами на одной машине заключается в том, что один из них отправляет другому какой-либо сигнал (signal). Сигналы в операционной системе Unix представляют собой форму программного прерывания. Каждый сигнал

3.3. Сигналы

3.3. Сигналы Сигналы — это механизм связи между процессами в Linux. Данная тема очень обширна, поэтому здесь мы рассмотрим лишь наиболее важные сигналы и методики управления процессами.Сигнал представляет собой специальное сообщение, посылаемое процессу. Сигналы являются

Пример 11-23. Сценарий, завершающий себя сам с помощью команды kill

Пример 11-23. Сценарий, завершающий себя сам с помощью команды kill #!/bin/bash# self-destruct.shkill $$ # Сценарий завершает себя сам. # Надеюсь вы еще не забыли, что «$$» — это PID сценария.echo «Эта строка никогда не будет выведена.»# Вместо него на stdout будет выведено сообщение «Terminated».exit 0# Какой

26.2. Сигналы

26.2. Сигналы Сигнал относится к типу сообщений, которые пересылаются из системы для информирования команды или сценария о совершении какого?либо события. Обычно речь идет об ошибках, связанных с функционированием памяти, о проблемах с доступом к информации или об

Сигналы, группы, сеансы

Сигналы в Unix указывают ядру, что надо прервать нормальное планирование процесса и завершить/остановить его, или, вместо продолжения выполнения процесса с места остановки, выполнить функцию — обработчик сигнала, и лишь затем продолжить выполнение основного кода.

Сигналы, предназначенные процессу, создаются (отправляются) в нескольких ситуациях: при аппаратных сбоях, при срабатывании особого таймера, при обработке спецсимволов (Ctrl C, Ctrl Z) драйвером управляющего терминала, с помощью системного вызова kill(). В зависимости от причины, отправляются сигналы разных типов. Тип сигнала обозначается целым числом (номером). В Linux сигналы нумеруются от 1 до 64. Сигнал может быть отправлен отдельной нити процесса, процессу в целом или группе процессов.

Для каждого номера сигнала в процессе (нити) предусмотрено некоторое действие (действие по умолчанию, игнорирование или вызов пользовательской функции). Доставка сигнала заключается в выполнении этого действия.

Между отправкой сигнала и его доставкой проходит некоторое непредсказуемое время, поскольку, обычно, сигналы обрабатываются (доставляются) при выходе из системных вызовов или в тот момент, когда планировщик назначает процесс на выполнение. Исключением является доставка сигнала SIGKILL остановленным процессам. Для большинства сигналов можно явно приостановить доставку с помощью установки маски блокирования доставки sigprocmask() , и, в случае необходимости, удалить сигнал без обработки с помощью sigwait() .

Сигналы SIGKILL и SIGSTOP не могут быть заблокированы или проигнорированы и на них нельзя установить свой обработчик.

Действия по умолчанию:

  • SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU — остановка процесса
  • SIGCONT — запуск остановленного процесса
  • SIGCHLD — игнорируется
  • SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGSEGV — сохранение дампа памяти и завершение (Linux)
  • остальные — завершение процесса

Сигнал, маска, обработчик

В упрощенном виде структуру в ядре, обеспечивающую доставку сигналов процессу, можно представить как таблицу:

Номер Есть Сигнал? Маска Обработчик
1 1 1 SIG_DFL
2 0 0 SIG_IGN
3 0 0 sig_func()
. . . .
  • Есть сигнал? — битовое поле, указывающее наличие недоставленного сигнала
  • Маска — битовое поле, указывающее временный запрет на доставку сигнала
  • Обработчик — указатель на действие, выполняемое при доставке сигнала. Может принимать значения: SIG_DFL — действие по умолчанию, SIG_IGN — игнорирование сигнала или указатель на функцию — обработчика сигнала.

Традиционно, при отправке процессу нескольких однотипных обычных сигналов, обработчик будет вызван лишь раз. Начиная с POSIX 1003.1, кроме обычных сигналов, поддерживаются сигналы реального времени, для которых создаётся очередь недоставленных сигналов, которая кроме номера сигнала, содержит значение (целое или адрес), которое уникально для каждого экземпляра сигнала.

Примеры использования сигналов

SIGKILL, SIGTERM, SIGINT, SIGHUP — завершение процесса. SIGKILL — не может быть проигнорирован, остальные могут. SIGTERM — оповещение служб о завершении работы ОС, SIGINT — завершение программы по нажатию Ctrl C, SIGHUP — оповещение программ, запущенных через модемное соединение, об обрыве связи (в настоящее время практически не используется).

SIGILL, SIGFPE, SIGBUS, SIGSEGV — аппаратный сбой. SIGILL — недопустимая инструкция CPU, SIGFPE — ошибка вычислений с плавающей точкой (деление на ноль), SIGBUS — физический сбой памяти, SIGSEGV — попытка доступа к несуществующим (защищенным) адресам памяти.

SIGSTOP, SIGCONT — приостановка и продолжение выполнения процесса

SIGPIPE — попытка записи в канал или сокет, у которого нет читателя

SIGCHLD — оповещение о завершении дочернего процесса.

Список сигналов

Особый сигнал с номером 0 фактически не доставляется, а используется в вызове kill() для проверки возможности доставки сигнала определённому процессу.

В Linux используется 64 сигнала. Список можно посмотреть в терминале командой kill -l

Posix.1-1990

Источник — man 7 signal

 Signal Value Action Comment ------------------------------------------------------------------------- SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process SIGINT 2 Term Interrupt from keyboard SIGQUIT 3 Core Quit from keyboard SIGILL 4 Core Illegal Instruction SIGABRT 6 Core Abort signal from abort(3) SIGFPE 8 Core Floating point exception SIGKILL 9 Term Kill signal SIGSEGV 11 Core Invalid memory reference SIGPIPE 13 Term Broken pipe: write to pipe with no readers SIGALRM 14 Term Timer signal from alarm(2) SIGTERM 15 Term Termination signal SIGUSR1 30,10,16 Term User-defined signal 1 SIGUSR2 31,12,17 Term User-defined signal 2 SIGCHLD 20,17,18 Ign Child stopped or terminated SIGCONT 19,18,25 Cont Continue if stopped SIGSTOP 17,19,23 Stop Stop process SIGTSTP 18,20,24 Stop Stop typed at tty SIGTTIN 21,21,26 Stop tty input for background process SIGTTOU 22,22,27 Stop tty output for background process 

Отправка сигнала

int kill(pid_t pid, int signum);

Для отправка сигнала необходимо, чтобы uid или euid текущего процесса был равен 0 или совпадал с uid процесса получателя.

Получатель сигнала зависит от величины и знака параметра pid :

  • pid > 0 — сигнал отправляется конкретному процессу
  • pid == 0 — сигнал отправляется всем членам группы
  • pid == -1 — сигнал отправляется всем процессам кроме init (в Linux’е еще кроме себя)
  • pid < -1 - сигнал отправляется группе с номером -pid

Если signum == 0 — сигнал не посылается, но делается проверка прав на посылку сигнала и формируются код ответа и errno.

int sigqueue(pid_t pid, int sig, const union sigval value);

Аналогично kill() , но выполняется по правилам сигналов реального времени. Сигнал и связанная с ним дополнительная информация (целое или адрес) value помещаются в очередь сигналов (FIFO). Таким образом процессу можно отправить несколько однотипных сигналов с разными значениями value .

Отправка сигнала текущему процессу. Эквивалент kill(getpid(),signum);

Убирает из маски сигналов сигнала SIGABRT и отправляет его текущему процессу . Если сигнал перехватывается или игнорируется, то после возвращения из обработчика abort() завершает программу. Выхода из функции abort() не предусмотрено. Единственный способ продолжить выполнение — не выходить из обработчика сигнала.

Отправка сигнала SIGALRM себе через time секунд. Возвращает 0 если ранее alarm не был установлен или число секунд остававшихся до срабатывания предыдущего alarma. Таймер управляющий alarm’ами один. Соответственно установка нового alarm’а отменяет старый. Параметр time==0 позволяет получить оставшееся до alarm’а время без установки нового.

Исторический способ обработки сигнала — signal

Установка реакции на сигнал через функцию signal() не до конца стандартизована и сохраняется для совместимости с историческими версиями Unix. Не рекомендуется к использованию. В стандарте POSIX signal() заменен на вызов sigaction(), сохраняющий для совместимости эмуляцию поведения signal().

sighandler — адрес функции обработчика void sighandler(int) или один из двух макросов: SIG_DFL (обработчик по умолчанию) или SIG_IGN (игнорирование сигнала).

signal(. ) возвращает предыдущее значение обработчика или SIG_ERR в случае ошибки.

В Linux и SysV при вызове sighandler обработчик сбрасывается в SIG_DFL и возможна доставка нового сигнала во время работы sighandler . Такое поведение заставляет первой строкой в sighandler восстанавливать себя в качестве обработчика сигнала, и, даже в этом случае, не гарантирует от вызова обработчика по умолчанию. В BSD системах сброс не происходит, доставка новых сигнала блокируется до выхода из sighandler .

#include void sighandler(int signum) < signal(signum,sighandler); . >main()

Реакция на сигнал — sigaction

Параметры для установки обработчика сигнала через sigaction()

struct sigaction < void (*sa_handler)(int); // Обработчик сигнала старого стиля void (*sa_sigaction)(int, siginfo_t *, void *); // Обработчик сигнала нового стиля // Обработчик выбирается на основе флага SA_SIGINFO // в поле sa_flags sigset_t sa_mask; // Маска блокируемых сигналов int sa_flags; // Набор флагов // SA_RESETHAND - сброс обработчика на SIG_DFL после выхода из назначенного обработчика. // SA_RESTART - восстановление прерванных системных вызовов после выхода из обработчика. // SA_SIGINFO - вызов sa_sigaction вместо sa_handler void (*sa_restorer)(void); // Устаревшее поле >

Данные, передаваемые в обработчик сигнала sa_sigaction()

siginfo_t < int si_signo; // Номер сигнала int si_code; // Способ отправки сигнала или уточняющее значение // SI_USER сигнал отправлен через вызов kill() // SI_QUEUE сигнал отправлен через вызов sigqueue() // FPE_FLTDIV - уточнение для сигнала SIGFPE - деление на ноль // ILL_ILLOPC - уточнение для сигнала SIGILL - недопустимый опкод // . pid_t si_pid; // PID процесса отправителя (дочернего процесса при SIGCHLD) uid_t si_uid; // UID процесса отправителя int si_status; // Статус завершения дочернего процесса при SIGCHLD sigval_t si_value; // Значение, переданое через параметр value при вызове sigqueue() void * si_addr; // Адрес в памяти // SIGILL, SIGFPE - адрес сбойной инструкции // SIGSEGV, SIGBUS - адрес сбойной памяти >

В Linux структура siginfo_t содержит больше полей, но они служат для совместимости и не заполняются.

Код

#include void myhandler(int sig) < . >void myaction(int signum, siginfo_t * siginfo, void *code) < . >main()

Блокирование сигналов

Все функции блокирования сигналов работают с маской сигналов типа sigset_t. В Linux это 64 бита, т.е. два слова в 32х разрядной архитектуре или одно в 64х разрядной. Выставленный бит в маске сигналов означает, что доставка сигнала с соответствующим номером будет заблокирована. Сигналы SIGKILL и SIGSTOP заблокировать нельзя.

Манипулирование маской

#include int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signum); int sigdelset(sigset_t *set, int signum); int sigismember(const sigset_t *set, int signum); int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); Изменить маску сигналов 

Параметр how определяет операцию над текущей маской. Значения SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK.

Проверка наличия заблокированных сигналов

int sigpending(sigset_t *set); // Получить список недоставленных из-за блокировки сигналов. int sigsuspend(const sigset_t *mask); //Установить новую маску и "уснуть" до получения и обработки разрешенного в ней сигнала. 

Очистка заблокированных сигналов

sigwait ожидает блокировки какого-либо из сигналов, указанных в маске, удаляет этот сигнал и возвращает его номер в параметр sig . Если реализация сигналов предусматривает очередь сигналов, то удаляется только один элемент из очереди.

int sigwait(const sigset_t *set, int *sig); 

Управляющий терминал, сеанс, группы

Управляющий терминал, сеанс, группы

Для организации диалоговой работы пользователей в Unix вводится понятие терминальной сессии. С точки зрения пользователя — это процесс работы с текстовым терминалом с момента ввода имени и пароля и до выхода из системы командой logout ( exit , нажатие ^D в пустой строке). Во время терминальной сессии может быть запущено несколько программ, которые будут параллельно выполнятся в фоновом режиме и между которыми можно переключаться в диалоговом режиме. После завершения терминальной сессии возможно принудительное завершение всех запущенных в ней фоновых процессов.

С точки зрения ядра — терминальная сессия — это группа процессов, имеющих один идентификатор сеанса sid. С идентификатором sid связан драйвер управляющего терминала, доступный всем членам сеанса как файл символьного устройства /dev/tty. Для каждого сеанса существует свой /dev/tty. Управляющий терминал взаимодействует с процессами сеанса с помощью отправки сигналов.

В рамках одного сеанса могут существовать несколько групп процессов. С каждым процессом связан идентификатор группы pgid. Одна из групп в сеансе может быть зарегистрирована в драйвере управляющего терминала как группа фоновых процессов. Процессы могут переходить из группы в группу самостоятельно или переводить из группы в группу другие процессы сеанса. Перейти в группу другого сеанса нельзя, но можно создать свой собственный сеанс из одного процесса со своей группой в этом сеансе. Вернуться в предыдущий сеанс уже не получится.

Группа процессов

Группа процессов — инструмент для доставки сигнала нескольким процессам, а также способ арбитража при доступе к терминалу. Идентификатор группы pgid равен pid создавшего её процесса — лидера группы. Процесс может переходить из группы в группу внутри одного сеанса.

#include int setpgid(pid_t pid, pid_t pgid); // включить процесс pid в группу pgid. // pid=0 означает текущий процесс, // pgid=0 означает pgid=pid текущего процесса // pid=pgid=0 - создание новой группы с pgid=pid текущего процесса // и переход в эту группу pid_t getpgid(pid_t pid); // получить номер группы процесса pid. // pid=0 - текущий процесс int setpgrp(void); // создание группы, эквивалент setpgid(0.0); pid_t getpgrp(void); // запрос текущей группы, эквивалент getpgid(0); 

Сеанс

Сеанс — средство для контроля путем посылки сигналов над несколькими группами процессов со стороны терминального драйвера. Как правило соответствует диалоговой пользовательской сессии. Идентификатор сеанса sid равняется идентификатору pid, создавшего его процесса — лидера сеанса. Одновременно с сеансом создаётся новая группа с pgid равным pid лидера сеанса. Поскольку переход группы из сеанса в сеанс невозможен, то создающий сеанс процесс не может быть лидером группы.

#include pid_t setsid(void); //Создание новой группы и нового сеанса. Текущий процесс не должен быть лидером группы. pid_t getsid(pid_t pid); //Возвращает номер сеанса для указанного процесса 

Создание собственного сеанса рекомендуется начать с fork, чтобы гарантировать, что процесс не является лидером группы.

if( fork() ) exit(0); setsid(); 

Фоновая группа сеанса

Процессы в фоновой группе выполняются до тех пор, пока не попытаются осуществить чтение или запись через файловый дескриптор управляющего терминала. В этот момент они получают сигнал SIGTTIN или SIGTTOU соответственно. Действие по умолчанию для данного сигнала — приостановка выполнения процесса.

Назначение фоновой группы:

#include pid_t tcgetpgrp(int fd); // получить pgid фоновой группы, связанной с управляющим терминалом, // на который ссылается файловый дескриптор fd int tcsetpgrp(int fd, pid_t pgrp); // назначить pgid фоновой группы терминалу, // на который ссылается файловый дескриптор fd 

Управляющий терминал

Некоторые сочетания клавиш позволяют посылать сигналы процессам сеанса:

  • ^C — SIGINT — завершение работы
  • ^Z — SIGTSTP — приостановка выполнения. bash отслеживает остановку дочерних процессов и вносит их в списки своих фоновых процессов. Остановленный процесс может быть продолжен командой fg n , где n — порядковый нрмер процесса в списке фоновых процессов

Открыть управляющий терминал сеанса

#include char name[L_ctermid]; int fd; ctermid(name); // если name=NULL, то используется внутренний буфер // ctermid возвращает указатель на буфер // L_ctermid - библиотечная константа fd = open(name, O_RDWR, 0); 

Сигналы

В этом примере процесс less взаимодействует с процессом grep посредством механизма, который называется неименований канал или пайп (pipe — канал). Мы не будем вдаваться в подробности, просто запомните, что посредством символа |, который можно в данном случае называть “пайпом” информация (результат выполнения) процесса less идет на вход другого процесса — grep. Таким образом один процесс передал информацию другому процессу.

Еще один способ общения процессов — это именованные каналы. Именованный канал можно создать командой mkfifo: $ mkfifo my_pipe $ ls -l | grep my_pipe prw-r–r– 1 igor igor 0 2009-11-09 17:59 my_pipe

Теперь в одной консоли выполните команду:

$ echo Hello > my_pipe

Как видите, команда не завершает свою работу, а ждет. Зарегистрируйтесь еще в одной консоли и выполните команду:

$ cat my_pipe Hello

Если вернуться на первую консоль, то вы увидите, что команда echo завершила свою работу. Таким образом через именованный канал my_pipe команда (процесс) echo передала информацию (слово Hello) процессу cat, который ее принял и вывел на экран.

Давайте теперь рассмотрим основной способ “общения” процессов — сигналы. Один процесс при помощи ядра может передать другому процессу специальное числовое значение сигнала. Процесс вызывает функцию передачи сигнала и передает необходимую информацию (код сигнала, PID процесса) ядру. Ядро передает сигнал процессу получателю и отслеживает как этот сигнал обрабатывается. Сигналы обозначаются цифрами или мнемоническими обозначениями. Перечень сигналов можно вывести командой kill -l.

Мнемонические имена которые вы видите (SIGTERM, SIGINT, SIGKILL) начинаются с приставки SIG. Имена в этом виде используются в языках программирования таких как С. В интерпретаторе bash используются или числа или мнемонические имена, но без приставки SIGTERM, INT, KILL.

Часть сигналов (INT, TERM) являются перехватываемыми. Это означает, что процесс при получении такого сигнала должен перейти на специальную подпрограмму, которая занимается обработкой сигнала. Если подпрограммы обработки нет (а ее написанием занимаются разработчики программы, которая выполняется в контексте процесса), то управление передается ядру, которое выполняет действия по умолчанию, описанные для каждого сигнала.

Часть сигналов являются такими которые можно заблокировать. Например, один процесс посылает сигнал TERM другому процессу, а он в свою очередь не закончил операции ввода/вывода. В таком случае второй процесс может заблокировать полученный сигнал (опять таки в обработчике сигнала) до момента выполнения необходимой операции ввода/вывода. Сигнал TERM — это сигнал корректного завершения работы процесса. Обработчик этого сигнала, должен выполнить все необходимые действия для правильного завершения работы.

И есть третья группа сигналов, которые не блокируются и для которых не нужны обработчики. Примером такого сигнала является сигнал KILL. Этот сигнал уничтожает процесс, так как для него нет обработчиков в процессах, то он будет обрабатываться ядром по умолчанию и так как он не блокируемый, то действия будут выполнятся немедленно.

Пока мы говорили о том как процессы “общаются” между собой с помощью сигналов. Но мы (пользователи) также можем посылать сигналы процессам. Например, комбинация клавиш Ctrl+C посылает процессу сигнал INT, который прерывает выполнение процесса. Если вы наберете в терминале команду sleep 100, то команда не вернет управление терминалу пока не завершится. Прервать выполнение этой команды можно нажав комбинацию клавиш Ctrl+C.

В чем же отличия между похожими сигналами INT, TERM, KILL (а также QUIT и HUP)? Несмотря на похожесть отличия есть:

Сигнал KILL не блокируется и не перехватывается и ведет к немедленному завершению процесса. Сигнал INT в отличии от KILL является блокируемым сигналом и перехватываемым. Сигнал TERM также является перехватываемым и блокируемым и предназначен для корректного (предпочтительного) завершения работы процесса. Сигнал QUIT — похож на TERM, но позволяет сохранить дамп памяти. Сигнал HUP — сейчас этот сигнал чаще всего интерпретируется процессами как “прочесть конфигурационные файлы”.

Рассмотрим два сигнала: STOP и CONT. Сигнал STOP останавливает процесс, то есть процесс переходит в состояние “остановленный“. В таком состоянии процесс будет до тех пор пока снова не получит сигнал. Если будет получен сигнал CONT, то процесс возобновит свою работу с того момента как он был остановлен. Практический пример:

Наберите в терминале команду sleep 1000 &.

Затем проверьте, что процесс находится в состоянии ожидания, о чем нам говорит буква S в столбце S:

$ top | grep [s]leep PID S TIME COMMAND 6301 S 0:00 sleep 1000

Теперь пошлем процессу сигнал STOP. Для этого используем команду kill (kill -название процесса PID процесса):

$ kill -STOP 6301 [1]+ Stopped sleep 1000

Проверяем статус процесса: $ top | grep [s]leep PID S TIME COMMAND 6301 T 0:00 sleep 1000

Видим, что процесс действительно находится в состоянии “остановленный” (символ T в столбце S).

Теперь отправим процессу сигнал продолжения работы (CONT) и проверим состояние: kill -CONT 6301 $ top | grep [s]leep PID S TIME COMMAND 6301 S 0:00 sleep 1000

Если необходимо корректно завершить процесс, то необходимо послать ему сигнал TERM: $ kill -TERM 6301 $ top | grep [s]leep [1]+ Terminated sleep 1000 $ top | grep [s]leep

Если сразу же после посылки сигнала TERM выполнить команду top x | grep [s]leep, то можно успеть увидеть сообщение о том, что процесс завершает работу, в при следующей попытке вывести информацию о нашем процессе sleep мы уже ничего не увидим — процесс прекратил существование. Команда kill без указания сигнала, по умолчанию передает процессу именно сигнал TERM. Поэтому можно было написать просто kill 6301.

Если необходимо срочно завершить процесс, или процесс не завершается по сигналу TERM, то тогда необходимо послать процессу сигнал KILL: $ sleep 1000 & [1] 6348 $ kill -KILL 6348 $ top | grep [s]leep [1]+ Killed sleep 1000

Если необходимо послать один и тот же сигнал нескольким процессам, то можно перечислить их через пробел: kill -TERM 2345 3456 4567.

Команда kill довольно ограничена в возможностях и не позволяет выполнять более сложные действия. Поэтому рассмотрим еще одну команду — killall. Основное преимущество этой команды, то что она умеет посылать сигналы всем процессам с одинаковым именем или всем процессам одного пользователя. Запустите несколько раз подряд команду sleep 1000 &:

$ top | grep [s]leep 6460 S 0:00 sleep 1000 6461 S 0:00 sleep 1000 6462 S 0:00 sleep 1000 6463 S 0:00 sleep 1000 6464 S 0:00 sleep 1000 6465 S 0:00 sleep 1000 6466 S 0:00 sleep 1000

Теперь, чтобы завершить все процессы с именем sleep, достаточно набрать команду killall sleep: $ killall sleep [1] Terminated sleep 1000 [2] Terminated sleep 1000 [3] Terminated sleep 1000 [4] Terminated sleep 1000 [6]- Terminated sleep 1000 [7]+ Terminated sleep 1000 [5]+ Terminated sleep 1000

Выполните команду sleep 1000 & еще несколько раз, а затем зарегистрируйтесь в другой консоли от имени другого пользователя (например, test) и также от его имени выполните команду sleep 1000 &. Теперь вернитесь в свою консоль и просмотрите процессы sleep всех пользователей:

$ top | grep [s]leep igor 6540 0.0 0.0 2952 628 S 22:30 0:00 sleep 1000 igor 6541 0.0 0.0 2952 632 S 22:30 0:00 sleep 1000 igor 6542 0.0 0.0 2952 628 S 22:30 0:00 sleep 1000 test 6543 0.0 0.0 2952 632 S 22:30 0:00 sleep 1000 test 6544 0.0 0.0 2952 628 S 22:30 0:00 sleep 1000 test 6545 0.0 0.0 2952 628 S 22:30 0:00 sleep 1000 test 6546 0.0 0.0 2952 632 S 22:30 0:00 sleep 1000

Теперь для того, чтобы удалить процессы только пользователя test необходимо выполнить (от имени пользователя root) команду killall -u test: igor@ubuntu:~$ sudo killall -u test igor@ubuntu:~$ top | grep [s]leep igor 6540 0.0 0.0 2952 628 S 22:30 0:00 sleep 1000 igor 6541 0.0 0.0 2952 632 S 22:30 0:00 sleep 1000 igor 6542 0.0 0.0 2952 628 S 22:30 0:00 sleep 1000

Команда выше удалит не только процессы sleep, но вообще все процессы пользователя test. Если необходимо удалить конкретно процессы sleep, то тогда команду нужно было записать так: killall -u test sleep.

Если запустить команду killall c ключом -i, то перед посылкой сигнала будет запрашиваться подтверждение:

igor@ubuntu:~$ killall -i sleep Прибить sleep(6540) ? (y/N) n Прибить sleep(6541) ? (y/N) n Прибить sleep(6542) ? (y/N) n

ЗАДАНИЯ (JOBS), КОМАНДЫ JOBS, FG, BG, STRONG>NOHUP, И TOP.

Мы неоднократно использовали знак & (амперсанд) в конце команды (sleep 100 &). Знак амперсанда в конце команды означает, что запускаемый процесс нужно будет перевести в фоновый режим. Если запустить команду sleep 100 без знака &, то мы не получим приглашение в командной строке пока не будет завершен процесс sleep.

Запущенные из консоли с помощью амперсанда команды, работают в фоновом режиме и называются задачами (jobs). Можно сказать, что задачи это процессы, привязанные к командному интерпретатору. Такие задачи помимо традиционного PID имеют еще свою нумерацию начинающуюся с единицы. Просмотреть запущенные задачи интерпретатора, можно командой jobs. В примере ниже показана ситуация когда есть две задачи и выполнение одного из них остановлено.

$ jobs [1]+ Stopped top [2]- Running sleep 100 &

Наберите в консоли команду top. Эта команда показывает в реальном времени существующие процессы, но не все, а только ту часть которая помещается на экране. Чуть позже мы вернемся к этой команде. Пока вы можете заметить, что top не возвращает управление командному интерпретатору. Можно либо выйти из программы (нажав q) или остановить процесс комбинацией клавиш ctrl+z (не путайте комбинации ctrl+cзавершение процесса и ctrl+zостановка процесса). Остановленный процесс top мы и видели на примере выше. Для того, чтобы возобновить работу данного процесса (задачи) есть две команды: fg и bg, сокращения от английских слов foreground (передний план) и background (задний план). Синтаксис простой: fg номер задачи. Команда fg, работает не только с остановленными задачами, но и с задачами вообще. В нашем примере команда fg 2 выведет процесс sleep на передний план и приглашение командного интерпретатора станет недоступным (так как будто мы запустили команду sleep без символа &). Команда fg 2 возобновит работу процесса top и выведет его на передний план. Команда fg без параметра возобновит работу последнего процесса остановленного комбинацией ctrl+z, а если таковых не окажется, то выведет на передний план последнюю задачу (задачу с большим порядковым номером). Задача, которая будет восстановлена (отображена) командой fg без параметра отмечена знаком + в выводе результатов команды jobs. Команда bg предназначена для восстановления работы остановленных процессов (задач) в фоновом режиме.

Отметьте для себя также, что задачи имеют свою нумерацию для каждого терминала (консоли). Если вы зарегистрируетесь в другой консоли и запустите в фоновом режиме процесс, то номер задачи будет начинаться с единицы. Также вы не найдете справки по командам fg и bg (man fg, man bg). Потому, что эти команды являются частью bash. И упоминание о них вы найдете в man bash.

Любые процессы запущенные из командного интерпретатора являются дочерними для него. И PPID таких процессов будет равен PID соответствующего командного интерпретатора. Если выйти из командного интерпретатора, то все процессы запущенные из него (в том числе и находящиеся в фоновом режиме) будут завершены. Зарегистрируйтесь в двух консолях и запустите во второй несколько процессов, перейдите в первую и выполните команду top al:

1 2 3 4 5 6 7 8 9

$ top al F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND 0 1000 13180 1053 20 0 6292 3552 wait Ss /0 0:00 bash 0 1000 16442 1054 20 0 6292 3560 wait Ss 0:00 bash 0 1000 16460 16442 20 0 2952 628 signal T 0:00 sleep 200 0 1000 16461 16442 20 0 18416 4392 signal T 0:00 mocp 0 1000 16469 16442 20 0 2952 628 hrtime S 0:00 sleep 1000 0 1000 16470 16442 20 0 2468 1208 poll_s S+ 0:00 top 0 1000 16473 13180 20 0 2424 828 — R+ /0 0:00 top al

В примере у нас запущено два командных интерпретатора bash с PID равными 13180 и 16442. Далее идут 4-е процесса, которые были запущены из второго командного интерпретатора — их можно определить по PPID равному 16442. Теперь выйдите (команда exit) из второго интерпретатора и снова выполните команду top al в первом интерпретаторе:

$ top al F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND 0 1000 13180 1053 20 0 6292 3556 wait Ss /0 0:00 bash 0 1000 16679 13180 20 0 2424 824 — R+ /0 0:00 top al

Как видим завершился не только процесс с PID 16442, но и все процессы потомки (PPID 16442). Еще одно подтверждение того, что процесс-потомок не может существовать без родительского процесса.

Но, что делать если необходимо запустить процесс, и выйти из консоли так чтобы процесс продолжал работать в системе? Выход один — передать процесс-потомок другому процессу, который будет для него родительским. Такая возможность реализована в команде nohup. Данная команда позволяет запускать процессы, который будут оторваны от терминала если, терминал будет закрыт. Проводим эксперимент. Запускаем любую команду (например ping) через nohup в одной консоли и не выходя из нее смотрим на процессы:

$ nohup ping 127.0.0.1 &

$ top alx F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND 4 0 17326 1 20 0 7908 3208 wait Ss tty2 0:00 /bin/login — 4 1000 17427 17326 20 0 6304 3560 wait S tty2 0:00 -bash 4 1000 17450 17427 20 0 1848 556 wait_f S tty2 0:00 ping 127.0.0.1 0 1000 17517 13180 20 0 2424 848 — R+ /0 0:00 top alx

Видим, что сейчас процесс ping имеют PPID равный 17427 (то есть это потомок командного интерпретатора bash) и PID 17450. Теперь выйдем из командного интерпретатора bash с PID 17427 и снова посмотрим на процессы:

$ top alx F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND 4 1000 17450 1 20 0 1848 556 poll_s S ? 0:00 ping 127.0.0.1

Как видим несмотря на то, что мы вышли из командного интерпретатора, процесс с PID 17450 остался в системе и принял в качестве родительского, процесс с PID равным 1, то есть процесс init. Процесс 17450 будет существовать до тех пор пока будет существовать процесс init, или пока мы сами не завершим его работу с помощью команды kill.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *