Linux. Processes

Материал из Wiki
Перейти к навигации Перейти к поиску

Типы процессов

В системе Linux существуют разные типы процессов:

  • Пользовательские Linux процессы — работают от имени обычной учетной записи пользователя и выполняются в пространстве пользователя. Если процесс не запущен таким образом, который дает процессу дополнительные разрешения, то пользовательский процесс не имеет доступа к файлам в системе, к которым не имеет доступа сам пользователь запустивший процесс.
  • Процессы-демоны — предназначенные для работы приложения в фоновом режиме. Такие процессы обычно управляются какими-нибудь службами (сервисами SystemD). Процесс-демон может прослушивать входящие запросы к службе. Например apache2 является процессом-демоном и прослушивает запросы на просмотр веб-страниц. Такие процессы могут работать от имени root, или от имени специальных системных пользователей. Например, apache2 работает от имени пользователя www-data.
  • Процессы ядра — выполняются только в пространстве ядра. Они похожи на процессы-демоны. Основное отличие состоит в том, что процессы ядра имеют полный доступ к структурам ядра. Процессы ядра не так гибки, как процессы-демоны. Вы можете изменить поведение процесса-демона, изменив конфигурационные файлы и перезагрузив службу, но для изменения процессов ядра может потребоваться перекомпиляция ядра.

Атрибуты процессов

Каждый процесс имеет набор атрибутов, например:

Это не весь список атрибутов, на самом деле их больше.

  • pid — идентификатор процесса;
  • ppid — идентификатор родительского процесса;
  • tty — управляющий терминал, с которого поступает ввод и на который поступает вывод. То есть stdin, stderr, stdout;
  • sid — идентификатор сеанса;
  • ruid — идентификатор пользователя запустившего исполняемый файл;
  • rgid — идентификатор группы пользователя запустившего исполняемый файл;
  • euid — идентификатор фактического пользователя от имени которого работает процесс;
  • egid — идентификатор фактической группы от имени которой работает процесс;
  • pgid — идентификатор группы процессов;
  • tpgid — идентификатор терминальной группы процессов (forefraund group);
  • pri — приоритет работы процесса, чем выше значение, тем выше приоритет. Пользователь, даже root не может менять это значение;
  • ni — любезность процесса, от него зависит pri. Чем выше ni, тем ниже pri. Только root может менять это значение;
  • s — состояние в котором находится процесс.

Состояния в которых могут находится процессы Linux

Процесс либо обрабатывается процессором, либо не обрабатывается. Только один процесс может обрабатываться на одном ядре процессора. Все остальные процессы должны ждать или находиться в каком-то другом состоянии. Вот список состояний в которых может находится процесс:

R (running — запущенный). Процесс находится на обработке у процессора.

R (runnable — готов к работе). Процесс готов к обработке и находится в очереди к процессору. Running и runnable обозначаются одинаковой буквой R.

D (uninterruptible sleep — в беспробудном сне). Когда процесс обращается к устройству, например к диску или сетевой карте, он переходит в это состояние. А возвращается из него только после получения запрошенной информации. Обычно в таком состоянии процесс находится не долго. В таком состоянии процесс перестает обрабатывать любые сигналы и, если что-то пойдет не так, то завершить такой зависший процесс, не перезагружая сервер, не получится.

I (Idle — бездействующий поток ядра). Состояние похоже на D, но такие процессы не нагружают процессор и исключены из расчета средней нагрузки системы (load average).

S (sleeping — спит). Процесс ожидает какие-то ресурсы, которые в данный момент недоступны. При переходе в это состояние, процесс немедленно отказывается от доступа к процессору. Когда ресурс, который ожидает процесс, становится доступным, процесс может снова перейти в состояние R (runnable). В спящем состоянии процесс продолжает обрабатывать сигналы.

T (stopped by job control signal — остановленный специальным сигналом). Про сигналы поговорим позже, тут главное понять, что процессы могут обрабатывать сигналы и один из них может остановить процесс. Это состояние похоже на паузу, то есть из этого состояния процесс может выйти и продолжить свою работу в состоянии R или S.

