Когда обработчик сигнала прерывает заблокированный системный вызов, этот системный вызов завершается с ошибкой EINTR. Мы можем воспользоваться этой моделью поведения для, например, установки таймера на блокирующий системный вызов. При необходимости прерванные системные вызовы могут быть перезапущены вручную. Кроме того, установка обработчика сигнала с помощью функции sigaction() с флагом SA_RESTART приводит к автоматическому перезапуску многих (но не всех) системных вызовов.
См. источники, перечисленные в разделе 20.15.
21.1. Реализуйте функцию abort().
22. Сигналы: дополнительные возможности
В этой главе мы завершим рассматривать сигналы. Здесь мы обсудим некоторые более сложные темы, включая такие, как:
• файлы дампа ядра;
• особые случаи доставки сигнала, его диспозиции и обработки;
• синхронная и асинхронная генерация сигналов;
• когда и в какой очередности доставляются сигналы;
• сигналы реального времени;
• использование функции sigsuspend() для настройки сигнальной маски процесса и ожидания прибытия сигнала;
• использование функции sigwaitinfo() (и sigtimedwait()) для синхронного ожидания доставки сигнала;
• использование функции signalfd() для получения сигнала через файловый дескриптор;
• старые сигнальные API операционной системы BSD.
Некоторые сигналы заставляют процесс создать файл дампа ядра и завершиться (см. табл. 20.1). Дамп ядра — это файл, содержащий образ памяти процесса на момент его завершения. (Термин
Одним из способов заставить программу создать файл дампа ядра является ввод символа
$ ulimit — c unlimited
$ sleep 30
Quit (core dumped)
$ ls — l core
— rw- 1 mtk users 57344 Nov 30 13:39 core
В данном примере оболочка распечатывает сообщение Quit (core dumped) после обнаружения того, что дочерний процесс (запустивший программу sleep) был завершен сигналом SIGQUIT с созданием файла дампа ядра.
Файл дампа ядра был создан в рабочем каталоге процесса и назван core. В скором времени будет рассказано, как можно изменить эти настройки по умолчанию.
Во многих реализациях есть инструмент (например, gcore во FreeBSD и Solaris), позволяющий получить дамп ядра запущенного процесса. Аналогичная функциональность доступна и на Linux за счет подключения процесса с помощью gdb и последующего запуска команды gcore.
Файл дампа ядра не создается в следующих случаях.
• У процесса нет права записи файла дампа ядра. Это может произойти, если у процесса отсутствуют права записи в каталоге, в котором создается файл дампа, или потому, что файл с таким именем уже существует в каталоге и либо недоступен для записи, либо не является обычным файлом (например, это может быть каталог или символьная ссылка).
• Обычный файл с таким именем уже существует и доступен для записи, но на него уже создано несколько (жестких) ссылок.
• Каталог, в котором планируется создание файла дампа, не существует.
• Ограничение ресурсов процесса для размера файла дампа памяти ядра установлено на 0. Это ограничение, RLIMIT_CORE, более подробно рассматривается в разделе 36.3. В вышеприведенном примере мы использовали команду ulimit (limit в оболочке С shell) для гарантии того, что для файлов core никакие ограничения не устанавливаются.
• Ограничение ресурсов процесса для размера файла, которое может быть создано процессом, установлено на 0. Это ограничение, RLIMIT_FSIZE, обсуждается более подробно в разделе 36.3.
• Бинарный исполняемый файл недоступен для чтения. Это не позволяет пользователям обратиться к дампу ядра для получения кода программы, недоступного никаким иным способом.
• Файловая система, в которой находится текущий рабочий каталог, монтирована в режиме «только для чтения», не располагает свободным местом или свободными индексными дескрипторами. Возможно, пользователь также достиг ограничения выделенной ему квоты пространства файловой системы.
• Выполняемая программа с установленным ID пользователя (или с установленным ID группы) не генерирует дамп ядра, если выполняется не владельцем файла (или из группы владельца). Это предотвращает ситуации, когда злоумышленники могут воспользоваться дампом памяти для получения и изучения конфиденциальной информации из программы, например паролей.