Книга: Разработка ядра Linux
Дерево семейства процессов
Дерево семейства процессов
В операционной системе 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 теперь указывает на один из процессов,
порожденных текущим процессом */
}
Дескриптор процесса init
— это статически выделенная структура данных с именем init_task
. Хороший пример использования связей между всеми процессами — это приведенный ниже код, который всегда выполняется успешно.
struct task_struct *task;
for (task = current; task != $init_task; task = task->parent)
;
/* переменная task теперь указывает на процесс init */
Конечно, проходя по иерархии процессов, можно перейти от одного процесса системы к другому. Иногда, однако, желательно выполнить цикл по всем процессам системы. Такая задача решается очень просто, так как список задач — это двухсвязный список. Для того чтобы получить указатель на следующее задание из этого списка, имея действительный указатель на дескриптор какого-либо процесса, можно использовать показанный ниже код:
list_entry(task->tasks.next, struct task_struct, tasks);
Получение указателя на предыдущее задание работает аналогично.
list_entry(task->tasks.prev, struct task_struct, tasks);
Дна указанных выше выражения доступны также в виде макросов next_task(task)
(получить следующую задачу), prev_task(task)
(получить предыдущую задачу). Наконец, макрос for_each_process(task)
позволяет выполнить цикл по всему списку задач. На каждом шаге цикла переменная task
указывает на следующую задачу из списка:
struct task_struct *task;
for_each_process(task) {
/* просто печатается имя команды и идентификатор PID
для каждой задачи */
printk("%s[%d]n", task->comm, task->pid);
}
Следует заметить, что организация цикла по всем задачам системы, в которой выполняется много процессов, может быть достаточно дорогостоящей операцией. Для применения такого кода должны быть веские причины (и отсутствовать другие альтернативы).
- Глава 7 Чего нужно опасаться при моделировании бизнес-процессов. Проектные риски моделирования бизнеспроцессов
- Эффективное взаимодействие процессов архитектуры Classic Server
- Семерка - первый шаг нового семейства
- 1.2. Понятие информации. Общая характеристика процессов сбора, передачи, обработки и накопления информации
- Дерево покупательских решений
- 3.4.2. Остановка процессов
- 3.4.3. Просмотр процессов
- Лекция 16. Взаимодействие процессов
- 1.1.3. Уязвимости процессов накопления знаний (самообучения)
- 3.2. Создание процессов
- 3.3.2. Оценка информационной безопасности на основе модели зрелости процессов
- ГЛАВА 1 Обзор средств взаимодействия процессов Unix