t (stopped by debugger during trace — остановлен отладчиком во время трассировки). Состояние подобное T, но в этом случае остановка процесса произошла не по сигналу а во время отладки.

Z (zombie — зомби). Когда процесс завершает свою работу, он освобождает свои ресурсы, но не освобождает свой PID в таблице процессов. Вместо этого он отправляет сигнал родителю, сообщая что он завершается. Родительский процесс должен освободить PID дочернего процесса. Отрезок времени между завершением процесса и когда родитель освободит PID завершенного дочернего процесса называется состоянием зомби. Процесс может остаться в состоянии Zombie, если родительский процесс умрет до того, как освободит PID дочернего процесса.

+ is in the foreground process group

Пример:

ps ax | grep zfs

    ...
        7  -  DL      113:34.22 [zfskern]
    2441  -  Is        0:00.07 /usr/sbin/mountd -r -S /etc/exports /etc/zfs/exports
    97898  -  IWs       0:00.00 /bin/bash -c /mnt/raid1/data/scripts/zfs_replication_mail01-mail.sh >> /mnt/raid1/data/log/zfs_replication_mail01-mail.log 2>&1
    97899  -  IW        0:00.00 /bin/bash /mnt/raid1/data/scripts/zfs_replication_mail01-mail.sh
    97919  -  D         5:23.64 zfs send -Pev -R raid1/mail01-mail@auto-20230620-214500
    97920  -  S         4:30.38 zfs recv -F raid3/volumes/mail01-mail_replica
    1946  0  S+        0:00.00 grep zfs
    ...

FreeBSD

   For BSD formats and when the stat keyword is used, additional

   characters may be displayed:

   <    high-priority (not nice to other users)

   N    low-priority (nice to other users)

   L    has pages locked into memory (for real-time and custom IO)

   s    is a session leader

   l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

   +    is in the foreground process group

PS legend

ps aux

...
USER       PID  %CPU %MEM  VSZ RSS     TTY   STAT START   TIME COMMAND
timothy  29217  0.0  0.0 11916 4560 pts/21   S+   08:15   0:00 pine
root     29505  0.0  0.0 38196 2728 ?        Ss   Mar07   0:00 sshd: can [priv]
can      29529  0.0  0.0 38332 1904 ?        S    Mar07   0:00 sshd: can@notty
...

   USER = user owning the process

   PID = process ID of the process

   %CPU = It is the CPU time used divided by the time the process has been running.

   %MEM = ratio of the process’s resident set size to the physical memory on the machine

   VSZ = virtual memory usage of entire process (in KiB)

   RSS = resident set size, the non-swapped physical memory that a task has used (in KiB)

   TTY = controlling tty (terminal)

   STAT = multi-character process state

   START = starting time or date of the process

   TIME = cumulative CPU time

   COMMAND = command with all its arguments

STATS:

D Uninterruptible sleep (usually IO)

R Running or runnable (on run queue)

S Interruptible sleep (waiting for an event to complete)

T Stopped, either by a job control signal or because it is being traced.

W paging (not valid since the 2.6.xx kernel)

X dead (should never be seen)

Z Defunct ("zombie") process, terminated but not reaped by its parent.

and the additional characters are:

< high-priority (not nice to other users)

N low-priority (nice to other users)

L has pages locked into memory (for real-time and custom IO)

s is a session leader

l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

+ is in the foreground process group (ПРОЦЕСС НА ПЕРЕДНЕМ ПЛАНЕ, ЕСЛИ "+" НЕТ, ТО ПРОЦЕСС В ФОНЕ)

Процесс-сирота

Процесс-сирота (англ. orphan process) — в семействе операционных систем UNIX вспомогательный процесс, чей основной процесс (или связь с ним) был завершен нештатно (не подав сигнала на завершение работы).

Обычно, «сиротой» остается дочерний процесс после неожиданного завершения родительского, но возможно возникновение сервера-сироты (локального или сетевого) при неожиданном прерывании связи или завершении клиентского процесса.

