Кроме ссылок на подструктуры показанный на рис. элемент процесса содержит следующие категории информации.
· Идентификация процесса: PID и PID родителя.
· Состояние сигнала: ожидающие доставки сигналы, маска сигналов и сводка действий сигналов.
· Трассировка: сведения о трассировке процесса.
· Таймеры: таймер реального времени и счетчики использования процессора.
· Подструктуры процесса, показанные на рис., содержат следующие категории сведений.
· Идентификация группы процессов: группа процесса и сеанс, к которому относится процесс.
· Мандаты пользователя: действительный, эффективный и сохраненный идентификаторы пользователя и группы.
· Управление памятью: структура, описывающая выделение виртуального адресного пространства, используемого процессами; пространство виртуальной памяти (VM) и связанные с ним структуры более полно описываются в главе 5.
· Дескрипторы файлов: массив указателей на элементы файлов, индексируемые открытыми дескрипторами файлов процесса, а также флаги открытых файлов и текущий каталог.
· Вектор системных вызовов: отображение номеров системных вызовов на действия; кроме текущего и нерекомендуемого собственных форматов исполняемых файлов FreeBSD, ядро может запускать двоичные файлы, откомпилированные для нескольких других вариантов UNIX, таких, как Linux, OSF/1 и System V Release 4, предоставляя альтернативные векторы системных вызовов при необходимости такого окружения.
· Учет ресурсов: структуры rlimit, описывающие использование многих ресурсов, предоставляемых системой.
· Статистика: сведения, собранные при работе процесса, которые сообщаются при его завершении и записываются в файл учета; включает также таймеры процесса и информацию о профилировании, если она собиралась.
· Действия сигналов: действия, которые должны быть предприняты, когда процессу посылается сигнал.
· Структура потока: содержание структуры потока.
Таблица: Состояния процесса
|
Состояние |
Описание |
|
NEW |
Создание процесса |
|
NORMAL |
Потоки будут в состояниях RUNNABLE (готовые к запуску), SLEEPING (спящие) или STOPPED (остановленные) |
|
ZOMBIE |
Завершение процесса |
Элемент состояния структуры процесса содержит текущее значение состояния процесса. Возможные значения состояния показаны в табл. Когда процесс впервые создается с помощью системного вызова fork, он вначале помечается как NEW. Состояние изменяется на NORMAL, когда для процесса выделено достаточно ресурсов для начала его выполнения. С этого момента состояние процесса будет дальше колебаться в пределах NORMAL (при этом потоки будут либо RUNNABLE - т. е. готовые к выполнению или на самом деле выполняющиеся, SLEEPING - т. е. ожидающие события, или STOPPED - т. е. остановленные сигналом или родительским процессом) до завершения процесса. Завершившийся процесс помечается как ZOMBIE до тех пор, пока он не освободит ресурсы и не сообщит о своем статусе завершения своему родительскому процессу.
Система организует структуры процессов в два списка. Элементы процессов находятся в списке zombproc, если процесс находится в состоянии ZOMBIE; в противном случае они находятся в списке allproc. Эти две очереди разделяют одни и те же связующие указатели в структуре процесса, поскольку списки являются взаимоисключающими. Отделение завершившихся процессов от работающих снижает время, затрачиваемое как системным вызовом wait, который должен сканировать среди зомби потенциальных кандидатов на возвращение, так и планировщиком и другими функциями, которые должны сканировать все готовые к выполнению процессы.
Большинство потоков, за исключением текущего выполняющегося потока (или потоков, если система многопроцессорная), также находятся в одной из двух очередей: очереди запуска или очереди ожидания. Потоки, находящиеся в готовом к выполнению состоянии, помещаются в очередь запуска, тогда как потоки, заблокированные в ожидании события, размещаются в очереди ожидания. Остановленные потоки, ожидающие события,
|
Иерархия групп процессов |

