Как узнать список процессов linux с помощью командной строки

Содержание:

Завершение процесса

Завершение процесса может быть вызвано несколькими событиями, от нормального завершения до завершения по сигналу или по вызову функции . Однако независимо от события, послужившего причиной завершения процесса, эта работа выполняется вызовом функции ядра (объявленной в ./linux/kernel/exit.c). Связь этой функции с различными вариантами завершения процесса показана на диаграмме, приведенной на рисунке 2.

Рисунок 2. Иерархия вызовов при завершении процесса

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

Обратите внимание на то, что если требуется отправка сигнала родительскому процессу (или процесс находится в режиме трассировки), задача не исчезнет из системы. Если отправка сигнала не требуется, вызов функции освободит память, используемую процессом

Представление процессов

Читайте другие статьи Тима Джонса на сайте developerWorks
  • Статьи Тима из серии Анатомия…
  • Все статьи Тима на сайте developerWorks

В ядре Linux процесс представлен довольно большой структурой (дескриптором процесса). Помимо самой необходимой для описания процесса информации эта структура содержит массу других данных, используемых для учета и связи с другими процессами (родительскими и порожденными). Полное описание структуры выходит за рамки статьи, однако, ее фрагмент, содержащий упомянутые в статье элементы, приведен в листинге 1. Стоит заметить, что структура объявлена в файле ./linux/include/linux/sched.h.

Листинг 1. Небольшой фрагмент структуры task_struct
struct task_struct {

	volatile long state; 
	void *stack; 
	unsigned int flags;

	int prio, static_prio;

	struct list_head tasks;

	struct mm_struct *mm, *active_mm;

	pid_t pid; pid_t tgid;

	struct task_struct *real_parent;

	char comm;

	struct thread_struct thread;

	struct files_struct *files;

	...

};

В листинге 1 можно вполне ожидаемо увидеть такие данные, как состояние выполнения, стек, набор флагов, указатель на дескриптор родительского процесса, поток выполнения (их может быть несколько) и дескрипторы открытых процессом файлов. Некоторые поля мы рассмотрим подробно сейчас, к остальным же вернемся позже. Переменная состоит из битовых флагов, отражающих состояние процесса. Большую часть времени процесс выполняется или ожидает выполнения в очереди (), находится в состоянии приостановки (), в состоянии непрерываемой приостановки (), в состоянии останова () и нескольких других. Полный список флагов состояний можно найти в файле ./linux/include/linux/sched.h.

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

Хотя каждому процессу назначается приоритет (его значение хранится в поле ), фактический приоритет процесса определяется динамически исходя из загрузки и других факторов. Чем ниже значение приоритета, тем выше его фактический приоритет.

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

Адресное пространство процесса представлено полями и . Поле содержит указатель на структуру, описывающую адресное пространство процесса, а поле указывает на такую же структуру, но относящуюся к предыдущему процессу (это сделано для ускорения переключения контекстов).

Последнее из рассматриваемых полей, , содержит сохраненное состояние процесса. Конкретная реализация этой структуры зависит от архитектуры оборудования, на котором выполняется Linux. Ее пример можно найти в файле ./linux/include/asm-i386/processor.h.
Эта структура служит для сохранения процесса при переключении контекста (сохраняется состояние аппаратных регистров, счетчика команд и т. п.).

Смерть родителя или потомка

В какой-то момент процессы должны завершаться. Вопрос только в том, какой завершится первым: родитель или потомок.

Родительский процесс завершается раньше потомка

Если родительский процесс умирает раньше своих потомков, осиротевшие потомки должны знать, кто их родитель. Вспомните о том, что у каждого процесса есть родитель, и вы можете полностью отследить дерево процессов, начиная с PID 1, имеющего также название
. Когда родитель умирает,

усыновляет всех его потомков, как показано в
.

Листинг 6. Родительский процесс умирает раньше потомка
#include <unistd.h>
#include <stdio.h>

int main(void) {

        int i;
        if (fork()) {
                /* Родитель */
                sleep(2);
                _exit(0);
        }
        for (i=0; i < 5; i++) {
                printf("My parent is   %d\n",  getppid());
                sleep(1);
        }
}
sunbox$ gcc die1.c -o die1
sunbox$ ./die1
My parent is   2920
My parent is   2920
sunbox$ My parent is 1
My parent is  1
My parent is  1

