Введение
Форма межпроцессного взаимодействия в компьютерных системах. Форма межпроцессного взаимодействия.
form of inter process communication
Сигналы — это стандартизированные сообщения, отправляемые работающей программе для инициирования определенного поведения, например, завершения работы или обработки ошибок. Они представляют собой ограниченную форму межпроцессного взаимодействия (IPC), обычно используемую в Unix, Unix-подобных и других операционных системах, соответствующих стандарту POSIX. Сигнал — это асинхронное уведомление, отправленное процессу или конкретному потоку в этом процессе для информирования о событии. Сигналы обычно используются для прерывания, приостановки, завершения или уничтожения процесса. Сигналы появились в Unix Bell Labs в 1970-х годах и впоследствии были специфицированы в стандарте POSIX. При отправке сигнала операционная система прерывает нормальный ход выполнения целевого процесса для доставки сигнала. Выполнение может быть прервано в любой неатомарной инструкции. Если процесс ранее зарегистрировал обработчик сигнала, выполняется эта подпрограмма. В противном случае выполняется обработчик сигнала по умолчанию. Встраиваемые программы могут находить сигналы полезными для межпроцессного взаимодействия, поскольку они отличаются алгоритмической эффективностью. Сигналы похожи на прерывания, но прерывания обрабатываются процессором и ядром, а сигналы обрабатываются ядром (возможно, через системные вызовы) и отдельными процессами. Ядро может передать прерывание процессу, вызвавшему его, в виде сигнала (типичные примеры — SIGSEGV, SIGBUS, SIGILL и SIGFPE).
История
Версия 1 Unix (1971) имела отдельные системные вызовы для перехвата прерываний, завершений работы и машинных ловушек. Появилась в версии 2 (1972). Версия 4 (1973) объединила все ловушки в один вызов, а версия 5 (1974) могла отправлять произвольные сигналы. В версии 7 (1979) каждой пронумерованной ловушке было присвоено символическое имя. Plan 9 from Bell Labs (конец 80-х) заменил сигналы сообщениями (нотами), позволяющими отправлять короткие произвольные строки.
Управление сигналами
Сигнальные обработчики могут быть установлены с помощью системных вызовов `signal` или `sigaction`. Если для конкретного сигнала не установлен обработчик, используется обработчик по умолчанию. В противном случае сигнал перехватывается и вызывается установленный обработчик. Процесс также может указать два стандартных действия без создания обработчика: игнорировать сигнал (SIG_IGN) и использовать обработчик по умолчанию (SIG_DFL). Существуют два сигнала, которые нельзя перехватить и обработать: SIGKILL и SIGSTOP.
Риски
Обработка сигналов подвержена гонкам данных. Поскольку сигналы асинхронны, другой сигнал (даже того же типа) может быть доставлен процессу во время выполнения обработчика сигнала. Функция может быть использована для блокировки и разблокировки доставки сигналов. Блокированные сигналы не доставляются процессу, пока не будут разблокированы. Сигналы, которые нельзя игнорировать (SIGKILL и SIGSTOP), не могут быть заблокированы. Сигналы могут прервать выполняемый системный вызов, оставляя управление возобновлением операции на усмотрение приложения. Обработчики сигналов должны быть написаны таким образом, чтобы не вызывать нежелательных побочных эффектов, например, изменение глобальных переменных, маски сигналов, обработчиков сигналов или других глобальных атрибутов процесса. Использование нереентерабельных функций, например, или , внутри обработчиков сигналов также небезопасно. В частности, спецификация POSIX и страница руководства Linux требуют, чтобы все системные функции, вызываемые непосредственно или косвенно из обработчика сигнала, были безопасны для асинхронных сигналов. Страница руководства содержит список таких функций (практически системные вызовы), в противном случае поведение не определено. Рекомендуется просто установить некоторую переменную в обработчике сигнала и проверить её в другом месте. Вместо этого обработчики сигналов могут помещать сигнал в очередь и немедленно возвращаться. Основной поток затем продолжит работу «непрерывно», пока сигналы не будут извлечены из очереди, например, в цикле обработки событий. «Непрерывно» здесь означает, что блокирующие операции могут возвращаться преждевременно и должны быть возобновлены, как упоминалось выше. Сигналы следует обрабатывать из очереди в основном потоке, а не в пуле рабочих потоков, поскольку это вновь вводит проблему асинхронности. Однако управление очередью невозможно реализовать безопасным для асинхронных сигналов способом, используя только , поскольку только отдельные операции чтения и записи таких переменных гарантированно атомарны, а не инкременты или (получение и) декременты, необходимые для очереди. Таким образом, фактически только один сигнал на обработчик может быть безопасно помещен в очередь до его обработки.
Связь с исключениями в отношении оборудования
Исполнение процесса может привести к генерации аппаратного исключения, например, при попытке деления на ноль или возникновении ошибки страницы. В Unix-подобных операционных системах это событие автоматически переключает контекст процессора для запуска обработчика исключений ядра. В случае некоторых исключений, таких как ошибка страницы, ядро располагает достаточной информацией для самостоятельной обработки события и возобновления выполнения процесса. Однако, другие исключения ядро не может обработать самостоятельно и должно передать операцию обработки исключения процессу, вызвавшему ошибку. Эта передача осуществляется посредством механизма сигналов, когда ядро отправляет процессу сигнал, соответствующий возникшему исключению. Например, если процесс попытался выполнить целочисленное деление на ноль на процессоре x86, будет сгенерировано исключение ошибки деления, которое заставит ядро отправить процессу сигнал SIGFPE. Аналогично, если процесс попытается обратиться к адресу памяти за пределами своего виртуального адресного пространства, ядро уведомит процесс о нарушении через сигнал SIGSEGV (сигнал нарушения сегментации). Очевидно, что точное соответствие между именами сигналов и исключениями зависит от типа процессора, поскольку типы исключений различаются в разных архитектурах.
Различные сигналы
Следующие сигналы не определены в спецификации POSIX. Однако они иногда используются в различных системах. Сигнал SIGEMT посылается процессу при возникновении ловушки эмулятора. Сигнал SIGINFO посылается процессу при получении запроса статуса (информации) от управляющего терминала. Сигнал SIGPWR посылается процессу при сбое питания системы. Сигнал SIGLOST посылается процессу при потере блокировки файла. Сигнал SIGSTKFLT посылается процессу при возникновении ошибки стека сопроцессора (то есть при извлечении из пустого стека или при записи в полный стек). Он определён, но не используется в Linux, где ошибка стека сопроцессора x87 вместо этого генерирует SIGFPE. Сигнал SIGUNUSED посылается процессу при выполнении системного вызова с неиспользуемым номером системного вызова. Он является синонимом SIGSYS на большинстве архитектур. Сигнал SIGCLD является синонимом SIGCHLD.