Почему многие программы Unix используют сигналы, подобные USR1? Синтаксис для «kill». Команды kill и сигналы

Серия контента:

В современных операционных системах существует понятие межпроцессного взаимодействия (Inter-Process Communication – IPC) – это набор способов обмена данными между процессами и/или потоками. Одним из таких способов обмена служат сигналы. Концепцию сигналов поддерживает большинство операционных систем, но, например, Windows, не имеет их полноценной поддержки для использования в качестве одного из способов IPC – в подобных операционных системах сигналы лишь реализованы в стандартной библиотеке языка C.

Концепция сигналов

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

Сигналы имеют определенный жизненный цикл. Вначале сигнал создается – высылается процессом или генерируется ядром. Затем сигнал ожидает доставки в процесс-приемник. Принято считать, что период ожидания сигнала равен промежутку времени между созданием сигнала и действием, которое этот сигнал высылает. В конце жизненного цикла сигнала происходит его перехват (прием) процессом и выполнение связанных с сигналом действий.

Простые сигналы и надежные сигналы

Существует деление сигналов на простые и надежные.

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

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

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

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

Сигналы и системные вызовы

Сигнал может прийти к процессу в тот момент, когда процесс находится внутри какого-нибудь системного вызова, например, ожидает ввода данных в read(). В этом случае развитие событий может пойти по следующему пути: приложение не пытается перехватить сигнал и прерывается ядром (например, приход сигнала SIGTERM) – тогда терминал остается в нестандартной конфигурации, что может затруднить работу пользователя. Конечно, можно перехватить сигнал, очистить терминал в обработчике сигнала, а затем выйти, но достаточно сложно написать такой обработчик сигнала, который бы знал, что делала программа в момент прерывания, чтобы решить, следует ли выполнять очистку терминала, или нет.

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

Современная реализация сигналов заставляет медленные системные вызовы возвращать код ошибки EINTR, когда они прерываются приходящим сигналом. Быстрые системные вызовы должны завершаться перед тем, как сигнал будет доставлен. Медленный системный вызов – системный вызов, требующий неопределенного количества времени для своего завершения, например read(), wait(), write(). Все системные вызовы, зависящие от непредсказуемых ресурсов, таких как действия человека, сетевые данные и т.п., являются медленными. Естественно, все остальные системные вызовы – быстрые.

Обычно программа обрабатывает код ошибки EINTR и, если не произошло ничего фатального, перезапускает системный вызов. Большинство Unix-like операционных систем в настоящее время делает это по умолчанию – нужно лишь обработать сигнал в обработчике, а системный вызов будет перезапущен автоматически. В Linux по умолчанию системные вызовы не перезапускаются, но для каждого сигнала процесс может установить флаг, указывающий системе о необходимости перезапуска медленных системных вызовов, прерванных этим сигналом.

Посылка сигналов

Посылка сигналов от одного процесса к другому обычно осуществляется при помощи системного вызова kill(). Его первый параметр – PID процесса, которому посылается сигнал; второй параметр – номер сигнала. Если мы хотим послать сигнал SIGTERM процессу с PID 6666, то используем системный вызов kill() так:

kill(6666, SIGTERM);

Вместо положительного значения PID можно передать вызову равное по модулю, но отрицательное значение. Тогда сигнал будет послан всем процессам из группы с номером, равным модулю переданного PID"а. Если PID равен 0, то сигнал посылается всем процессам из группы, к которой относится и текущий процесс. Эти возможности используются в основном оболочками для управления заданиями.

Если в качестве PID передать в системный вызов kill() значение -1, то сигнал будет послан всем процессам за исключением init"а. Такая возможность применяется для завершения работы системы.

Более подробная информация по системному вызову kill() приведена в man 2 kill.

Послать сигнал самому себе процесс может при помощи системного вызова raise(), который принимает один параметр – номер сигнала. Пример:

raise(SIGTERM);

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

Перехват сигналов

Все программы, подчиняющиеся стандарту POSIX, регистрируют свои обработчики сигналов при помощи системного вызова sigaction(). Этот системный вызов имеет три параметра: первый – int signum – номер перехватываемого сигнала. Второй – struct sigaction * act – указатель на структуру, описывающую правила установки обработчика. Третий параметр – struct sigaction * oact – принимает уже установленные правила обработчика сигнала. Либо второй, либо третий (но не оба сразу!) параметр можно установить в NULL при необходимости.

Структура struct sigaction имеет следующее описание:

struct sigaction { __sighandler_t sa_handler; sigset_t sa_mask; int sa_flags; };

sa_handler – указатель на обработчик сигнала, причем обработчик должен быть объявлен следующим образом:

void signal_handler(int signo);

где единственный параметр – номер сигнала, который попал в обработчик. sa_handler также может быть равным SIG_IGN – сигнал игнорируется процессом, и SIG_DFL – сигнал вызывает действие по умолчанию, например прерывание процесса.

sa_mask – набор сигналов, которые должны блокироваться при вызове заданного в этой же структуре обработчика сигнала. Как их устанавливать, рассматривается далее.

Параметр sa_flags позволяет процессу модифицировать поведение сигнала. Параметр может принимать всего четыре значения, которые, впрочем, можно объединять при помощи битовой операции "ИЛИ":

  1. SA_NOCLDSTOP – отсылать сигнал SIGCHLD только в случае прерывания дочернего процесса. Приостановка дочернего процесса не вызывает посылки сигнала.
  2. SA_NODEFER – эмуляция простых (ненадежных) сигналов.
  3. SA_RESTHAND – после прихода сигнала его обработчик сбрасывается в SIG_DFL.
  4. SA_RESTART – перезапуск системного вызова после возврата из обработчика сигнала. Если флаг не установлен, то системный вызов возвращает ошибку EINTR.