Находятся в очереди ожидания или не находятся ни в одной из очередей. Очереди запуска организованы в соответствии с приоритетами планирования потоков. Очереди ожидания организованы в структуры данных, которые хешируются по идентификатору события. Такая организация оптимизирует обнаружение спящих потоков, которые необходимо пробудить при наступлении события.
Указатель p_pptr и связанные списки (р children и р sibling) используются для нахождения связанных процессов, как показано на рис.. Когда процесс запускает порожденный процесс, последний добавляется к списку pchildren своего родителя. Порожденный процесс хранит также в своем указателе p_pptr обратную ссылку на своего родителя. Если у процесса есть несколько активных в одно и то же время порожденных процессов, последние связываются посредством своих элементов списка psibling. На рис. процесс В является прямым потомком процесса А, тогда как процессы С, D и Е являются потомками процесса В и родственными по отношению друг к другу. Процессом В обычно является оболочка, запустившая конвейер, включающий процессы С, D и Е. Процесс А, возможно, мог бы быть процессом инициализации системы init.
Процессорное время выделяется потокам в соответствии с их классами планирования и приоритетами планирования. Ядро FreeBSD имеет два класса планирования ядра и три пользовательских класса планирования. Ядро всегда запускает поток, находящийся в классе с наивысшим приоритетом. Любые потоки прерывания ядра имеют преимущество при запуске по сравнению с другими, за ними следуют любые потоки верхней половины ядра. Любые готовые к выполнению потоки реального времени имеют преимущество перед потоками в классах с разделением времени и ожидающих. Приоритеты потоков в классах реального времени и ожидания устанавливаются приложениями с использованием системного вызова rtprio и никогда не регулируются ядром. Приоритеты прерываний нижней половины устанавливаются при конфигурировании устройств и никогда не изменяются. Приоритеты верхней половины устанавливаются в соответствии с предопределенными приоритетами для каждой подсистемы ядра и никогда не изменяются.
Приоритеты потоков, работающих в классе разделения времени, регулируются ядром на основе использования ресурсов и недавнего использования процессора. У потока есть два приоритета планирования: один для планирования выполнения в режиме пользователя, а другой для планирования выполнения в режиме ядра. Поле kguserjjri, связанное со структурой потока, содержит приоритет планирования режима пользователя, тогда как поле td_priority содержит текущий приоритет планирования. Текущий приоритет может отличаться от приоритета режима пользователя, когда поток выполняется в верхней половине ядра. Приоритеты меняются в диапазоне от 0 до 255, причем чем ниже значение, тем выше приоритет. Приоритеты режима пользователя колеблются от 128 до 255; приоритеты менее 128 используются лишь, когда поток спящий, т. е. ожидает события в ядре, и немедленно после него поток пробуждается. Потокам в ядре предоставляются более высокие приоритеты, поскольку они обычно удерживают при пробуждении разделяемые ресурсы ядра. После получения ими ресурса система хочет выполнить их как можно скорее, чтобы они смогли использовать ресурс и вернуть его до того, как его запросит и заблокируется в его ожидании другой поток.
Когда поток в ядре засыпает, он должен указать, нужно ли его пробудить и пометить как готовый к выполнению, если ему будет послан сигнал. В FreeBSD поток ядра будет пробужден сигналом, лишь если на время сна он установит флаг РСАТСН. Интерфейс msleep() также обрабатывает состояния сна, ограниченные максимальной продолжительностью времени и обработкой повторно запускаемых системных вызовов. Интерфейс msleep() включает ссылку на строку, описывающую пробуждающее поток событие; эту строку можно увидеть извне, например в ps. Решение о том, использовать ли прерываемый сон, зависит от того, как долго поток может быть заблокированным. Поскольку сложно быть готовым к обработке сигналов в середине выполнения какой-либо другой операции, многие состояния сна являются непрерываемыми; т. е. выполнение потока не может быть запланировано до тех пор, пока не произойдет событие, которого он ожидает. Например, поток, ожидающий завершения дискового ввода/вывода, будет спать с заблокированными сигналами.
Для быстро возникающих сигналов откладывание обработки сигнала до момента его завершения является незаметным. Однако запросы, которые могут вызвать засыпание потока на длительный период, такие, как ожидание ввода с терминала или из сети, должны быть готовы к прерыванию своего сна таким образом, чтобы отправка сигналов не задерживалась на неопределенный срок. Потоки с прерываемым сном могут снимать свои системные вызовы из-за поступления сигнала до события, которого они ожидают. Для предотвращения постоянного удержания ресурса ядра эти потоки должны проверить, почему они были пробуждены. Если они были пробуждены из-за сигнала, они должны освободить удерживаемые ресурсы. Затем они должны вернуть ошибку, переданную им msleep(), которая будет EINTR, если после сигнала системный вызов должен быть отменен, или ERESTART, если системный вызов должен быть осуществлен повторно. Иногда событие, предполагавшееся кратковременным, такое, как дисковый ввод/вывод, задерживается из-за аппаратного сбоя. Поскольку поток спит в ядре с заблокированными сигналами, он будет глух ко всем попыткам отправить сигнал, даже такой сигнал, который вызвал бы его безусловное завершение. Единственным решением этой проблемы является замена вызовов sleep() для аппаратных событий таким образом, чтобы они стали прерываемыми.
В оставшейся части данной книги мы будем всегда использовать sleep() при ссылке на процедуру, переводящей поток в состояние сна, даже когда одним из использующихся интерфейсов является msleep().
- 11/09/2010 16:42 - Добровольное переключение контекста
- 08/09/2010 09:38 - Переключение контекста на низком уровне
- 01/09/2010 07:22 - Состояние потока
- 01/09/2010 05:13 - Переключение контекста
- 28/08/2010 04:32 - Структура потока
- 17/08/2010 04:52 - Планирование
- 17/08/2010 04:44 - Многозадачное программирование
- 14/08/2010 01:10 - Введение в управление процессами
- 13/08/2010 12:27 - Учет использования ресурсов
- 10/08/2010 06:42 - Ограничения ресурсов