Форма межпроцессного взаимодействия в компьютерных системах
Сигналы — это стандартизированные сообщения, отправляемые работающей программе для запуска определенного поведения, например, выхода или обработки ошибок. Они представляют собой ограниченную форму межпроцессного взаимодействия (IPC), обычно используемую в Unix , Unix-подобных и других POSIX -совместимых операционных системах.
Сигнал — это асинхронное уведомление, отправляемое процессу или определенному потоку в том же процессе, чтобы уведомить его о событии. Обычно сигналы используются для прерывания, приостановки, завершения или уничтожения процесса. Сигналы появились в Bell Labs Unix 1970-х годов и позднее были определены в стандарте POSIX .
При отправке сигнала операционная система прерывает нормальный поток выполнения целевого процесса для доставки сигнала. Выполнение может быть прервано во время любой неатомарной инструкции . Если процесс ранее зарегистрировал обработчик сигнала , эта процедура выполняется. В противном случае выполняется обработчик сигнала по умолчанию.
Встроенные программы могут использовать сигналы для межпроцессного взаимодействия, поскольку сигналы отличаются своей алгоритмической эффективностью .
Сигналы похожи на прерывания , разница в том, что прерывания опосредуются ЦП и обрабатываются ядром , в то время как сигналы опосредуются ядром (возможно, через системные вызовы) и обрабатываются отдельными процессами . [ необходима ссылка ] Ядро может передать прерывание как сигнал процессу, который его вызвал (типичными примерами являются SIGSEGV , SIGBUS , SIGILL и SIGFPE).
История
- В версии 1 Unix (1971) имелись отдельные системные вызовы для перехвата прерываний, завершений работы и машинных ловушек.
- kill появился в версии 2 (1972).
- Версия 4 (1973) объединила все ловушки в один вызов, сигнал .
- Версия 5 (1974) могла посылать произвольные сигналы. [1]
- В версии 7 (1979) каждая пронумерованная ловушка получила символическое название.
- План 9 от Bell Labs (конец 80-х) заменил сигналы нотами , которые позволяют отправлять короткие произвольные строки. [2]
Отправка сигналов
Системный вызов kill (2) отправляет указанный сигнал указанному процессу, если разрешения позволяют. Аналогично, команда kill(1) позволяет пользователю отправлять сигналы процессам. Библиотечная функция raise(3) отправляет указанный сигнал текущему процессу.
Такие исключения , как деление на ноль , нарушение сегментации (SIGSEGV) и исключение с плавающей точкой (SIGFPE), приведут к созданию дампа ядра и завершению программы.
Ядро может генерировать сигналы для уведомления процессов о событиях. Например, SIGPIPE будет сгенерирован, когда процесс пишет в канал, который был закрыт читателем; по умолчанию это приводит к завершению процесса, что удобно при построении конвейеров оболочки .
Ввод определенных комбинаций клавиш на управляющем терминале запущенного процесса заставляет систему посылать ему определенные сигналы: [3]
- Ctrl-C (в старых Unix-системах DEL) отправляет сигнал INT («прерывание», SIGINT); по умолчанию это приводит к завершению процесса.
- Ctrl-Z отправляет сигнал TSTP («терминальная остановка», SIGTSTP ); по умолчанию это приводит к приостановке выполнения процесса. [4]
- Ctrl-\ отправляет сигнал QUIT (SIGQUIT); по умолчанию это приводит к завершению процесса и созданию дампа ядра.
- Ctrl-T (поддерживается не во всех UNIX) отправляет сигнал INFO (SIGINFO); по умолчанию и если поддерживается командой, это заставляет операционную систему отображать информацию о запущенной команде. [5]
Эти комбинации клавиш по умолчанию в современных операционных системах можно изменить с помощью команды stty .
Обработка сигналов
Обработчики сигналов могут быть установлены с помощью системного вызова signal(2) или sigaction(2) . Если обработчик сигнала не установлен для определенного сигнала, используется обработчик по умолчанию. В противном случае сигнал перехватывается и вызывается обработчик сигнала. Процесс также может указать два поведения по умолчанию, не создавая обработчик: игнорировать сигнал (SIG_IGN) и использовать обработчик сигнала по умолчанию (SIG_DFL). Есть два сигнала, которые нельзя перехватить и обработать: SIGKILL и SIGSTOP .
Риски
Обработка сигналов уязвима для условий гонки . Поскольку сигналы асинхронны, другой сигнал (даже того же типа) может быть доставлен процессу во время выполнения процедуры обработки сигналов.
Вызов sigprocmask (2) может использоваться для блокировки и разблокировки доставки сигналов. Заблокированные сигналы не доставляются процессу, пока не будут разблокированы. Сигналы, которые нельзя игнорировать (SIGKILL и SIGSTOP), не могут быть заблокированы.
Сигналы могут вызвать прерывание текущего системного вызова, оставляя приложению задачу управления непрозрачным перезапуском .
Обработчики сигналов должны быть написаны таким образом, чтобы не приводить к нежелательным побочным эффектам, например, изменению errno , изменению маски сигнала, изменению расположения сигнала и другим глобальным изменениям атрибутов процесса . Использование нереентерабельных функций , например, malloc или printf , внутри обработчиков сигналов также небезопасно. В частности, спецификация POSIX и страница руководства Linux signal (7) требуют, чтобы все системные функции, напрямую или косвенно вызываемые из функции сигнала, были асинхронно-сигнально-безопасными . [6] [7] Страница руководства signal-safety(7) дает список таких асинхронно-сигнально-безопасных системных функций (фактически системных вызовов ), в противном случае это неопределенное поведение . [8] Предлагается просто задать некоторую переменную в обработчике сигнала и протестировать ее в другом месте. [9]volatile sig_atomic_t
Обработчики сигналов могут вместо этого поместить сигнал в очередь и немедленно вернуться. Затем основной поток будет продолжаться «непрерывно», пока сигналы не будут извлечены из очереди, например, в цикле событий . «Непрерывно» здесь означает, что операции, которые блокируются, могут преждевременно вернуться и должны быть возобновлены , как упоминалось выше. Сигналы должны обрабатываться из очереди в основном потоке, а не рабочими пулами , поскольку это снова вводит проблему асинхронности. Однако управление очередью невозможно безопасным способом асинхронного сигнала только с sig_atomic_t , поскольку только отдельные чтения и записи в такие переменные гарантированно будут атомарными, а не инкрементами или (выборками)-декрементами, как это требовалось бы для очереди. Таким образом, фактически только один сигнал на обработчик может быть безопасно поставлен в очередь с sig_atomic_t , пока он не будет обработан.
Связь с аппаратными исключениями
Выполнение процесса может привести к возникновению аппаратного исключения , например, если процесс попытается выполнить деление на ноль или возникнет ошибка страницы .
В операционных системах типа Unix это событие автоматически изменяет контекст процессора для запуска выполнения обработчика исключений ядра . В случае некоторых исключений, таких как ошибка страницы , ядро имеет достаточно информации, чтобы полностью обработать само событие и возобновить выполнение процесса.
Однако другие исключения ядро не может обработать разумно, и вместо этого оно должно отложить операцию обработки исключений на процесс, вызвавший ошибку. Эта отсрочка достигается с помощью механизма сигналов, при котором ядро отправляет процессу сигнал, соответствующий текущему исключению. Например, если процесс попытается выполнить целочисленное деление на ноль на процессоре x86 , будет сгенерировано исключение ошибки деления , которое заставит ядро отправить сигнал SIGFPE процессу.
Аналогично, если процесс попытается получить доступ к адресу памяти за пределами своего виртуального адресного пространства , ядро уведомит процесс об этом нарушении с помощью SIGSEGV ( сигнал нарушения сегментации ). Точное соответствие между именами сигналов и исключениями, очевидно, зависит от ЦП, поскольку типы исключений различаются в зависимости от архитектуры.
Сигналы POSIX
Список ниже документирует сигналы, указанные в Single Unix Specification . Все сигналы определены как макроконстанты в <signal.h>
заголовочном файле. Имя макроконстанты состоит из префикса "SIG" , за которым следует мнемоническое имя сигнала.
Процесс может определить, как обрабатывать входящие сигналы POSIX . Если процесс не определяет поведение для сигнала, то используется обработчик по умолчанию для этого сигнала. В таблице ниже перечислены некоторые действия по умолчанию для совместимых с POSIX систем UNIX, таких как FreeBSD , OpenBSD и Linux .
- Переносной номер:
- Для большинства сигналов соответствующий номер сигнала определяется реализацией. В этом столбце перечислены номера, указанные в стандарте POSIX. [10]
- Действия объяснены:
- Terminate – Ненормальное завершение процесса. Процесс завершается со всеми последствиями _exit(), за исключением того, что статус, доступный для wait() и waitpid(), указывает на ненормальное завершение указанным сигналом.
- Terminate (core dump) – Ненормальное завершение процесса. Кроме того, могут возникнуть определенные реализацией ненормальные действия завершения, такие как создание файла core.
- Игнорировать – игнорировать сигнал.
- Остановить – остановить (или приостановить) процесс.
- Продолжить – продолжить процесс, если он остановлен; в противном случае игнорировать сигнал.
- СИГАБРТ иSIGIOT
- Сигнал SIGABRT отправляется процессу, чтобы сообщить ему о необходимости прерывания , т. е. завершения. Сигнал обычно инициируется самим процессом, когда он вызывает
abort()
функцию стандартной библиотеки C , но он может быть отправлен процессу извне, как и любой другой сигнал. - SIGIOT указывает на то, что ЦП выполнил явную инструкцию «trap» (без определенной функции) или нереализованную инструкцию (когда эмуляция недоступна).
- Примечание: «ловушка ввода/вывода» — неправильное название для любой инструкции «ловушки» ЦП. Термин отражает раннее использование таких инструкций, в основном для реализации функций ввода/вывода, но они не привязаны по своей сути к вводу/выводу устройства и могут использоваться для других целей, таких как связь между виртуальными и реальными хостами.
- SIGIOT и SIGABRT обычно являются одним и тем же сигналом, и получение этого сигнала может указывать на любое из вышеперечисленных состояний.
- СИГАЛРМ ,SIGVTALRM иСИГПРОФ
- Сигналы SIGALRM, SIGVTALRM и SIGPROF отправляются процессу при достижении соответствующего временного предела. Процесс устанавливает эти временные пределы, вызывая
alarm
или setitimer
. Временной предел для SIGALRM основан на реальном или тактовом времени; SIGVTALRM основан на процессорном времени, используемом процессом; а SIGPROF основан на процессорном времени, используемом процессом и системой от его имени (известном как таймер профилирования ). В некоторых системах SIGALRM может использоваться внутренне реализацией функции sleep
. - СИГБУС
- Сигнал SIGBUS отправляется процессу, когда он вызывает ошибку шины . Условиями, которые приводят к отправке сигнала, являются, например, неправильное выравнивание доступа к памяти или несуществующий физический адрес.
- СИГЧЛД
- Сигнал SIGCHLD отправляется процессу, когда дочерний процесс завершается , останавливается или возобновляется после остановки. Одним из распространенных способов использования сигнала является указание операционной системе очистить ресурсы, используемые дочерним процессом после его завершения без явного вызова системного
wait
вызова. - SIGCONT
- Сигнал SIGCONT дает указание операционной системе продолжить (перезапустить) процесс, ранее приостановленный сигналом SIGSTOP или SIGTSTP. Одним из важных применений этого сигнала является управление заданиями в оболочке Unix .
- СИГФПЭ
- Сигнал SIGFPE отправляется процессу, когда в оборудовании для арифметики с плавающей точкой или целыми числами обнаружено исключительное (но не обязательно ошибочное) состояние. Это может включать деление на ноль , переполнение или отсутствие значения в арифметике с плавающей точкой, переполнение целого числа , недопустимую операцию или неточное вычисление. Поведение может различаться в зависимости от оборудования.
- ПОДПИШИТЕСЬ
- Сигнал SIGHUP отправляется процессу, когда его управляющий терминал закрыт. Первоначально он был разработан для уведомления процесса о разрыве последовательной линии ( зависании ). В современных системах этот сигнал обычно означает, что управляющий псевдо- или виртуальный терминал закрыт. [11] Многие демоны (у которых нет управляющего терминала) интерпретируют получение этого сигнала как запрос на перезагрузку своих файлов конфигурации и очистку/повторное открытие своих файлов журналов вместо выхода. [12] nohup — это команда, заставляющая команду игнорировать сигнал.
- СИГИЛЛ
- Сигнал SIGILL отправляется процессу, когда он пытается выполнить недопустимую , неправильно сформированную, неизвестную или привилегированную инструкцию .
- SIGINT
- Сигнал SIGINT отправляется процессу его управляющим терминалом, когда пользователь хочет прервать процесс. Обычно это инициируется нажатием Ctrl+C , но в некоторых системах можно использовать символ " delete " или клавишу " break ". [13]
- SIGKILL
- Сигнал SIGKILL отправляется процессу, чтобы вызвать его немедленное завершение ( kill ). В отличие от SIGTERM и SIGINT, этот сигнал не может быть перехвачен или проигнорирован, и принимающий процесс не может выполнить какую-либо очистку при получении этого сигнала. Применяются следующие исключения:
- Процессы-зомби не могут быть завершены, поскольку они уже мертвы и ждут, когда их поглотят родительские процессы.
- Процессы, находящиеся в заблокированном состоянии, не завершатся, пока не проснутся снова.
- Процесс init является особенным: он не получает сигналы, которые не хочет обрабатывать, и поэтому может игнорировать SIGKILL. [14] Исключением из этого правила является время, когда init проходит ptraced в Linux. [15] [16]
- Непрерывно спящий процесс может не завершиться (и не освободить свои ресурсы) даже при отправке SIGKILL. Это один из немногих случаев, когда систему UNIX, возможно, придется перезагрузить для решения временной проблемы с программным обеспечением.
- SIGKILL используется в качестве последнего средства при завершении процессов в большинстве процедур завершения работы системы , если она добровольно не завершается в ответ на SIGTERM. Чтобы ускорить процедуру завершения работы компьютера, Mac OS X 10.6, также известная как Snow Leopard , отправляет SIGKILL приложениям, которые пометили себя как «чистые», что приводит к более быстрому завершению работы, предположительно без каких-либо негативных последствий. [17] Команда
killall -9
имеет похожий, хотя и опасный эффект, при выполнении, например, в Linux; она не позволяет программам сохранять несохраненные данные. У нее есть и другие параметры, и без них она использует более безопасный сигнал SIGTERM. - СИГПАЙП
- Сигнал SIGPIPE отправляется процессу, когда он пытается записать данные в канал без процесса, подключенного к другому концу.
- СИГПОЛЛ
- Сигнал SIGPOLL отправляется, когда событие произошло в явно отслеживаемом файловом дескрипторе. [18] Его использование фактически приводит к выполнению асинхронных запросов ввода-вывода , поскольку ядро будет опрашивать дескриптор вместо вызывающего. Он предоставляет альтернативу активному опросу .
- SIGRTMIN дляSIGRTMAX
- Сигналы SIGRTMIN — SIGRTMAX предназначены для использования в целях, определяемых пользователем. Это сигналы реального времени .
- СИГКВИТ
- Сигнал SIGQUIT отправляется процессу его управляющим терминалом, когда пользователь запрашивает завершение процесса и выполнение дампа ядра .
- СИГСЭГВ
- Сигнал SIGSEGV отправляется процессу, когда он делает недопустимую ссылку на виртуальную память или ошибку сегментации , т. е. когда он выполняет нарушение сегментации . [ 19]
- СИГНАЛ СТОП
- Сигнал SIGSTOP дает указание операционной системе остановить процесс для его последующего возобновления.
- СИГСИС
- Сигнал SIGSYS отправляется процессу, когда он передает неверный аргумент системному вызову . На практике этот тип сигнала встречается редко, поскольку приложения полагаются на библиотеки (например, libc ) для выполнения вызова. SIGSYS может быть получен приложениями, нарушающими правила безопасности Linux Seccomp, настроенные для их ограничения. SIGSYS также может использоваться для эмуляции внешних системных вызовов, например эмуляции системных вызовов Windows в Linux. [20]
- СИГТЕРМ
- Сигнал SIGTERM отправляется процессу для запроса на его завершение . В отличие от сигнала SIGKILL, он может быть перехвачен и интерпретирован или проигнорирован процессом. Это позволяет процессу выполнить корректное завершение, освобождая ресурсы и сохраняя состояние, если это необходимо. SIGINT почти идентичен SIGTERM.
- SIGTSTP
- Сигнал SIGTSTP отправляется процессу его управляющим терминалом , чтобы запросить его остановку ( terminal st o p ). Обычно он инициируется нажатием пользователем клавиши + . В отличие от SIGSTOP, процесс может зарегистрировать обработчик сигнала для сигнала или игнорировать его.CtrlZ
- СИГТТИН иСИГТТОУ
- Сигналы SIGTTIN и SIGTTOU отправляются процессу, когда он пытается выполнить чтение или запись соответственно с tty в фоновом режиме . Обычно эти сигналы принимаются только процессами под управлением задания ; демоны не имеют управляющих терминалов и, следовательно, никогда не должны получать эти сигналы.
- СИГТРАП
- Сигнал SIGTRAP отправляется процессу, когда возникает исключение (или ловушка ): условие, о котором отладчик запросил информирование, например, когда выполняется определенная функция или когда изменяется значение определенной переменной .
- СИГУРГ
- Сигнал SIGURG отправляется процессу, когда сокет имеет срочные или внеполосные данные, доступные для чтения.
- SIGUSR1 иSIGUSR2
- Сигналы SIGUSR1 и SIGUSR2 отправляются процессу для указания определяемых пользователем условий .
- SIGXCPU
- Сигнал SIGXCPU отправляется процессу, когда он использует ресурсы ЦП в течение времени, превышающего определенное предопределенное пользователем значение. [21] Прибытие сигнала SIGXCPU дает принимающему процессу возможность быстро сохранить любые промежуточные результаты и корректно завершить работу, прежде чем он будет завершен операционной системой с помощью сигнала SIGKILL.
- SIGXFSZ
- Сигнал SIGXFSZ отправляется процессу, когда размер файла превышает максимально допустимый размер .
- СИГВИНЧ
- Сигнал SIGWINCH отправляется процессу, когда его управляющий терминал изменяет свой размер (изменяется окно ) . [ 22]
Разные сигналы
Следующие сигналы не указаны в спецификации POSIX . Однако они иногда используются в различных системах.
- СИГЕМТ
- Сигнал SIGEMT отправляется процессу при возникновении ловушки эмулятора .
- СИГИНФО
- Сигнал SIGINFO отправляется процессу при получении запроса статуса ( информации ) от управляющего терминала.
- СИГПВР
- Сигнал SIGPWR отправляется процессу, когда в системе происходит сбой питания .
- СИГЛОСТ
- Сигнал SIGLOST отправляется процессу при потере блокировки файла .
- SIGSTKFLT
- Сигнал SIGSTKFLT отправляется процессу, когда сопроцессор сталкивается с ошибкой стека ( т . е . выталкивание, когда стек пуст, или вставка, когда он полон). [ 23] Он определен, но не используется в Linux, где ошибка стека сопроцессора x87 вместо этого генерирует SIGFPE. [24]
- SIGUNUSED
- Сигнал SIGUNUSED отправляется процессу, когда выполняется системный вызов с неиспользуемым номером системного вызова. Он является синонимом SIGSYS на большинстве архитектур. [23]
- SIGCLD
- Сигнал SIGCLD является синонимом SIGCHLD. [23]
Смотрите также
Ссылки
- ^ Макилрой, МД (1987). Исследовательский ридер Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (Технический отчет). CSTR. Bell Labs. 139.
- ^ Гальярди, Пьетро. «Программирование на языке C в Plan 9 от Bell Labs». doc.cat-v.org . Получено 22 января 2022 г. .
- ^ "Сигналы завершения". Библиотека GNU C) .
- ^ "Сигналы управления заданиями". Библиотека GNU C.
- ^ "Разные сигналы". Библиотека GNU C.
- ^ "The Open Group Base Specifications Issue 6, IEEE Std 1003.1, издание 2004 г.: Системные интерфейсы, глава 2". pubs.opengroup.org . Получено 20 декабря 2020 г. .
- ^ "signal(7) - страница руководства Linux". man7.org . Получено 20 декабря 2020 г. .
- ^ "signal-safety(7) - страница руководства Linux". man7.org . Получено 20 декабря 2020 г. .
- ^ "The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition: <signal.h>". pubs.opengroup.org . Получено 20 декабря 2020 г. .
- ^ "IEEE Std 1003.1-2017 - kill". IEEE, Open Group.
Соответствие между целыми значениями и используемым значением
sig
показано в следующем списке. Эффекты указания любого
signal_number,
отличного от перечисленных ниже, не определены.
- ^ Майкл Керриск (25 июля 2009 г.). "signal(7)". Руководство программиста Linux (версия 3.22) . Архив ядра Linux . Получено 23 сентября 2009 г. .
- ^ "perlipc(1)". Perl Programmers Reference Guide, версия 5.18 . perldoc.perl.org — Официальная документация по языку программирования Perl . Получено 21 сентября 2013 г. .
- ^ "Правильная обработка SIGINT и SIGQUIT" . Получено 6 октября 2012 г.
- ^ https://manpages.ubuntu.com/manpages/zesty/man2/kill.2.html Архивировано 28 января 2018 г. в разделе Wayback Machine ПРИМЕЧАНИЯ
- ^ "SIGKILL init process (PID 1)". Переполнение стека .
- ^ "Может ли root завершить процесс init?". Unix & Linux Stack Exchange .
- ^ "Mac Dev Center: Что нового в Mac OS X: Mac OS X v10.6". 28 августа 2009 г. Получено 18 ноября 2017 г.
- ^ "ioctl - управляет устройством STREAM". Спецификация системного вызова POSIX . The Open Group . Получено 19 июня 2015 г.
- ^ "Что такое "нарушение сегментации"?". support.microfocus.com . Получено 22 ноября 2018 г. .
- ^ "Syscall User Dispatch – Документация ядра Linux". kernel.org . Получено 11 февраля 2021 г. .
- ^ "getrlimit, setrlimit - управление максимальным потреблением ресурсов". Спецификация системного вызова POSIX . The Open Group . Получено 10 сентября 2009 г.
- ^ Clausecker, Robert (19 июня 2017 г.). "0001151: Ввести новый сигнал SIGWINCH и функции tcsetsize(), tcgetsize() для получения/установки размера окна терминала". Austin Group Defect Tracker . Austin Group . Получено 12 октября 2017 г. .
Принято как помечено
- ^ abc "signal(7) — страницы руководства Linux". manpages.courier-mta.org . Получено 22 ноября 2018 г. .
- ^ "Linux 3.0 x86_64: Когда возникает SIGSTKFLT?". Stack Overflow .
- Стивенс, В. Ричард (1992). Расширенное программирование в среде UNIX® . Рединг, Массачусетс: Addison Wesley. ISBN 0-201-56317-7.
- "The Open Group Base Specifications Issue 7, 2013 Edition". The Open Group . Получено 19 июня 2015 .
Внешние ссылки
- Таблица сигналов Unix, Али Аланджави, Университет Питтсбурга
- Man7.org Сигнальная страница Man7.org
- Введение в программирование сигналов Unix Введение в программирование сигналов Unix на Wayback Machine (архивировано 26 сентября 2013 г.)
- Еще одно введение в программирование сигналов Unix (запись в блоге, 2009 г.)
- UNIX и надежные сигналы POSIX Бариса Шимшека (хранится в Архиве Интернета )
- Обработчики сигналов Хеннинга Брауэра