Вы здесь

Процессы

Процессы – действующее начало. В общем случае с процессом связаны код и данные в виртуальной оперативной памяти, отображение виртуальной памяти на физическую, состояние процессора (регистры, текущая исполняемая инструкция и т.п.). Кроме того в Unix с процессом связана информация о приоритете (в том числе понижающий коэффициент nice), информация об открытых файлах и обработчиках сигналов. Программа, выполняемая внутри процесса, может меняться в течение его существования.

Создание процессов fork()

Новые процессы создаются вызовом int pid=fork(), который создаёт точную копию вызвавшего его процесса. Пара процессов называются "родительский" и "дочерний" и отличаются друг от друга тремя значениями:

  • уникальный идентификатор процесса PID
  • идентификатор родительского процесса PPID
  • значение, возвращаемое вызовом fork(). В родительском это PID дочернего процесса или ошибка (-1), в дочернем fork() всегда возвращает 0.

После создания, дочерний процесс может загрузить в свою память новую программу (код и данные) из исполняемого файла вызовом execve(const char *filename, char *const argv [], char *const envp[]);

Дочерний процесс связан с родительским значением PPID. В случае завершения родительского процесса PPID меняется на особое значение 1 - PID процесса init.

Процесс init

В момент загрузки ядра создаётся особый процесс с PID=1, который должен существовать до перезагрузки ОС. Все остальные процессы в системе являются его дочерними процессами (или дочерними от дочерних и т.д.). Обычно, в первом процессе исполняется программа init поэтому в дальнейшем я буду называть его "процесс init".

В Linux процесс init защищен от вмешательства других процессов. К нему нельзя подключиться отладчиком, к его памяти нельзя получить доступ через интерфейс procfs, ему не доставляются сигналы, приводящие к завершению процесса. kill -KILL 1 - не сработает. Если же процесс init всё таки завершится, то ядро также завершает работу с соответствующим сообщением.

В современных дистрибутивах классическая программа init заменена на systemd, но сущности процесса с PID=1 это не меняет.

При загрузке Linux ядро сначала монтирует корневую файловую систему на образ диска в оперативной памяти - initrd, затем создаётся процесс с PID=1 и загружает в него программу из файла /init. В initrd из дистрибутива CentOS начальный /init - это скрипт для /bin/bash. Скрипт загружает необходимые драйверы, после чего делает две вещи, необходимые для полноценного запуска Linux:

  1. Перемонтирует корневую файловую систему на основной носитель
  2. Загружает командой exec в свою память основную программу init

Для того, чтобы выполнить эти два пункта через загрузчик в начального init два параметра:

  • основной носитель корневой ФС. Например: root=/dev/sda1
  • имя файла с программой init. Например: init=/bin/bash

Если второй параметр опущен то ищется имя зашитое в начальный init по умолчанию.

Если вы загрузите вместо init /bin/bash, как в моём примере, то сможете завершить первый и единственный процесс командой exit и пронаблюдать сообщение:

Kernel panic - not syncing: Attempted to kill init!

Этот пример так же показывает, как получить права администратора при физическом доступе к компьютеру.

PID

Каждый процесс имеет уникальный на данный момент времени идентификатор PID. Поменять PID процесса невозможно.

Значения PID 0 и 1 зарезервированы. Процесс с PID==0 не используется, PID==1 - принадлежит программе init.

Максимальное значение PID в Linux равняется PID_MAX-1. Текущее значение PID_MAX можно посмотреть командой:

cat /proc/sys/kernel/pid_max

По умолчанию это 2^16 (32768) однако в 64-разрядных Linux его можно увеличить до 2^22 (4194304):

echo 4194303 > /proc/sys/kernel/pid_max

*PID* назначаются последовательно. При создании нового процесса вызовом fork ищется *PID*, больший по значению, чем тот, который был возвращён предыдущим вызовом fork. Если при поиске достигнуто значение pid_max, то поиск продолжается с PID=2. Такое поведение выбрано потому, что некоторые программы могут проверять завершение процесса по существованию его PID. В этой ситуации желательно, чтобы PID не использовался некоторое время после завершения процесса.

UID и GID

С процессом связано понятие "владельца" и "группы", определяющие права доступа процесса к другим процессам и файлам в файловой системе. "Владелец" и "группа", это числовые идентификатор UID и GID, являющийся атрибутами процесса. В отличие от файла, процесс может принадлежать нескольким группам одновременно. Пользователь в диалоговом сеансе имеет право на доступ к своим файлам поскольку диалоговая программа (shell), которую он использует, выполняется в процессе с тем же UIDом, что и UID, указанный в атрибутах файлов.

Процесс может поменять своего владельца и группу в двух случаях:

  1. текущий UID равен 0 (соответствует пользователю root) и процесс обратился к системному вызову setuid(newuid). В этом случае процесс полностью меняет владельца.
  2. процесс обратился к вызову exec(file) загрузив в свою память программу из файла в атрибутах которого выставлен флаг suid или sgid. В этом случае владелец процесса сохраняется, но права доступа будут вычисляться на основе UID и GID файла.
Прикрепленный файлРазмер
Иконка изображения fork-exex-wait.png25.8 КБ
Яндекс.Метрика