Как обычно, при успешном выполнении sigaction() возвращается 0, а в случае ошибки – отрицательное значение.

Маска сигналов процесса

Добавление сигналов в структуру sigset_t sa_mask, ее очистка и т.п. осуществляются при помощи набора функций sigemptyset(), sigfillset(), sigaddset(), sigdelset(). Первые две функции принимают один параметр – указатель на структуру sigset_t. Эти функции очищают и заполняют всеми возможными сигналами структуру sigset_t соответственно.

Последние две функции, соответственно, добавляют и удаляют один определенный сигнал из структуры и имеют по два параметра. Их первый параметр – указатель на структуру sigset_t, а второй – номер сигнала.

Все рассмотренные выше функции возвращают 0 при успешном завершении и число, не равное нулю, – при ошибке.

Кроме того, существует еще одна функция, проверяющая, находится ли указанный сигнал в указанном наборе – sigismember(). Ее параметры совпадают с параметрами sigaddset(). Функция возвращает 1, если сигнал находится в наборе, 0 – если не находится, и отрицательное число – при возникшей ошибке.

Помимо всего прочего, мы можем задать список сигналов, доставка которых процессу будет заблокирована. Это выполняется при помощи функции sigprocmask(int how, const sigset_t * set, sigset_t * oldset).

Первый ее параметр описывает то, что должно выполняться:

  1. SIG_BLOCK – сигналы из набора set блокируются;
  2. SIG_UNBLOCK – сигналы из набора set разблокируются;
  3. SIG_SETMASK – сигналы из набора set блокируются, остальные разблокируются.

Второй параметр является указателем на тот самый набор, сигналы из которого блокируются/разблокируются. Если он равен NULL, то значение первого параметра игнорируется системным вызовом.

Третий параметр – указатель на уже используемую маску сигналов; его можно поставить в NULL, если эти данные не нужны.

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

Принципы написания обработчиков сигналов

Одно из самых главных правил написания обработчиков сигналов – обработчик должен быть реентерабельным, т.е. он должен допускать свой повторный вызов, когда процесс уже находится в обработчике. Нужно заботиться о том, чтобы обработчик сигналов не использовал глобальные структуры данных или медленные системные вызовы. Если избежать этого, увы, невозможно, то стоит позаботиться о защите от повторного вызова обработчика во время работы со структурой данных или с системным вызовом. Добиться этого можно, заблокировав на время доставку сигнала, обработчик которого сейчас работает, при помощи системного вызова sigprocmask(). Например, мы имеем обработчик сигнала SIGCHLD, выполняем в нем блокировку так:

void chld_handler(int signum) { sigset_t set; if (sigemptyset(&set)) { return;) if (sigaddset(&set, SIGCHLD)) { return; } if (sigprocmask(SIG_BLOCK, &set, NULL)) { return; } /* делаем здесь что-то важное */ if (sigprocmask(SIG_UNBLOCK, &set, NULL)) { return; } return; }

Кроме всего перечисленного выше, считается, что обработчик должен быть максимально простым – в идеале он должен выставлять некий флаг и завершаться, а все остальное должна выполнять основная часть программы.

Заключение

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

В завершение цикла будет рассказано о том, как получить (и отправить) дополнительные данные о сигнале, если вам не хватает обычной информации о том, что сигнал откуда-то пришел в ваш процесс.

Ресурсы для скачивания

static.content.url=http://www.сайт/developerworks/js/artrating/

ArticleID=495997

ArticleTitle=Работа с сигналами в Linux: Часть 1. Основы работы с сигналами

Сигналы - это запросы на прерывание, реализуемые на уровне процессов. Определено свыше тридцати различных сигналов, и они находят самое разное применение.

  • Сигналы могут посылаться между процессами как средство коммуникации.
  • Сигналы могут посылаться драйвером терминала для уничтожения или приостановки процессов, когда пользователь нажимает специальные комбинации клавиш, такие как или .
  • Сигналы могут посылаться в самых разных целях пользователем или администратором с помощью команды kill.
  • Сигналы могут посылаться ядром, когда процесс выполняет нелегальную инструкцию, например деление на нуль.
  • Сигналы могут посылаться ядром для уведомления процесса о "представляющем интерес" событии, таком как прекращение дочернего процесса или доступность данных в канале ввода-вывода.
  • Дамп памяти - это файл, содержащий образ памяти процесса. Его можно использовать для отладки.