В этом примере родительский процесс вызывает , ждет две секунды и завершается. Порожденный процесс продолжается, распечатывая PID своего родителя в течение пяти секунд. Вы можете видеть, что когда родитель умирает, PPID изменяется на 1. Также интересно возвращение управления командному процессору. Поскольку порожденный процесс выполняется в фоне, как только родитель умирает, управление возвращается к командному процессору.

Потомок умирает раньше родителя

описывает процесс противоположный : смерть потомка раньше родителя. Для того чтобы лучше показать, что происходит, непосредственно из процесса ничего не распечатывается. Вместо этого, интересная информация находится в списке процессов.

Листинг 7. Порожденный процесс умирает раньше родительского
  sunbox$ cat die2.c
#include <unistd.h>
#include <stdio.h>

int main(void) {

        int i;
        if (!fork()) {
                /* Потомок немедленно завершается*/
                _exit(0);
        }
	/* Родитель ждет около минуты*/
        sleep(60);
}

sunbox$ gcc die2.c -o die2
sunbox$ ./die2 &
 2934
sunbox$ ps -ef | grep 2934
    sean  2934  2885   0 21:43:05 pts/1       0:00 ./die2
    sean  2935  2934   0        - ?           0:00 <defunct>
sunbox$ ps -ef | grep 2934
+  Exit 199                ./die2

выполняется в фоновом режиме, используя оператор
, после этого на экран выводится список процессов, отображая только выполняемый процесс и его потомков. PID 2934 – родительский процесс, PID 2935 – процесс, который
создается и немедленно завершается. Несмотря на преждевременный выход, порожденный процесс все еще находится в таблице процессов, уже как
умерший
процесс, который еще называется
зомби. Когда через 60 секунд родитель умирает, оба процесса завершаются.

Когда порожденный процесс умирает, его родитель информируется при помощи сигнала, который называется
. Точный механизм всего этого сейчас не имеет значения

Что действительно важно, так это то, что родитель должен как-то узнать о смерти потомка. С момента смерти потомка и до того момента как родитель получает сигнал, потомок находится в состоянии зомби

Зомби не выполняется и не потребляет ресурсов CPU; он только занимает пространство в таблице процессов. Когда родитель умирает, ядро наконец-то может убрать потомков вместе с родителем. Значит, единственный способ избавиться от зомби — это убить родителя. Лучший способ справиться с зомби – гарантировать, что они не окажутся на первом месте. Код в

описывает обработчик сигналов, для работы с входящим сигналом
.

Листинг 8. Обработчик сигналов в действии
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>

void sighandler(int sig) {
        printf("In signal handler for signal  %d\n",  sig);
        /* wait() это основное для подтверждения SIGCHLD */
        wait(0);
}

int main(void) {

        int i;
        /* Установить обработчик сигнала к SIGCHLD  */
        sigset(SIGCHLD,  &sighandler);
        if (!fork()) {
                /* Потомок */
                _exit(0);
        }
        sleep(60);
}
sunbox$ gcc die3.c -o die3
sunbox$ ./die3 &
 3116
sunbox$ In signal handler for signal  18 
ps -ef | grep 3116
    sean  3116  2885   0 22:37:26 pts/1       0:00 ./die3

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

для того, чтобы подождать завершения порожденного процесса. Поскольку процесс уже завершен, это необходимо для того, чтобы ядро получило подтверждение о смерти потомков. На самом деле, родителю следовало бы сделать больше, чем просто подтвердить сигнал. Ему следовало бы также очистить данные потомка.

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

Ядро

Если известно название ядра, которое вы хотите загрузить, то просто
введите символ прямого слэша (/) и затем нажмите клавишу Tab. После
этого GRUB отобразит список ядер и образов .

После того как образ ядра оказывается в памяти и ему передается управление
от загрузчика 2-й ступени, наступает стадия ядра. Однако образ ядра не
является исполняемым, это сжатый образ ядра. Обычно это zImage (сжатый
образ размером менее 512KB) или bzImage (большой сжатый образ, размером
более 512KB), который был сжат при помощи zlib. В начале такого образа
ядра располагается программа, которая выполняет минимальную настройку
аппаратного обеспечения и затем распаковывает ядро, хранящееся внутри
образа ядра, и помещает его в верхнюю область памяти. Если имеется образ
начального RAM-диска, то программа также перемещает его в память и
помечает для дальнейшего использования, а затем вызывает само ядро, после
чего начинается загрузка ядра.