Процессы-сироты расходуют системные ресурсы сервера и могут быть источником проблем. Существует несколько их решений:

  • Уничтожение (англ. extermination) заключается в завершении процесса (например, посылкой сигнала SIGTERM или SIGKILL), используется наиболее часто (особенно оператором, обслуживающим систему).
  • Перевоплощение (англ. reincarnation) — система пытается «воскресить» родителей в состоянии на момент перед их удалением или найти других (например, более старших) родителей.
  • Выдача лимита времени (англ. expiration) — процессу выдаётся временная квота для завершения до момента, когда он будет «убит» принудительно. Отметим, что процессу оставлена возможность запросить дополнительное время для завершения.

В Unix-подобных системах все процессы-сироты немедленно усыновляются специальным системным процессом «init». Эта операция ещё называется переподчинением (англ. reparenting) и происходит автоматически. Хотя технически процесс «init» признаётся родителем этого процесса, его всё равно считают «осиротевшим», поскольку первоначально создавший его процесс более не существует.

Процесс зомби

Происходит от слова «зомби», означающего «живой мертвец» (оксюморон, англ. undead). Термин является яркой метафорой о том, что процесс «умер», но не «погребён».

Возникновение зомби

Процесс при завершении (как нормальном, так и в результате не обрабатываемого сигнала) освобождает все свои ресурсы и становится «зомби» — пустой записью в таблице процессов, хранящей статус завершения, предназначенный для чтения родительским процессом.

Зомби-процесс существует до тех пор, пока родительский процесс не прочитает его статус с помощью системного вызова wait(), в результате чего запись в таблице процессов будет освобождена.

При завершении процесса система уведомляет родительский процесс о завершении дочернего с помощью сигнала SIGCHLD, таким образом может быть удобно (но не обязательно) осуществлять вызов wait() в обработчике данного сигнала.

Проблемы зомби

Зомби не занимают памяти (как процессы-сироты), но блокируют записи в таблице процессов, размер которой ограничен для каждого пользователя и системы в целом (В Linux максимальный возможный идентификатор процесса по умолчанию ограничен 32 тысячами, но может быть перенастроен на величину до 4 миллионов. При этом максимальный идентификатор потока в ОС ограничен 500 млн.).

При достижении лимита записей все процессы пользователя, от имени которого выполняется создающий зомби родительский процесс, не будут способны создавать новые дочерние процессы. Кроме этого, пользователь, от имени которого выполняется родительский процесс, не сможет зайти на консоль (локальную или удалённую) или выполнить какие-либо команды на уже открытой консоли (потому что для этого командный интерпретатор sh должен создать новый процесс), и для восстановления работоспособности (завершения виновной программы) будет необходимо вмешательство системного администратора.

Иногда, если родительский процесс выполняется от имени суперпользователя, для освобождения записей (перезапуска процесса) может потребоваться перезагрузка (причём зачастую — только аппаратным рестартом). Некоторые операционные системы (например, Sun Solaris) при возникновении такой ситуации аварийно завершают часть выполняющихся процессов, восстанавливая работоспособность системы.

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

Игнорирование обработки завершения дочерних процессов не является правильным, но обычно не приводит к проблемам для короткоживущих программ, так как при завершении процесса все его потомки становятся потомками процесса init, который постоянно считывает статус своих потомков-зомби, очищая таблицу процессов. Именно для задействования этого механизма выполняется стандартная техника запуска демонов "double fork()": промежуточный родитель завершается, делая родителем своего потомка процесс init .

Для долгоживущих и часто создающих дочерние процессы программ, необходима корректная обработка контроля завершения дочерних программ, потому что накапливание необрабатываемых зомби приводит к «утечке ресурсов» в виде накопления записей в таблице процессов.

В linux, начиная с версии kernel 3.4, процесс имеет возможность объявить себя усыновителем сирот ("subreaper") вместо процесса init командой prctl(PR_SET_CHILD_SUBREAPER).