Функции, связанные с этими комбинациями клавиш, могут назначаться другим клавишам помощью команды stty, но на практике такое встречается очень редко. Мы подразумеваем, что с данными клавишами связаны их стандартные функции. Когда поступает сигнал, возможен один из двух вариантов развития событий. Если процесс назначил сигналу подпрограмму обработки, то после вызова ей предоставляется информация о контексте, в котором был сгенерирован сигнал. В противном случае ядро выполняет от имени процесса действия, заданные по умолчанию. Эти действия зависят от сигнала. Многие сигналы приводят к завершению процесса, а в некоторых случаях при этом еще и создается дамп памяти. Процедура вызова обработчика называется перехватом сигнала. Когда выполнение обработчика завершается, процесс возобновляется с той точки, где был получен сигнал. Для того чтобы определенные сигналы не поступали в программу, нужно задать их игнорирование или блокирование. Игнорируемый сигнал просто пропускается и не влияет на работу процесса. Блокируемый сигнал ставится в очередь на обработку, но ядро не требует от процесса никаких действий до явного разблокирования сигнала. Обработчик вызывается для разблокированного сигнала только один раз, даже если в течение периода блокировки поступило несколько аналогичных сигналов. Ниже перечислены сигналы, которые должны быть известны любому системному администратору. Традиционно имена сигналов записываются прописными буквами. Иногда к именам добавляется префикс SIG (например, SIGHUP). Имя Описание Реакция Перехваты- Блоки- Дамп умолчанию 1 HUP Отбой Завершение Да Да Нет 2 INT Прерывание Завершение Да Да Нет 3 QUIT Выход Завершение Да Да Да 9 KILL Уничтожение Завершение Нет Нет Нет 10 BUS Ошибка на шине Завершение Да Да Да 11 SEGV Ошибка сегментации Завершение Да Да Да 12 TERM Запрос на завершение завершение Да Да Нет 13 STOP Останов Останов Нет Нет Нет 14 TSTP Сигнал останова, посылаемый Останов Да Да Нет с клавиатуры 15 CONT Продолжение после останова Игнорируется Да Нет Нет 16 WINCH Изменение окна Игнорируется Да Да Нет 17 USR1 Определяется пользователем Завершение Да Да Нет 18 USR2 Определяется пользователем Завершение Да Да Нет Существуют и другие сигналы, не показанные в табл. 5.1; большинство из них сообщает о всяких загадочных ошибках, например "неверная инструкция". По умолчанию такие сигналы, как правило, приводят к завершению программы и созданию дампа памяти. Перехват и блокирование сигналов обычно разрешены, так как есть достаточно "умные" программы, устраняющие последствия ошибок. Сигналы BUS и segv также посылаются при возникновении ошибок. Мы включили их в таблицу, поскольку они чрезвычайно распространены: обычно программа аварийно завершается именно из-за них. Сами по себе эти сигналы не имеют диагностической ценности. Они лишь указывают на факт неправильного обращения к памяти6. Сигналы KILL и STOP нельзя ни перехватить, ни заблокировать, ни проигнорировать. Сигнал KILL приводит к уничтожению процесса, которому он посылается, а сигнал STOP приостанавливает выполнение процесса до получения сигнала CONT. Сигнал CONT можно перехватить и проигнорировать, но нельзя заблокировать. Сигнал tstp представляет собой более "гибкую" версию сигнала STOP. Проще всего описать его как запрос на останов. Он генерируется драйвером терминала при нажатии пользователем комбинации клавиш . Программы, перехватывающие этот сигнал, обычно выполняют операции очистки, а затем посылают сами себе сигнал STOP. С другой стороны, программы могут игнорировать сигнал TSTP, чтобы их нельзя было остановить командой с клавиатуры. Эмуляторы терминалов посылают сигнал WINCH, когда происходит изменение их конфигурационных параметров (например, числа строк на виртуальном терминале). Это позволяет программам, которые взаимодействуют с эмуляторами, таким как текстовые редакторы, автоматически переконфигурировать себя в ответ на изменения. Если размер окна не удается правильно изменить, убедитесь в том, что сигнал WINCH генерируется и корректно обрабатывается. Хотя назначение сигналов KILL, INT, TERM, HUP и QUIT может показаться одинаковым, в действительности они совершенно различны.
  • Сигнал KILL не блокируется и приводит к безусловному завершению процесса на уровне ядра. По сути, процесс не успевает даже принять этот сигнал.
  • Сигнал INT посылается драйвером терминала при нажатии пользователем комбинации клавиш и служит запросом на завершение текущей операции. Перехватив этот сигнал, простые программы должны завершить работу или позволить уничтожить себя стандартному обработчику сигнала. Программы, в которых есть интерактивный режим командной строки, должны прекратить текущую операцию, выполнить очистку и снова перейти в режим ожидания.
  • Сигнал TERM представляет собой запрос на завершение программы. Предполагается, что процесс, получивший этот сигнал, осуществляет очистку и завершается.
  • У сигнала HUP есть две распространенные интерпретации. Во-первых, многие демоны воспринимают его как команду сброса. Если демон способен повторно про честь свой конфигурационный файл и адаптироваться к изменениям без перезапуска, сигнал HUP позволяет менять его поведение.
  • Во-вторых, этот сигнал иногда генерируется драйвером терминала при попытке уничтожить связанные с терминалом процессы. В основном это поведение сохранилось со времен использования проводных соединений терминалов и модемов. Отсюда и название "отбой".
  • Интерпретаторы семейства csh (tcsh и другие) обычно делают фоновые процессы невосприимчивыми к сигналу HUP, чтобы они могли продолжать свою работу, даже когда пользователь выходит из системы. Пользователи интерпретаторов семейства sh (ksh, bash и так далее) могут эмулировать такое поведение с помощью команды nohup.
  • Сигнал QUIT напоминает сигнал TERM, за исключением того, что по умолчанию стандартный обработчик создает дамп памяти.