При вызове bzImage (образ для i386) выполнение начинается
вс ассемблерной
функции (основные этапы показаны на рисунке 3). Эта
программа выполняет основную настройку аппаратного обеспечения и вызывает
процедуру, располагающуюся в
. Процедура настраивает
базовую среду (стек и т.п.) и очищает Block Started by Symbol (BSS). Затем
выполняется декомпрессия ядра при помощи вызова
C-функции(которая хранится в
). После декомпрессии ядра
в память происходит его вызов. Это еще одна функция
, но она располагается в файле

В новой функции (которая называется swapper или
process 0) инициализируются таблицы страниц (page tables) и обеспечивается
подключение функции memory paging (отображение страниц). Также
определяется тип центрального процессора и сопроцессора для вычислений с
плавающей точкой (FPU), если он имеется, и данная информация сохраняется
для последующего использования. Далее вызывается
функцияиз(), которая
осуществляет переход в ту часть ядра Linux, которая не зависит от
особенностей конкретной аппаратной платформы. Можно сказать, что это
функция для ядра Linux.

Рисунок 3. Выполнение основных функций
при загрузке ядра Linux для i386

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

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

Вывод функции decompress_kernel

Функция отвечает за те обычные сообщения
о разархивировании, которые появляются на экране:

Функция позволяет создать компактное ядро Linux, где
драйверы скомпилированы как загружаемые модули. Эти загружаемые модули
обеспечивают доступ ядра к дискам и файловым системам, которые имеются на
этих дисках. Также имеются драйверы для других аппаратных устройств. Так
как корневая файловая система представляет собой файловую систему
на диске, то функция обеспечивает для загрузчика
возможность обратиться к диску и смонтировать действительную корневую
файловую систему. Во встраиваемой системе без жесткого диска
может представлять собой окончательную файловую
систему, или же окончательная файловая система может монтироваться при
помощи сетевой файловой системы (Network File System, NFS).

grub> kernel /bzImage-2.6.14.2
   

grub> initrd /initrd-2.6.14.2.img
   

grub> boot

Uncompressing Linux... Ok, booting the kernel.

Init

После загрузки и инициализации ядра запускается первое приложение в
пространстве пользователя. Это первая из вызываемых программ, которые
скомпилированы со стандартной библиотекой C. До этого момента процесса
стандартные C-приложения еще не выполнялись.

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

Загрузчик 1-й ступени

Первичный начальный загрузчик, хранящийся в MBR, представляет собой образ
размером 512 байт, который содержит как программный код, так и небольшую
таблицу разделов (см. рисунок 2). Первые 446 байт представляют собой
собственно первичный загрузчик, который содержит как программный код, так
и текст сообщений об ошибках. Следующие 64 байта представляют собой
таблицу разделов, которая содержит запись для каждого из четырех разделов
диска (по 16 байт каждая). В конце MBR располагаются два байта, которые
носят название «магического числа» (0xAA55). Это магическое число служит
для целей проверки MBR.

Рисунок 2. Строение MBR

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

Как использовать ps для получения списка процессов

Команды top и htop предоставляют удобный интерфейс для просмотра запущенных процессов, аналогичный графическому диспетчеру задач.

Тем не менее, данные инструменты не всегда достаточно гибки, чтобы адекватно охватить все сценарии.

При вызове без аргументов результаты могут быть немного неполными:

ps

Эти данные отображают все процессы, связанные с текущим пользователем и терминальной сессией. Это имеет смысл, так как в данный момент с терминала запущены только команды bash and ps.

Чтобы получить более полную картину процессов данной системы, можно запустить следующее:

ps aux

Эти параметры приказывают ps показать процессы, принадлежащие всем пользователям (вне зависимости от их терминала) в удобном формате.

Чтобы увидеть дерево, отображающее иерархические отношения, можно запустить команду с данными параметрами:

ps axjf

Как можно видеть, процесс kthreadd отображен как порождающий относительно процесса ksoftirqd/0 и других.

Примечание об идентификаторах процессов (PID)

В Linux и Unix-подобных системах каждому процессу присвоен идентификатор (PID). Таким образом операционная система идентифицирует и отслеживает процессы.

