itmo_conspects

Лекция 5. Процессы, часть II

Сигнал

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

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

Согласно стандарту POSIX, сигналы делятся на стандартные и сигналы реального времени

В Linux всего 31 стандартный сигнал. Рассмотрим самые распространенные из них:

Имя Код Назначение Действие по умолчанию
SIGHUP (от hang up) 1 Процесс завершается, а дочерние процессы получает этот сигнал, чтобы тоже завершиться. Ранее использовался для обозначения прерывания телефонной связи между терминалом и пользователем (дословно “положить трубку”) 🛑
SIGINT (от interrupt) 2 Прерывание выполнения команд от клавиатуры (в терминале вызывается по комбинации Ctrl+C) 🛑
SIGQUIT 3 Прерывание с дампом ядра (обычно Ctrl+\), посылается всем процессам группы 🛑📦
SIGILL (от illegal) 4 Сигнал, посланный ядром, который означает, что выполнявшаяся инструкция является неправильной с точки зрения архитектуры процессора 🛑📦
SIGFPE (от floating point exception) 8 Ошибочная арифметическая операция 🛑📦
SIGKILL 9 Немедленное принудительное завершение процесса 🛑
SIGUSR1 и SIGUSR2 10 и 12 Сигналы, определенные пользователем 🛑
SIGSEGV (от segmentation fault) 11 Нарушение доступа к памяти, например, доступ к еще невыделенной странице 🛑📦
SIGPIPE 13 Процесс написал в именованный канал, но нет процесса, который мог бы прочитать это 🛑
SIGTERM (от terminate) 15 Сигнал завершения 🛑
SIGCHLD, также SIGCLD (от child) 17 Дочерний процесс завершился, был остановлен или продолжил исполнение 🙈
SIGCONT (от continue) 18 Процесс продолжает исполнение ▶️
SIGSTOP 19 Перевод процесса в состояние “Остановлен” ⏸️
SIGTSTR 20 Сигнал остановки с терминала по комбинации Ctrl+Z ⏸️

По умолчанию каждый процесс имеет таблицу обработчиков сигналов, наследованную от первого процесса (init или systemd). Такие обработчики обычно могут совершать такие действия:

Здесь код сигнала указан для архитектур x86 и ARM. В других архитектурах (например, MIPS или SPARC) код сигнала может отличаться

Среди этих все, кроме SIGKILL и SIGSTOP, можно перехватить и переопределить обработчики, например, назначить на SIGINT правильной завершение процесса. На сигналы SIGKILL и SIGSTOP операционная система принудительно убивает или переводит процесс в состояние “Остановлен” соответственно

Сигналы реального времени используются для обычных программ. Они не имеют определенного значения, и всего их может быть до 33 – они определены интервалом от SIGRTMIN (чаще всего 34 или 35) и SIGRTMAX (64). Так как разные имплементации потоков библиотеки glibc используют первые 1 или 2 сигнала для своих задач, рекомендуется использовать SIGRTMIN + 3 вместо 37 или 38

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

Источник: https://www.man7.org/linux/man-pages/man7/signal.7.html

Планирование процессов

Подробнее про планирование процессов описано в курсе “Операционные системы”

За время развития операционной системы Linux существовало множество планировщиков:

В Linux можно выделить 2 типа процессов:

Рассмотрим, как работает Completely Fair Scheduler

Ключевая идея планировщика - каждый процесс должен получать долю процессорного времени, пропорциональную её весу (то есть приоритету). Вместо фиксированных очередей планировщик CFS использует виртуальное время vruntime для каждой задачи

Сами процессы с vruntime должны где-то храниться, причем операции добавления удаления должны быть быстрыми. По этой причине выбрали красно-черное дерево - процессы отсортированы по величине vruntime, а само дерево является самобалансирующимся, то есть в любой момент времени его высота примерно равна log N, а все операции имеют сложность O(log N)

Красно-черное дерево в CFS

Подробнее про CFS: https://www.kernel.org/doc/html/latest/scheduler/sched-design-CFS.html, https://developer.ibm.com/tutorials/l-completely-fair-scheduler/
Исходный код CFS: https://github.com/torvalds/linux/blob/v6.5/kernel/sched/fair.c


Completely Fair Scheduler полагался на множество эвристик и параметров, чтобы корректно работать с интерактивными и фоновыми задачами

Новый алгоритм Earliest eligible virtual deadline first вместо этого имеет математический подход. В нем есть три понятия:

На каждом шаге EEVDF:

Однако процессы могут кратковременно засыпать, чтобы повышать свой лаг, что делает планировщик несправедливым. Чтобы бороться с этим, планировщик не убирает такие задачи из очереди “Готовность”, а также меньше уменьшает их лаг

Статья про EEVDF: https://citeseerx.ist.psu.edu/document?doi=805acf7726282721504c8f00575d91ebfd750564&repid=rep1&type=pdf
Документация про EEVDF: https://docs.kernel.org/scheduler/sched-eevdf.html

Псевдофайловая система /proc/

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

Директория /proc/ содержит множество поддиректорий вида /proc/<PID> с числовыми названиями. Это число представляет из себя идентификатор процесса, а поддиректория хранит информацию о процессе, а именно:


Помимо информации для каждого процесса /proc/ хранит общую информацию об операционной системе