Сигналы USR1 и USR2 не имеют стандартного назначения. Ими можно пользоваться в различных целях. Например, веб-сервер Apache интерпретирует сигнал USR1 как запрос на перезапуск. Отправка сигналов: команда kill Команду kill чаще всего используют для уничтожения процессов. Эта команда может послать процессу любой сигнал, но по умолчанию это сигнал TERM. Команду kill могут выполнять как рядовые пользователи (для своих собственных процессов), так и суперпользователь (для любого процесса). Она имеет следующий синтаксис: kill [-сигнал] идентификатор, где сигнал - это номер или символическое имя посылаемого сигнала, а идентификатор - номер искомого процесса. Команда kill без номера сигнала не гарантирует, что процесс будет уничтожен, поскольку сигнал TERM можно перехватывать, блокировать и игнорировать. Команда kill -9 идентификатор "гарантированно" уничтожает процесс, так как сигнал с номером 9 (KILL) не перехватывается. Используйте команду kill -9 только в случае, если "вежливый" запрос на завершение программы не был выполнен. Мы написали слово "гарантированно" в кавычках, так как иногда процессы переходят в такое состояние, в котором их нельзя завершить даже таким способом (обычно это связано с блокировкой ввода-вывода, например, при остановке жесткого диска). Единственный выход в такой ситуации - перезагрузка. Команда killall выполняет различные функции в системах UNIX и Linux. В Linux команда killall уничтожает процессы, заданные именем. Например, следующая команда уничтожает все процессы веб-сервера Apache. ubuntu$ sudo killall httpd Стандартная UNIX-команда killall, предусмотренная в дистрибутивах Solaris, HP-UX и AIX, не принимает параметры и просто уничтожает все процессы текущего пользователя. Ее выполнение от имени суперпользователя приведет к уничтожению процесса init и выключению компьютера. Ух! Команды pgrep и pkill в системах Solaris, HP-UX и Linux (но не в АЕХ) осуществляют поиск процессов, заданных именами (или другими атрибутами). Команда pgrep выводит идентификаторы процессов, удовлетворяющих заданному в командной строке критерию, а команда pkill посылает найденным процессам сигнал. Например, следующая команда посылает сигнал TERM всем процессам, выполняемым от имени пользователя ben. $ sudo pkill -u ben IPC, inter-process communication ). Фактически, сигнал - это асинхронное уведомление процесса о каком-либо событии. Когда сигнал послан процессу, операционная система прерывает выполнение процесса. Если процесс установил собственный обработчик сигнала , операционная система запускает этот обработчик, передав ему информацию о сигнале. Если процесс не установил обработчик, то выполняется обработчик по умолчанию.

Названия сигналов «SIG…» являются числовыми константами (макроопределениями Си) со значениями, определяемыми в заголовочном файле signal.h . Числовые значения сигналов могут меняться от системы к системе, хотя основная их часть имеет в разных системах одни и те же значения. Утилита kill позволяет задавать сигнал как числом, так и символьным обозначением.

Посылка сигналов

Сигналы посылаются:

  • с терминала, нажатием специальных клавиш или комбинаций (например, нажатие Ctrl-C генерирует SIGINT , Ctrl-\ SIGQUIT , а Ctrl-Z SIGTSTP);
  • ядром системы:
    • при возникновении аппаратных исключений (недопустимых инструкций, нарушениях при обращении в память, системных сбоях и т. п.);
    • ошибочных системных вызовах;
    • для информирования о событиях ввода-вывода;
  • одним процессом другому (или самому себе), с помощью системного вызова kill() , в том числе:

Сигналы не могут быть посланы завершившемуся процессу, находящемуся в состоянии «зомби» .

Обработка сигналов

Обработчик по умолчанию для большинства сигналов завершает выполнение процесса. Для альтернативной обработки всех сигналов, за исключением SIGKILL и SIGSTOP , процесс может назначить свой обработчик или игнорировать их возникновение модификацией своей сигнальной маски . Единственное исключение - процесс с pid 1 (init), который имеет право игнорировать или обрабатывать любые сигналы, включая KILL и STOP.

Безопасность

Процесс (или пользователь из оболочки) с эффективным UID , не равным 0 (UID суперпользователя), может посылать сигналы только процессам с тем же UID.

Классификация сигналов

POSIX определяет 28 сигналов, которые можно классифицировать следующим образом:

Название Код Действие по умолчанию Описание Тип
SIGABRT 6 Завершение с дампом памяти Сигнал посылаемый функцией abort() Управление
SIGALRM 14 Завершение Сигнал истечения времени, заданного alarm() Уведомление
SIGBUS 10 Завершение с дампом памяти Неправильное обращение в физическую память Исключение
SIGCHLD 18 Игнорируется Дочерний процесс завершен или остановлен Уведомление
SIGCONT 25 Продолжить выполнение Продолжить выполнение ранее остановленного процесса Управление
SIGFPE 8 Завершение с дампом памяти Ошибочная арифметическая операция Исключение
SIGHUP 1 Завершение Закрытие терминала Уведомление
SIGILL 4 Завершение с дампом памяти Недопустимая инструкция процессора Исключение
SIGINT 2 Завершение Сигнал прерывания (Ctrl-C) с терминала Управление
SIGKILL 9 Завершение Безусловное завершение Управление
SIGPIPE 13 Завершение Запись в разорванное соединение (пайп, сокет) Уведомление
SIGQUIT 3 Завершение с дампом памяти Сигнал «Quit» с терминала (Ctrl-\) Управление
SIGSEGV 11 Завершение с дампом памяти Нарушение при обращении в память Исключение
SIGSTOP 23 Остановка процесса Остановка выполнения процесса Управление
SIGTERM 15 Завершение Сигнал завершения (сигнал по умолчанию для утилиты kill) Управление
SIGTSTP 20 Остановка процесса Сигнал остановки с терминала (Ctrl-Z). Управление
SIGTTIN 26 Остановка процесса Попытка чтения с терминала фоновым процессом Управление
SIGTTOU 27 Остановка процесса Попытка записи на терминал фоновым процессом Управление
SIGUSR1 16 Завершение Пользовательский сигнал № 1 Пользовательский
SIGUSR2 17 Завершение Пользовательский сигнал № 2 Пользовательский
SIGPOLL 22 Завершение Событие, отслеживаемое poll() Уведомление
SIGPROF 29 Завершение Истечение таймера профилирования Отладка
SIGSYS 12 Завершение с дампом памяти Неправильный системный вызов Исключение
SIGTRAP 5 Завершение с дампом памяти Ловушка трассировки или брейкпоинт Отладка
SIGURG 21 Игнорируется На сокете получены срочные данные Уведомление
SIGVTALRM 28 Завершение Истечение «виртуального таймера» Уведомление
SIGXCPU 30 Завершение с дампом памяти Процесс превысил лимит процессорного времени Исключение
SIGXFSZ 31 Завершение с дампом памяти Процесс превысил допустимый размер файла Исключение