Быстрый способ узнать PID процесса – использовать команду pgrep:

pgrep bash
1017

Это запросит идентификатор процесса и вернет его.

Первый порожденный при запуске процесс под названием init получает PID «1».

pgrep init
1

Данный процесс отвечает за порождение всех остальных процессов системы. Чем позже порожден процесс, тем больше будет присвоенный ему PID.

Родительский процесс – это процесс, ответственный за порождение другого процесса. Если порождающий процесс был прекращен, то дочерние процессы также прервутся. PID родительского процесса называется PPID.

PID и PPID можно увидеть в заголовках столбцов во многих приложениях управления процессами, включая top, htop и ps.

Любое общение между пользователем и операционной системой, связанное с процессами, предполагает перевод имен процессов в их идентификаторы и наоборот. Вот зачем утилиты сообщают PID.

Использование семейства системных вызовов exec

Задачей

является замена текущего процесса на новый процесс. Отметьте использование слова
заменить. Как только вы вызываете
, текущий процесс завершается и начинается новый. Если вы хотите создать отдельный процесс, сначала вы должны вызвать , затем вызвать для новой программы в дочернем процессе.
В
показан этот сценарий.

Листинг 4. Запуск разных программ посредством соединения
с
sunbox$ cat exec1.c
#include <unistd.h>
#include <stdio.h>

int main (void) {

        /* Определить массив с завершающим нулем команды для запуска
		 следующим за любым параметром,  в этом случае никаким */
        char *arg[] = { "/usr/bin/ls",  0 };

        /* fork и exec в порожденном процессе */
        if (fork() == 0) {
                printf("In child process:\n");
                execv(arg,  arg);
                printf("I will never be called\n");
        }
        printf("Execution continues in parent process\n");
}
sunbox$ gcc exec1.c -o exec1
sunbox$ ./exec1
В порожденном процессе:
fork1.c      exec1        fork2       exec1.c      fork1
fork2.c      
Выполнение продолжается в родительском процессе

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

При вызове
в первую очередь получает указатель на строку с именем программы для запуска, а затем указатель на массив параметров, который вы задали ранее. Первый элемент массива фактически является именем программы, следовательно, параметры начинают перечисляться со второго элемента. Запомните, что порожденный процесс никогда не возвращается после вызова . Это означает, что выполняемый процесс заменяется на новый.

Есть и другие системные вызовы . Они отличаются способом приема параметров и вопросом относительно необходимости передачи переменных окружения.
— это один из самых простых способов замены текущего образа процесса, поскольку он использует массив с завершающим null-символом и не требует информации об окружении. Другие варианты:
, который принимает параметры в отдельные аргументы или
, который также принимает массив переменных окружения с завершающим null-символом. Причем, не каждая операционная система поддерживает все варианты. Выбор зависит от платформы, способа программирования и от того, нужно ли вам определять какие-либо переменные окружения.

Obsolete Sort Keys

These keys are used by the BSD O option (when it is used for sorting). The GNU —sort option doesn’t use these keys, but the specifiers described below in the section. Note that the values used in sorting are the internal values ps uses and not the «cooked» values used in some of the output format fields (e.g., sorting on tty will sort into device number, not according to the terminal name displayed). Pipe ps output into the sort command if you want to sort the cooked values.

key long name description
c cmd simple name of executable
C pcpu CPU utilization
f flags flags as in long format F field
g pgrp process group ID
G tpgid controlling tty process group ID
j cutime cumulative user time
J cstime cumulative system time
k utime user time
m min_flt number of minor page faults
M maj_flt number of major page faults
n cmin_flt cumulative minor page faults
N cmaj_flt cumulative major page faults
o session session ID
p pid process ID
P ppid parent process ID
r rss resident set size
R resident resident pages
s size memory size in kilobytes
S share amount of shared pages
t tty the device number of the controlling tty
T start_time time process was started
U uid user ID number
u user username
v vsize total VM size in KiB
y priority kernel scheduling priority

Process State Codes

Here are the different values that the s, stat and state output specifiers (header «STAT» or «S«) display to describe the state of a process:

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

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

Options: Process Selection By List

These options accept a single argument in the form of a blank-separated or comma-separated list, and they can be used multiple times. For example:

ps -p "1 2" -p 3,4

