• TASK_ZOMBIE
— процесс завершен, однако порождающий его процесс еще не вызвал системный вызов wait4()
. Дескриптор такого процесса должен оставаться доступным на случай, если родительскому процессу потребуется доступ к этому дескриптору. Когда родительский процесс вызывает функцию wait4()
, то такой дескриптор освобождается.
• TASK_STOPPED
— выполнение процесса остановлено. Задача не выполняется и не имеет право выполняться. Такое может случиться, если задача получает какой-либо из сигналов SIGSTOP
, SIGTSTP
, SIGTTIN
или SIGTTOU
, а также если сигнал приходит в тот момент, когда процесс находится в состоянии отладки.
Манипулирование текущим состоянием процесса
Исполняемому коду ядра часто необходимо изменять состояние процесса. Наиболее предпочтительно для этого использовать функцию
set_task state(task, state);
/* установить задание 'task' в состояние 'state' */
которая устанавливает указанное состояние для указанной задачи. Если применимо, то эта функция также пытается применить барьер памяти ( memory barrier ), чтобы гарантировать доступность установленного состояния для всех процессоров (необходимо только для SMP-систем). В других случаях это эквивалентно выражению:
task->state = state;
Вызов set_current_state(state)
является синонимом к вызову set_task_state(current, state)
.
Одна из наиболее важных частей процесса— это исполняемый программный код. Этот код считывается из выполняемого файла ( executable ) и выполняется в адресном пространстве процесса. Обычно выполнение программы осуществляется в пространстве пользователя . Когда программа выполняет системный вызов (см. главу 5, "Системные вызовы") или возникает исключительная ситуация, то программа входит в пространство ядра .
С этого момента говорят, что ядро "выполняется от имени процесса" и делает это в контексте процесса . В контексте процесса макрос current
является действительным [14] Отличным от контекста процесса является контекст прерывания, описанный в главе 6, "Прерывания и обработка прерываний". В контексте прерывания система работает не от имени процесса, а выполняет обработчик прерывания. С обработчиком прерывании не связан ни один процесс, поэтому и контекст процесса отсутствует.
. При выходе из режима ядра процесс продолжает выполнение в пространстве пользователя, если в это время не появляется готовый к выполнению более приоритетный процесс. В таком случае активизируется планировщик, который выбирает для выполнения более приоритетный процесс.
Системные вызовы и обработчики исключительных ситуаций являются строго определенными интерфейсами ядра. Процесс может начать выполнение в пространстве ядра только посредством одного из этих интерфейсов — любые обращения к ядру возможны только через эти интерфейсы.
Дерево семейства процессов
В операционной системе Linux существует четкая иерархия процессов. Все процессы являются потомками процесса init
, значение идентификатора PID
для которого равно 1. Ядро запускает процесс init
на последнем шаге процедуры загрузки системы. Процесс init
, в свою очередь, читает системные файлы сценариев начальной загрузки ( initscripts ) и выполняет другие программы, что в конце концов завершает процедуру загрузки системы.
Каждый процесс в системе имеет всего один порождающий процесс. Кроме того, каждый процесс может иметь один или более порожденных процессов. Процессы, которые порождены одним и тем же родительским процессом, называются родственными ( siblings ). Информация о взаимосвязи между процессами хранится в дескрипторе процесса. Каждая структура task_struct
содержит указатель на структуру task_struct
родительского процесса, который называется parent, эта структура также имеет список порожденных процессов, который называется children
. Следовательно, если известен текущий процесс ( current
), то для него можно определить дескриптор родительского процесса с помощью выражения:
struct task_struct *task = current->parent;
Аналогично можно выполнить цикл по процессам, порожденным от текущего процесса, с помощью кода:
struct task_struct *task;
struct list_head *list;
list_for_each(list, ¤t->children) {
task = list_entry(list, struct task_struct, sibling);
/* переменная task теперь указывает на один из процессов,
Читать дальше