При обработке исключений и отладочных сигналов перед завершением процесс может записать в текущий каталог файл с дампом памяти процесса (англ. core image ), используя который, отладчик может восстановить условия, при которых возникло данное исключение. Иногда (например, для программ, выполняемых от имени суперпользователя) дамп памяти не создаётся из соображений безопасности.

SA_SIGINFO

Обычно обработчик сигнала получает только один аргумент - номер сигнала (это позволяет использовать одну функцию-обработчик для нескольких сигналов). Если при задании обработчика сигнала (функцией sigaction()) указать опцию SA_SIGINFO, то в обработчик будут переданы ещё два аргумента:

  1. указатель на структуру siginfo_t , включающую:
    • битовую маску дополнительных «кодов сигнала», определяющих причину его возникновения;
    • идентификатор процесса (PID), пославшего сигнал;
    • эффективный идентификатор пользователя (UID), от имени которого выполняется процесс (например, утилита kill), пославший сигнал;
    • адрес инструкции, в которой возникло исключение;
    • и т. п.
  2. указатель на «машинный контекст» на момент возникновения сигнала (со «стеком сигнала» - дополнительными данными, которые помещаются в стек при вызове некоторых сигналов-исключений).

Большинство дополнительных кодов специфичны для каждого сигнала. Коды, общие для всех сигналов:

См. также

Напишите отзыв о статье "Сигналы (UNIX)"

Ссылки

  • - Концепция сигналов (IEEE Std 1003.1, 2004 Edition)
  • - Описание структур и констант, связанных с сигналами (IEEE Std 1003.1, 2004 Edition)
  • - «Правила использования сигналов в Unix» (Сообщение в конференции RU.UNIX.PROG)

Отрывок, характеризующий Сигналы (UNIX)

– Целый вечер вам буду петь, – сказала Наташа.
– Волшебница всё со мной сделает! – сказал Денисов и отстегнул саблю. Он вышел из за стульев, крепко взял за руку свою даму, приподнял голову и отставил ногу, ожидая такта. Только на коне и в мазурке не видно было маленького роста Денисова, и он представлялся тем самым молодцом, каким он сам себя чувствовал. Выждав такт, он с боку, победоносно и шутливо, взглянул на свою даму, неожиданно пристукнул одной ногой и, как мячик, упруго отскочил от пола и полетел вдоль по кругу, увлекая за собой свою даму. Он не слышно летел половину залы на одной ноге, и, казалось, не видел стоявших перед ним стульев и прямо несся на них; но вдруг, прищелкнув шпорами и расставив ноги, останавливался на каблуках, стоял так секунду, с грохотом шпор стучал на одном месте ногами, быстро вертелся и, левой ногой подщелкивая правую, опять летел по кругу. Наташа угадывала то, что он намерен был сделать, и, сама не зная как, следила за ним – отдаваясь ему. То он кружил ее, то на правой, то на левой руке, то падая на колена, обводил ее вокруг себя, и опять вскакивал и пускался вперед с такой стремительностью, как будто он намерен был, не переводя духа, перебежать через все комнаты; то вдруг опять останавливался и делал опять новое и неожиданное колено. Когда он, бойко закружив даму перед ее местом, щелкнул шпорой, кланяясь перед ней, Наташа даже не присела ему. Она с недоуменьем уставила на него глаза, улыбаясь, как будто не узнавая его. – Что ж это такое? – проговорила она.
Несмотря на то, что Иогель не признавал эту мазурку настоящей, все были восхищены мастерством Денисова, беспрестанно стали выбирать его, и старики, улыбаясь, стали разговаривать про Польшу и про доброе старое время. Денисов, раскрасневшись от мазурки и отираясь платком, подсел к Наташе и весь бал не отходил от нее.