…is a valid command.

Options which select processes by list are as follows:

123 Identical to «—pid 123«.
123 Identical to «—pid 123«.
-C cmdlist Select by command name. This selects the processes whose executable name is given in cmdlist.
-G grplist Select by real group ID (RGID) or name. This selects the processes whose real group name or ID is in the grplist list. The real group ID identifies the group of the user who created the process.
-g grplist Select by session OR by effective group name. Selection by session is specified by many standards, but selection by effective group is the logical behavior that other operating systems use. This ps will select by session when the list is completely numeric (as sessions are). Group ID numbers will work only when some group names are also specified. See the -s and —group options.
—Group grplist Select by real group ID (RGID) or name. Identical to -G.
—group grplist Select by effective group ID (EGID) or name. This selects the processes whose effective group name or ID is in grouplist. The effective group ID describes the group whose file access permissions are used by the process. The -g option is often an alternative to —group.
p pidlist Select by process ID. Identical to -p and —pid.
-p pidlist Select by PID. This selects the processes whose process ID numbers appear in pidlist. Identical to p and —pid.
—pid pidlist Select by process ID. Identical to -p and p.
—ppid pidlist Select by parent process ID. This selects the processes with a parent process ID in pidlist. That is, it selects processes that are children of those listed in pidlist.
-s sesslist Select by session ID. This selects the processes with a session ID specified in sesslist.
—sid sesslist Select by session ID. Identical to -s.
t ttylist Select by tty. Nearly identical to -t and —tty, but can also be used with an empty ttylist to indicate the terminal associated with ps. Using the T option is considered cleaner than using t with an empty ttylist.
-t ttylist Select by tty. This selects the processes associated with the terminals given in ttylist. Terminals (ttys, or screens for text output) can be specified in several forms: /dev/ttyS1, ttyS1, S1. A plain «» may be used to select processes not attached to any terminal.
—tty ttylist Select by terminal. Identical to -t and t.
U userlist Select by effective user ID (EUID) or name. This selects the processes whose effective username or ID is in userlist. The effective user ID describes the user whose file access permissions are used by the process. Identical to -u and —user.
-U userlist Select by real user ID (RUID) or name. It selects the processes whose real username or ID is in the userlist list. The real user ID identifies the user who created the process.
-u userlist Select by effective user ID (EUID) or name. This selects the processes whose effective username or ID is in userlist. The effective user ID describes the user whose file access permissions are used by the process. Identical to U and —user.
—User userlist Select by real user ID (RUID) or name. Identical to -U.
—user userlist Select by effective user ID (EUID) or name. Identical to -u and U.

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

Системные вызовы

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

Основная же работа вызова часто выполняется другой функцией, названной по шаблону .

Рассмотрим создание пользовательского процесса шаг за шагом. Создание пользовательских процессов и процессов ядра фактически выполняется одним и тем же механизмом — вызовом . При создании потока ядра оно вызывает функцию (см. файл ./linux/arch/i386/kernel/process.c), выполняющую предварительную работу и затем вызывающую .

Аналогичные действия выполняются при создании пользовательского процесса. Программа осуществляет вызов , который, в свою очередь, обращается к системному вызову (см. файл ./linux/arch/i386/kernel/process.c). Связь этих функций показана на диаграмме, приведенной на рисунке 1.

Рисунок 1. Иерархия вызовов при создании процесса

Из рисунка 1 видно, что функция выполняет основную работу по созданию процесса. Она объявлена в файле ./linux/kernel/fork.c (наряду с другой функцией создания процессов — ).

Функция начинает создание процесса с обращения к вызову , возвращающему новый PID. Затем проверяет, не находится ли родительский процесс в состоянии трассировки отладчиком. Если это так, то в параметре функции устанавливается флаг . Далее функция вызывает функцию , передавая ей флаги, стек, регистры, дескриптор родительского процесса и ранее полученный новый PID.

Функция создает новый процесс путем копирования родительского процесса. Она выполняет все необходимые действия кроме запуска процесса, который происходит позже. Сначала проверяет, допустимо ли сочетание флагов . Если это не так, она возвращает код ошибки . Затем она запрашивает Модуль безопасности Linux (LSM), разрешено ли текущей задаче породить новую задачу. Узнать больше об LSM в контексте Security-Enhanced Linux (SELinux) можно из материалов, приведенных в разделе Статьи.