Два дня после этого, Ростов не видал Долохова у своих и не заставал его дома; на третий день он получил от него записку. «Так как я в доме у вас бывать более не намерен по известным тебе причинам и еду в армию, то нынче вечером я даю моим приятелям прощальную пирушку – приезжай в английскую гостинницу». Ростов в 10 м часу, из театра, где он был вместе с своими и Денисовым, приехал в назначенный день в английскую гостинницу. Его тотчас же провели в лучшее помещение гостинницы, занятое на эту ночь Долоховым. Человек двадцать толпилось около стола, перед которым между двумя свечами сидел Долохов. На столе лежало золото и ассигнации, и Долохов метал банк. После предложения и отказа Сони, Николай еще не видался с ним и испытывал замешательство при мысли о том, как они свидятся.
Светлый холодный взгляд Долохова встретил Ростова еще у двери, как будто он давно ждал его.
– Давно не видались, – сказал он, – спасибо, что приехал. Вот только домечу, и явится Илюшка с хором.
– Я к тебе заезжал, – сказал Ростов, краснея.
Долохов не отвечал ему. – Можешь поставить, – сказал он.
Ростов вспомнил в эту минуту странный разговор, который он имел раз с Долоховым. – «Играть на счастие могут только дураки», сказал тогда Долохов.
– Или ты боишься со мной играть? – сказал теперь Долохов, как будто угадав мысль Ростова, и улыбнулся. Из за улыбки его Ростов увидал в нем то настроение духа, которое было у него во время обеда в клубе и вообще в те времена, когда, как бы соскучившись ежедневной жизнью, Долохов чувствовал необходимость каким нибудь странным, большей частью жестоким, поступком выходить из нее.
Ростову стало неловко; он искал и не находил в уме своем шутки, которая ответила бы на слова Долохова. Но прежде, чем он успел это сделать, Долохов, глядя прямо в лицо Ростову, медленно и с расстановкой, так, что все могли слышать, сказал ему:
– А помнишь, мы говорили с тобой про игру… дурак, кто на счастье хочет играть; играть надо наверное, а я хочу попробовать.
«Попробовать на счастие, или наверное?» подумал Ростов.
– Да и лучше не играй, – прибавил он, и треснув разорванной колодой, прибавил: – Банк, господа!
Придвинув вперед деньги, Долохов приготовился метать. Ростов сел подле него и сначала не играл. Долохов взглядывал на него.
– Что ж не играешь? – сказал Долохов. И странно, Николай почувствовал необходимость взять карту, поставить на нее незначительный куш и начать игру.
– Со мной денег нет, – сказал Ростов.
– Поверю!
Ростов поставил 5 рублей на карту и проиграл, поставил еще и опять проиграл. Долохов убил, т. е. выиграл десять карт сряду у Ростова.
– Господа, – сказал он, прометав несколько времени, – прошу класть деньги на карты, а то я могу спутаться в счетах.
Один из игроков сказал, что, он надеется, ему можно поверить.
– Поверить можно, но боюсь спутаться; прошу класть деньги на карты, – отвечал Долохов. – Ты не стесняйся, мы с тобой сочтемся, – прибавил он Ростову.
Игра продолжалась: лакей, не переставая, разносил шампанское.
Все карты Ростова бились, и на него было написано до 800 т рублей. Он надписал было над одной картой 800 т рублей, но в то время, как ему подавали шампанское, он раздумал и написал опять обыкновенный куш, двадцать рублей.
– Оставь, – сказал Долохов, хотя он, казалось, и не смотрел на Ростова, – скорее отыграешься. Другим даю, а тебе бью. Или ты меня боишься? – повторил он.
Ростов повиновался, оставил написанные 800 и поставил семерку червей с оторванным уголком, которую он поднял с земли. Он хорошо ее после помнил. Он поставил семерку червей, надписав над ней отломанным мелком 800, круглыми, прямыми цифрами; выпил поданный стакан согревшегося шампанского, улыбнулся на слова Долохова, и с замиранием сердца ожидая семерки, стал смотреть на руки Долохова, державшего колоду. Выигрыш или проигрыш этой семерки червей означал многое для Ростова. В Воскресенье на прошлой неделе граф Илья Андреич дал своему сыну 2 000 рублей, и он, никогда не любивший говорить о денежных затруднениях, сказал ему, что деньги эти были последние до мая, и что потому он просил сына быть на этот раз поэкономнее. Николай сказал, что ему и это слишком много, и что он дает честное слово не брать больше денег до весны. Теперь из этих денег оставалось 1 200 рублей. Стало быть, семерка червей означала не только проигрыш 1 600 рублей, но и необходимость изменения данному слову. Он с замиранием сердца смотрел на руки Долохова и думал: «Ну, скорей, дай мне эту карту, и я беру фуражку, уезжаю домой ужинать с Денисовым, Наташей и Соней, и уж верно никогда в руках моих не будет карты». В эту минуту домашняя жизнь его, шуточки с Петей, разговоры с Соней, дуэты с Наташей, пикет с отцом и даже спокойная постель в Поварском доме, с такою силою, ясностью и прелестью представились ему, как будто всё это было давно прошедшее, потерянное и неоцененное счастье. Он не мог допустить, чтобы глупая случайность, заставив семерку лечь прежде на право, чем на лево, могла бы лишить его всего этого вновь понятого, вновь освещенного счастья и повергнуть его в пучину еще неиспытанного и неопределенного несчастия. Это не могло быть, но он всё таки ожидал с замиранием движения рук Долохова. Ширококостые, красноватые руки эти с волосами, видневшимися из под рубашки, положили колоду карт, и взялись за подаваемый стакан и трубку.

Сигналы — программные прерывания. Они используются для связи между процессами в UNIX и UNIX-подобных операционных систем, таких как Linux, Mac OS.

Сигналы использовались еще с Bell Labs UNIX в 1970 и сегодня официально определено стандартом POSIX. Когда сигнал поступает на процесс, операционная система прерывает нормальный поток выполнения процесса и обеспечивает уведомление.

Не имеет значения, какую операционную систему вы используете, вы несомненно столкнетесь с тем что ваши приложения, блокируются и отказаться работать должным образом. В Unix, Linux, есть команда «kill», которую вы можете использовать, чтобы прекратить процесс немедленно, но и не только это, но об этом немного позже я расскажу. В этой статье «Команда kill в Unix/Linux» я расскажу и покажу на готовых примерах различные команды утилиты kill.

Команды kill и сигналы

Когда вы выполняете команду «kill», вы на самом деле посылает е сигнал к системе и даете указание расторгнуть работу некорректной роботы приложения. Существует в общей сложности 60 сигналов, которые можно использовать, но все, что вы действительно должны знать, SIGTERM (15) и SIGKILL (9).

Вы можете просмотреть все сигналы с помощью команды:

# kill -l

На моей MacOS:

Я постараюсь рассказать о всех сигналах, но для самого начала поговорим только о самых важных и часто использующихся.

Основные сигналы

Следующие сигналы являются частью стандарта POSIX. Каждый сигнал макрос, определенный в Файл заголовка системы. Они, как правило, сокращенны, без их SIG- префикса; например SIGHUP часто называют просто как HUP.

SIGTERM – Этот сигнал запрашивает остановку процесса который работает. Этот сигнал может быть проигнорирован.Процессу дается время, чтобы хорошо выключился. Когда программа хорошо выключается, это означает, что ей дано время, чтобы спасти его прогресс и освободить ресурсы. Другими словами, он не «forced» прекращение работы процесса.

SIGKILL – сигнал SIGKILL заставляет процесс прекратить выполнение своей работы немедленно. Программа не может игнорировать этот сигнал. Несохраненный прогресс будет потерян.

Синтаксис для «kill».

Синтаксис команды такой:

# kill PID(s)

# kill [-s] [-l] %pid

Сигнал по умолчанию (если он не указан) является SIGTERM. Когда данный сигнал не помогает и не работает, вы можете использовать следующие опции для «kill» чтобы завершить процесс принудительно:

# kill SIGKILL PID

# kill -9 PID

где «-9» — это флаг относится к сигналу SIGKILL.

Если вы не знаете какой нужно использовать PID приложения которого следует избавиться, то запустите команду:

$ ps -aux

А если знаете конкретное приложение (например apache), то можно отсеять ненужное и вывести все процессы по данной службе:

$ ps -aux | grep apache

И это отобразит все запущенные приложения вместе с его PID-ом(ами).

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

# kill -9 3629

Стоит также отметить, что вы можете использовать несколько процессов одновременно чтобы их можно было » убить»:

# kill -9 PID1 PID2 PID 3

Перезагурзить конфигурационные файлы или перезапуск утилит:

# kill -1 number_of_PID

Особенно полезными сигналы включают HUP, INT, kill, STOP, CONT, и 0.

Варианты таковы:

-s signal_name
Символическое имя сигнала, задающее сигнал для отправки сигнала не по умолчанию.

-l
Если операнд не указан, то показать имена сигналов; В противном случае, написать название сигнала, соответствующего exit_status.

-signal_name
Символическое имя сигнала, задающее сигнал для отправки в TERM по умолчанию.

-signal_number
Неотрицательное десятичное целое, задающее сигнал для отправки в TERM по умолчанию.

Следующие PID-ы, имеют особое значение:
-1 Если суперпользователь, то транслирует сигнал всем процессам; в противном случае вещает на все процессыbelong-
ing для пользователя.

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

  • 1 HUP (hang up) — повесить.
  • 2 INT (interrupt) — прерывание.
  • 3 QUIT (quit) — выход.
  • 6 ABRT (abort) — прерывания.
  • 9 KILL (non-catchable, non-ignorable kill)
  • 14 ALRM (alarm clock) — будильник.
  • 15 TERM (software termination signal) — Программное обеспечение для прекращения сигнала.

PKill

Команда «pkill» позволяет использовать расширенные шаблоны регулярных выражений и других критериев соответствия. Вместо того чтобы использовать PID, теперь вы можете убить приложение, введя имя процесса. Например, чтобы убитьбраузер Firefox , просто запустите команду:

# pkill Firefox

Так как он соответствует шаблону регулярного выражения, вы также можете ввести часть имени процесса, например:

# pkill fire

Чтобы избежать «убийства» неправильных процессов, вы можете сделать «pgrep -l [имя_процесса]» в список подходящих процессов.

Pkill команда имеет гораздо больше вариантов, например если указать опцию «-u», то она позволит вам указать имя пользователя или ID. В этом примере мы посылаем сигнал TERM всем процессам, принадлежащие пользователю ‘nobody’:

# pkill -u nobody

Killall

Killall использует имя процесса, а вместо PID, и он «убивает» все экземпляры процесса с тем же именем. Например, если вы используете несколько экземпляров браузера Firefox, вы можете убить их всех с помощью команды:

# killall firefox

В Gnome, вы можете перезапустить Nautilus с помощью команды:

# killall nautilus

xkill

Xkill является графическим способом «убить» приложение. При вводе «XKill» в терминале, курсор мыши будет немедленно стать «крест». Все, что вам нужно сделать, это нажать «крест» на провинившихся приложение и он убьет приложение мгновенно. Если вы заинтересованы, вы можете добавить сочетание клавиш для включения функции XKill.

Еще сигналы которые используются

SIGABRT

Этот сигнал посылает сигнал процессу, чтобы прервать операцию. ABRT как правило, направлен на сам процесс, когда он вызывает функцию abort() языка программирования С, чтобы сигнализировать аварийное завершение, но он может быть направлен из любого процесса, как и любой другой сигнал.

SIGALRM, SIGVTALRM и SIGPROF

ALRM, VTALRM и / или сигнал PROF отправляется процессу, когда лимит времени, указанный при вызове функции сигнализации (например, setitimer) истекает.

ALRM

Посылается, когда настоящее время или часы с течением времени.

VTALRM

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

PROF

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

SIGBUS

BUS сигнал посылает процессу, когда это приводит к ошибке шины. Условия, которые приводят к данному сигналу, например, неправильное выравнивание доступа к памяти или отсутствие физического адреса.

SIGCHLD

Сигнал CHLD отправляет процессу, когда дочерний процесс завершается, прерывается или возобновляется после прерывания. Один из распространенного использование сигнала — это дать сигнал ОС на очистку ресурсов, которые используются в процессе дочернего процесса после его окончания без явного системного вызова.

SIGCONT

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

SIGFPE

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

SIGHUP

Сигнал HUP посылает процессу, когда его управляющий терминал закрыт. Первоначально он был разработан, чтобы уведомить процесс после последовательного падения линии (HUP ответственный за «зависания»). В современных системах, этот сигнал обычно означает, что контроль псевдо или виртуальным терминалом был закрыт.

SIGILL

ILL сигнал, посылаемый процессу при попытке выполнить вредоносные, неизвестные или привилегированные команды (инструкции).

SIGINT

Сигнал INT посылает процессу от управляющего терминала, когда пользователь желает прервать процесс. Это как правило, инициируется нажатием Control-C, но на некоторых системах, «delete» или «break».

SIGKILL

Сигнал KILL посылает процессу чтобы он немедленно прекратил работу. В отличие от SIGTERM и SIGINT этот сигнал не может быть захвачен или проигнорирован и принимающий процесс не может выполнить какие-либо очистку после получения этого сигнала.

SIGPIPE

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

SIGQUIT

QUIT сигнал посылается процессу от его управляющего терминала, когда пользователь запрашивает процесс выполнения дампа.

SIGSEGV

Сигнал SEGV отправляется в процесс, когда он делает недопустимую ссылку виртуальной памяти или сбой сегментации, то есть когда он выполняет нарушение сегментации.

SIGSTOP

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

SIGTERM

Сигнал TERM посылается в процесс чтобы запросить о его прекращении. В отличие от сигнала «kill», он может быть и интерпретируемым или игнорируемым в процессе. Это позволяет процессу выполнять «nice» выполнение для прекращения высвобождения ресурсов и сохранения состояния в случае необходимости. Следует отметить, что SIGINT почти идентичен SIGTERM.

SIGTSTP

Сигнал TSTP посылается в процесс его управляющего терминала и говорит ему, что нужно временно приостановить. Это обычно инициируется пользователем нажатием Control-Z. В отличие от SIGSTOP, этот процесс может зарегистрировать обработчик сигнала или чтобы игнорировать сигнал.

SIGTTIN и SIGTTOU

В TTIN и TTOU сигналы посылаются процессу, когда он пытается прочитать или записать соответственно с (tty) терминала на заднем плане. Как правило, этот сигнал может быть получен только с помощью процессов находящихся под контролем рабочей панели; демоны не имеют управляющие терминалы и никогда не должны получать этот сигнал.

SIGUSR1 и SIGUSR2

Сигналы USR1 и USR2 отправляются процессу и указывают определенные пользователем условия.

SIGPOLL

Сигнал POLL отправляется в процессе, когда происходит асинхронное событие ввода / вывода.

SIGSYS

Сигнал SYS отправляется в процессе, когда он пропускает плохой аргумент для системного вызова.

SIGTRAP

TRAP сигнал посылает процессу когда возникает состояние что отладчик просил быть информированным — Например, когда конкретная функция выполняется или когда меняется определенное значение переменной.

SIGURG

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

SIGXCPU

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

SIGXFSZ

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

SIGRTMIN to SIGRTMAX

Сигналы RTMIN — RTMAX предназначены для использования в пользовательских целей. Они сигналы реального времени.

Разные сигналы

Следующие сигналы не стандартизированы POSIX, но иногда используются на некоторых системах.

SIGEMT

Сигнал ЕМТ отправляется в процессе, когда происходит прерывание эмулятора.

SIGINFO

Сигнал INFO отправляется в процессе, когда запрос статуса получен от управляющего терминала.

SIGPWR

Сигнал PWR отправляется в процессе, когда система испытывает сбой питания.

SIGLOST

LOST сигнал посылается к процессу, когда «file lock» теряется.

SIGWINCH

Сигнал WINCH отправляется в процессе, когда его управляющий терминал меняет свой размер.

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

Сигналы могут быть отправлены с клавиатуры. Несколько стандартных значений по умолчанию перечислены ниже. По умолчанию сочетания клавиш для отправки сигналов прерывания может быть определен с помощью команды stty.

CTRL-C

Отправить SIGINT (прерывание). По умолчанию это вызывает процесс прекращается.

CTRL-Z

Отправить SIGTSTP (Suspend). По умолчанию это вызывает процесс приостановить все операции.

CTRL-\

Отправить SIGQUIT (Quit). По умолчанию это вызывает процесс прекратить немедленно и сбросить ядро.

CTRL-T

Отправить SIGINFO (INFO). По умолчанию это заставляет операционную систему отображать информацию о команде. Не поддерживается на всех системах.

вывод

Когда приложения ведут себя неправильно и вызвают к зависанию системы, это очень заманчиво, чтобы перезагрузить компьютер и начать сеанс снова и снова. С помощью этих команд «kill», вы сможете лучше управлять плохим поведением приложений которые вызывают или могут вызвать крах системы. На этом, я завершаю данную тему «Команда kill в Unix/Linux».




Top