Далее происходит вызов функции (объявлена в файле ./linux/kernel/fork.c), создающей новый экземпляр структуры и копирующей в него различные дескрипторы, относящиеся к текущему процессу. После создания стека нового потока производится инициализация полей структуры , описывающих состояние процесса, после чего происходит возврат в . Затем в производится проверка лимитов и полномочий, выполняются вспомогательные действия, включающие инициализацию различных полей структуры . Потом происходит вызов функций, выполняющих копирование составляющих процесса: таблицы дескрипторов открытых файлов (), таблицы сигналов и обработчиков сигналов ( и ), адресного пространства процесса () и структуры ().

Затем только что созданная задача назначается процессору из числа разрешенных для ее выполнения (). После того как новый процесс унаследует приоритет родительского процесса, выполняется еще небольшое число вспомогательных действий и происходит возврат в . Теперь новый процесс существует, но пока не выполняется. Функция решает эту проблему вызовом . Эта функция, определенная в файле ./linux/kernel/sched.c, инициализирует служебные данные планировщика, помещает новый процесс в очередь выполнения и инициирует его выполнение. После этого функция завершает создание процесса и свою работу, возвращая значение PID.

Options: Output Format Control

These options are used to choose the information displayed by ps. The output may differ from version to version.

-c Show different scheduler information for the -l option.
—context Display security context format (when using SE Linux).
-f Do full-format listing. This option can be combined with other UNIX-style options to add additional columns. It also causes the command arguments to be printed. When used with -L, the NLWP (number of threads) and LWP (thread ID) columns will be added. See the c option, the format keyword args, and the format keyword comm.
-F Extra full format. See the -f option, which -F implies.
—format format user-defined format. Identical to -o and o.
j BSD job control format.
-j Jobs format.
l Display BSD long format.
-l Long format. The -y option is often useful with this.
-M Add a column of security data. Identical to Z (for SE Linux).
O format is preloaded o (overloaded). The BSD O option can act like -O (user-defined output format with some common fields predefined) or can be used to specify sort order. Heuristics are used to determine the behavior of this option. To ensure that the desired behavior is obtained (sorting or formatting), specify the option in some other way (e.g., with -O or —sort). When used as a formatting option, it is identical to -O, with the BSD personality.
-O format Like -o, but preloaded with some default columns. Identical to «-o pid,format,state,tname,time,command» or «-o pid,format,tname,time,cmd«; see -o, below.
o format Specify user-defined format. Identical to -o and —format.
-o format User-defined format. format is a single argument in the form of a blank-separated or comma-separated list, which offers a way to specify individual output columns. The recognized keywords are described in the section below. Headers may be renamed («ps -o pid,ruser=RealUser -o comm=Command«) as desired. If all column headers are empty («ps -o pid= -o comm=«) then the header line will not be output. Column width will increase as needed for wide headers; this may be used to widen up columns such as WCHAN («ps -o pid,wchan=WIDE- WCHAN-COLUMN -o comm«). Explicit width control («ps opid,wchan:42,cmd«) is offered too. The behavior of «ps -o pid=X,comm=Y» varies with personality; output may be one column named «X,comm=Y» or two columns named «X» and «Y«. Use multiple -o options when in doubt. Use the PS_FORMAT environment variable to specify a default as desired; DefSysV and DefBSD are macros that may be used to choose the default UNIX or BSD columns.
s Display signal format.
u Display user-oriented format.
v Display virtual memory format.
X Register format.
-y Do not show flags; show rss in place of addr. This option can only be used with -l.
Z Add a column of security data. Identical to -M (for SE Linux).

Syntax

Let’s take a look at the basic syntax:

Since all arguments are optional, let’s see what it does with no options:

By default, it prints the processes of the current user and terminal in four columns:

  • PID – the process id
  • TTY – terminal associated with the process
  • TIME – elapsed CPU utilization time for the process
  • CMD – the executable command

Also, unlike the top command, we can only see a snapshot of this information at a given time.

Due to historical reasons, ps accepts options in various formats:

  • not preceded with a dash (BSD style)
  • preceded with a dash (UNIX style)
  • preceded with two dashes (GNU style)

While most options have equivalents in all three formats, we’ll be focusing primarily on UNIX-style syntax throughout the remainder of the article.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *