2004 г
Основы операционной системы UNIX
Copyleft (no c) - 1996-2004
В. Кравчук,
OpenXS Initiative, идея, составление, перевод, примеры
Назад Оглавление Вперёд
Управление процессами
Основным ресурсом компьютера является его процессор (или процессоры). В каждый
момент времени один процессор может выполнять только один процесс. Организация
планирования процессов так, чтобы за счет их переключения создавалась иллюзия
одновременной работы нескольких процессов - одна из основных задач любой
многопользовательской и многозадачной операционной системы.
В ОС UNIX основным средством организации и единицей многозадачности является
процесс - уникальным образом идентифицируемая программа, которая нуждается в
получении доступа к ресурсам компьютера. Операционная система манипулирует образом
процесса, который представляет собой программный код, а также разделами данных
процесса, определяющими среду выполнения. Сегмент кода содержит реальные
инструкции процессора, включающие как строки, скомпилированные и написанные
пользователем, так и стандартный код, сгенерированный компилятором для системы.
Этот системный код обеспечивает взаимодействие между программой и операционной
системой.
Основой операционной системы UNIX является ядро. Ядро представляет собой
специальную программу (или несколько программных модулей, в случае модульного
ядра), которая постоянно находится в оперативной памяти и работает, пока работает
операционная система. Ядро управляет всеми таблицами, используемыми для
отслеживания процессов и других ресурсов. Ядро загружается в память во время
начальной загрузки и немедленно запускает необходимые процессы, в частности процесс
инициализации операционной системы - init.
Данные, связанные с процессом, также являются частью образа процесса. Некоторые из
них хранятся в регистрах, обычно представленных регистрами процессора. Кроме того,
существуют динамические области хранения данных (куча), выделяемые процессом по
ходу работы при необходимости.
Еще у процесса есть стек, содержащийся в памяти и используемый для хранения
локальных переменных программы и передачи параметров. Когда процесс выполняет
обращение к функции или подпрограмме, в стек отправляется новый фрейм. Одной из
частей каждого фрейма является указатель на базу предыдущего фрейма, который
позволяет легко вернуться из вызова функции. При этом важно знать местоположение
текущего фрейма и вершину стека.
Регистры играют важную роль в работе процессов. Обычно
выделяется четыре регистра, имеющих специальное значение:
Регистр |
Назначение |
PC |
Программный счетчик - указывает на текущую строку кода. |
PS |
Указывает состояние процессора. |
SP |
Указывает на вершину стека. |
FP |
Указывает на текущий фрейм стека. |
Во время исполнения или в ожидании "своего часа" процессы содержатся в виртуальной
памяти со страничной организацией. Часть этой виртуальной памяти сопоставляется с
физической. Часть физической памяти резервируется для ядра операционной системы.
Пользователи могут получить доступ только к оставшейся для процессов памяти. При
необходимости, страницы памяти процессов откачиваются из физической памяти на
диск, в область подкачки. При обращении к странице в виртуальной памяти, если она не
находится в физической памяти, происходит ее подкачка с диска.
Виртуальная память реализуется и автоматически поддерживается ядром ОС UNIX.
В ОС UNIX выделяется три типа процессов: системные, процессы-демоны
и прикладные процессы.
Системные процессы являются частью ядра и всегда расположены в оперативной памяти.
Системные процессы не имеют соответствующих им программ в виде исполняемых
файлов и запускаются особым образом при инициализации ядра системы. Выполняемые
инструкции и данные этих процессов находятся в ядре системы, таким образом, они могут
вызывать функции и обращаться к данным, недоступным для остальных процессов.
К системным процессам можно отнести и процесс начальной инициализации,
init,
являющийся прародителем всех остальных процессов. Хотя init не является частью ядра,
и его запуск происходит из выполняемого файла, его работа жизненно важна для
функционирования всей системы в целом.
Демоны - это не интерактивные процессы, которые запускаются обычным
образом - путем
загрузки в память соответствующих им программ, и выполняются в фоновом режиме.
Обычно демоны запускаются при инициализации системы, но после инициализации ядра
и обеспечивают работу различных подсистем UNIX: системы терминального доступа,
системы печати, сетевых служб и т.д. Демоны не связаны ни с одним пользователем.
Большую часть времени демоны ожидают, пока тот или иной процесс запросит
определенную услугу.
К прикладным процессам относятся все остальные процессы, выполняющиеся в системе.
Как правило, это процессы, порожденные в рамках пользовательского сеанса работы.
Важнейшим пользовательским процессом является начальный командный
интерпретатор, который обеспечивает выполнение команд пользователя в системе UNIX.
Пользовательские процессы могут выполняться как в интерактивном (приоритетном),
так и в фоновом режимах. Интерактивные процессы монопольно владеют терминалом, и
пока такой процесс не завершит свое выполнение, пользователь не имеет доступа к
командной строке.
В следующем примере, показывающем часть списка процессов в ОС Solaris 8,
полужирным выделены системные процессы. В этой ОС системными являются процесс-
планировщик (sched), процесс откачки страниц виртуальной памяти (pageout)
и процесс, синхронизирующий файловые системы (fsflush). Пользовательские процессы
представлены на более темном фоне. Все остальные процессы - это демоны, реализующие
те или иные службы. Имена команд, начинающиеся с дефиса, представляют начальные
командные интерпретаторы пользователей.
[kravchuk@arturo 13:48:53 /]$ ps -ecf | more
UID PID PPID CLS PRI STIME TTY TIME CMD
root 0 0 SYS 96 Фев 23 ? 0:19 sched
root 1 0 TS 58 Фев 23 ? 0:04 /etc/init -
root 2 0 SYS 98 Фев 23 ? 0:08 pageout
root 3 0 SYS 60 Фев 23 ? 87:49 fsflush
root 411 1 TS 58 Фев 23 ? 0:00 /usr/lib/saf/sac -t 300
root 259 1 TS 50 Фев 23 ? 2:20 /usr/sbin/nscd
root 184 1 TS 46 Фев 23 ? 0:00 /usr/lib/netsvc/yp/ypxfrd
root 68 1 TS 58 Фев 23 ? 0:02
/usr/lib/sysevent/syseventd
root 144 1 TS 59 Фев 23 ? 0:00 /usr/sbin/in.rdisc -s
root 161 1 TS 58 Фев 23 ? 0:41 /usr/sbin/rpcbind
...
markov 5724 5723 TS 48 12:07:16 pts/1 0:00 -bash
root 3705 215 TS 54 09:46:57 ? 0:00 in.telnetd
root 6804 6803 IA 48 Мар 25 ?? 0:00 /usr/dt/bin/dtterm
root 87 310 TS 59 Мар 19 ? 0:02 /usr/local/samba/bin/smbd
-D -s/usr/local/samba/lib/smb.conf
root 27210 215 TS 54 Мар 27 ? 0:00 in.telnetd
root 3918 215 TS 54 10:11:00 ? 0:00 in.telnetd
kravchuk 3697 3679 TS 38 09:46:39 pts/14 0:00 -bash
...
Процесс в UNIX имеет ряд атрибутов, позволяющих операционной системе управлять
его работой. Основные атрибуты представлены в следующих подразделах.
Каждый процесс имеет уникальный идентификатор PID, позволяющий ядру системы
различать процессы. Когда создается новый процесс, ядро присваивает ему следующий
свободный (т.е. не ассоциированный ни с каким процессом) идентификатор. Присвоение
идентификатора обычно происходит по возрастающий, т.е. идентификатор нового
процесса больше, чем идентификатор процесса, созданного перед ним. Если
идентификатор достигает максимального значения (обычно - 65737), следующий процесс
получит минимальный свободный PID и цикл повторяется. Когда процесс завершает
работу, ядро освобождает использовавшийся им идентификатор.
Идентификатор процесса, породившего данный процесс. Все процессы в системе, кроме
системных процессов и процесса init, являющегося прародителем остальных процессов,
порождены одним из существующих или существовавших ранее процессов.
Относительный приоритет процесса, учитываемый планировщиком при определении
очередности запуска. Фактическое же распределение процессорных ресурсов
определяется приоритетом выполнения (атрибут PRI), зависящим от нескольких
факторов, в частности от заданного относительного приоритета. Относительный
приоритет не изменяется системой на всем протяжении жизни процесса (хотя может быть
изменен пользователем или администратором) в отличие от приоритета выполнения,
динамически изменяемого планировщиком.
Терминал или псевдотерминал, связанный с процессом. С этим терминалом по умолчанию
связаны стандартные потоки: входной, выходной и поток сообщений
об ошибках. Потоки (программные каналы) являются стандартным средством
межпроцессного взаимодействия в ОС UNIX.
Процессы-демоны не связаны с терминалом.
Реальным идентификатором пользователя данного процесса является идентификатор
пользователя, запустившего процесс. Эффективный идентификатор служит для
определения прав доступа процесса к системным ресурсам (в первую очередь к ресурсам
файловой системы). Обычно реальный и эффективный идентификаторы совпадают, т.е.
процесс имеет в системе те же права, что и пользователь, запустивший его. Однако
существует возможность задать процессу более широкие права, чем права пользователя,
путем установки бита SUID, когда эффективному идентификатору присваивается
значение идентификатора владельца выполняемого файла (например, пользователя
root).
Реальный идентификатор группы равен идентификатору основной или текущей группы
пользователя, запустившего процесс. Эффективный идентификатор служит для
определения прав доступа к системным ресурсам от имени группы. Обычно эффективный
идентификатор группы совпадает с реальным. Но если для выполняемого файла
установлен бит SGID, такой файл выполняется с эффективным идентификатором
группы-владельца.
Жизненный цикл процесса в ОС UNIX может быть разбит на несколько состояний.
Переход из одного состояния в другое происходит в зависимости от наступления
определенных событий в системе.
Возможны следующие состояния процесса:
- Процесс выполняется в пользовательском режиме. При этом процессором
выполняются прикладные инструкции данного процесса.
- Процесс выполняется в режиме ядра. При этом процессом выполняются системные
инструкции ядра от имени процесса.
- Процесс не выполняется, но готов к запуску, как только планировщик выберет его
(состояние runnable). Процесс находиться в очереди на выполнение и обладает
всеми необходимыми ему ресурсами, кроме процессора.
- Процесс находиться в состоянии сна (asleep), ожидая недоступного в данный
момент ресурса, например завершения операции ввода-вывода.
- Процесс возвращается из режима ядра в режим задачи, но ядро прерывает его и
производит переключение контекста для запуска более приоритетного процесса.
- Процесс только что создан системным вызовом fork и находится в переходном
состоянии: он существует, но не готов к запуску и не находиться в состоянии сна.
- Процесс выполнил системный вызов exit и перешел в состояние зомби
(zombie, defunct). Как такового процесса не существует, но
остаются записи, содержащие код возврата и временную статистику его выполнения,
доступную для родительского процесса. Это состояние является конечным в жизненном цикле
процесса.
Процесс начинает свой жизненный путь с состояния 6, когда родительский процесс
выполняет системный вызов fork. После того как создание процесса полностью
завершено, процесс завершает "дочернюю часть" вызова fork и переходит в состояние 3
готовности к запуску, ожидая своей очереди на выполнение. Когда планировщик
выбирает процесс для выполнения, он переходит в состояние 1 и выполняется в
пользовательском режиме.
Выполнение в пользовательском режиме завершается в результате системного вызова
или прерывания, и процесс переходит в режим ядра, в котором выполняется код системного
вызова или прерывания. После этого процесс опять может вернуться в пользовательский
режим. Однако во время выполнения системного вызова процесса в режиме ядра процессу
может понадобиться недоступный в данный момент ресурс. Для ожидания доступа к
такому ресурсу, процесс делает системный вызов sleep и переходит в состояние 4 - сна.
При этом процесс добровольно освобождает вычислительные ресурсы, которые
предоставляются следующему наиболее приоритетному процессу. Когда ресурс
становиться доступным, ядро "пробуждает процесс", используя вызов wakeup, помещает
его в очередь на выполнение, и процесс переходит в состояние 3 готовности к запуску.
При предоставлении процессу вычислительных ресурсов происходит переключение
контекста, в результате которого сохраняется образ, или контекст, текущего
процесса, и управление передается новому. Переключение контекста может произойти, например,
если процесс перешел в состояние сна, или если в состоянии готовности к запуску
находится процесс с более высоким приоритетом, чем текущий. В последнем случае ядро
не может немедленно прервать текущий процесс и произвести переключение контекста.
Дело в том, что переключение контекста при выполнении в режиме ядра может
произвести к нарушению целостности самой системы. Поэтому переключение контекста
откладывается до момента перехода процесса из режима ядра в пользовательский режим,
когда все системные операции завершены, и структуры данных ядра находятся в
нормальном состоянии.
Таким образом, после того как планировщик выбрал процесс на запуск, последний
начинает свое выполнение в режиме ядра, где завершает переключение контекста. Далее
состояние процесса зависит от предыстории.
Наконец, процесс выполняет системный вызов exit и заканчивает свое выполнение.
Процесс может быть также завершен вследствие получения сигнала. В обоих случаях ядро
освобождает ресурсы, принадлежащие процессу, за исключением кода возврата и
статистики его выполнения, и переводит процесс в состояние зомби. В этом состоянии
процесс находится до тех пор, пока родительский процесс не выполнит системный вызов
wait, после чего вся информация о процессе будет уничтожена, а родитель получит код
возврата завершившегося процесса.
Каждый процесс UNIX имеет контекст, под которым понимается вся информация,
требуемая для описания процесса. Эта информация сохраняется, когда выполнение
процесса приостанавливается, и восстанавливается, когда планировщик предоставляет
процессу вычислительные ресурсы.
Контекст процесса в ОС UNIX состоит из нескольких частей:
- Адресное пространство процесса в пользовательском режиме
Сюда входят код, данные и стек процесса, а также другие области, например,
разделяемая память или код и данные динамических библиотек.
- Управляющая информация
Ядро использует две основные структуры для управления процессом - proc и user.
Сюда же входят данные, необходимые для отображения виртуального адресного
пространства процесса в физическую память.
- Среда процесса
Переменные среды процесса, значения которых задаются в командном
интерпретаторе или в самом процессе с помощью системных вызовов,
а также наследуются порожденным процессом от родительского и обычно хранятся
в нижней части стека. Среду процесса можно получать или изменять с помощью
функций.
- Аппаратный контекст
Сюда входят значения общих и ряда системных регистров процессора, в частности,
указатель текущей инструкции и указатель стека (см. в
начале раздела).
Переключение между процессами, необходимое для распределения вычислительного
ресурса, по существу, выражается в переключении контекста, когда контекст
выполнявшегося процесса запоминается, а восстанавливается контекст процесса,
выбранного планировщиком. Переключение процесса является достаточно ресурсоемкой
операцией. Помимо сохранения состояния регистров процесса, ядро вынуждено
выполнить множество других действий.
Контекст переключается в четырех случаях:
- Текущий процесс переходит в состояние сна, ожидая недоступного ресурса.
- Текущий процесс завершает свое выполнение.
- Если после пересчета приоритетов в очереди на выполнение есть более
высокоприоритетный процесс.
- Происходит пробуждение более высокоприоритетного процесса.
Первые два случая соответствуют добровольному переключению контекста и действия
ядра при этом достаточно просты. Ядро вызывает процедуру переключения контекста из
функций sleep или exit.
Третий и четвертый случаи переключения контекста происходят не по воле процесса,
который в это время выполняется в режиме ядра и поэтому не может быть немедленно
приостановлен. В этой ситуации ядро устанавливает специальный флаг runrun, который
указывает, что в очереди находится более высокоприоритетный процесс, требующий
предоставления вычислительных ресурсов. Перед переходом процесса из режима ядра в
режим задачи ядро проверяет этот флаг и, если он установлен, вызывает функцию
переключения контекста.
Планирование процессов и UNIX основано на приоритете процесса. Планировщик всегда
выбирает процесс с наивысшим приоритетом. Приоритет процесса не является
фиксированным и динамически изменяется системой в зависимости от использования
вычислительных ресурсов, времени ожидания запуска и текущего состояния процесса.
Если процесс готов к запуску и имеет наивысший приоритет, планировщик приостановит
выполнение текущего процесса (с более низким приоритетом), даже если последний не
"выработал" свой временной квант.
Ядро UNIX является непрерываемым (nonpreemptive). Это означает, что процесс,
находящийся в режиме ядра (в результате системного вызова или прерывания) и
выполняющий системные инструкции, не может быть прерван системой, а
вычислительные ресурсы переданы другому высокоприоритетному процессу. В этом
состоянии выполняющийся процесс не может освободить процессор "по собственному
желанию", в результате недоступности какого-либо ресурса перейдя в состояние сна. В
противном случае система может прервать выполнение процесса только при переходе из
режима ядра в пользовательский режим. Такой подход значительно упрощает решение
задач синхронизации и поддержки целостности структур данных ядра.
Каждый процесс имеет два атрибута приоритета: текущий приоритет, на основании
которого происходит планирование, и относительный приоритет, называемый также
поправкой приоритета - nice number, который задается
при порождении процесса и влияет на текущий приоритет.
Диапазон значений текущего приоритета различен, в зависимости от версии ОС UNIX и
используемого планировщика. В любом случае, процессы, выполняющиеся в
пользовательском режиме, имеют более низкий приоритет, чем работающие в режиме
ядра.
Новый процесс создается в UNIX только путем системного вызова fork. Процесс,
сделавший вызов fork, называется родительским, а вновь созданный
процесс - порожденным. Новый процесс является точной копией родительского.
При порождении (разветвлении) процесса проверяется, достаточно ли памяти и места
в таблице процессов для данного процесса. Если да, то образ текущего процесса копируется
в новый образ процесса, и в таблице процессов возникает новый элемент. Новому процессу
присваивается новый уникальный идентификатор (PID). Когда изменение таблицы
процессов ядра завершается, процесс добавляется к списку процессов, доступных для
выполнения и ожидающих в очереди планировщика подобно другим процессам.
Порожденный процесс наследует от родительского процесса следующие основные
характеристики:
- Способы обработки сигналов (адреса функций обработки сигналов).
- Реальные и эффективные идентификаторы пользователя и группы.
- Значение поправки приоритета.
- Все присоединенные разделяемые сегменты памяти.
- Идентификатор группы процессов.
- Терминальную линию.
- Текущий каталог.
- Корневой каталог.
- Маска создания файлов (umask).
- Ограничения ресурсов (ulimit).
Порожденный процесс отличается от родительского процесса следующими основными
характеристиками:
- Порожденный процесс имеет свой уникальный идентификатор.
- Порожденный процесс имеет другой идентификатор родительского процесса,
равный идентификатору породившего процесса.
- Порожденный процесс имеет свои собственные копии дескрипторов файлов (в
частности, стандартных потоков), открытых родительским процессом. Каждый
дескриптор файла порожденного процесса имеет первоначально такое же значение
текущей позиции в файле, что и соответствующий родительский.
- У порожденного процесса обнуляются счетчики времени, потраченного системой
для его обслуживания.
Системный вызов fork завершается неудачей и новый процесс не порождается,
если:
- Создать процесс запрещает системное ограничение на общее количество
процессов.
- Создать процесс запрещает системное ограничение на количество процессов у
одного пользователя.
- Общее количество системной памяти, предоставленной для физического
ввода-вывода, временно оказалось недостаточным.
При успешном завершении порожденному процессу возвращается значение 0, а
родительскому процессу возвращается идентификатор порожденного процесса. В случае
ошибки родительскому процессу возвращается -1, новый процесс не создается и
переменной errno присваивается код ошибки.
Обычно после порождения порожденный процесс выполняет системный вызов
exec, перекрывающий сегменты текста и данных процесса новыми
сегментами текста и данных, взятыми из указанного выполняемого файла. При этом
аппаратный контекст процесса инициализируется заново.
Выполняемый файл состоит из заголовка, сегмента команд и сегмента данных. Данные
(глобальные переменные) состоят из инициализированной и неинициализированной
частей.
Если системный вызов exec закончился успешно, то он не может вернуть
управление, так как вызвавший процесс уже заменен новым процессом. Возврат из
системного вызова exec свидетельствует об ошибке. В таком случае результат
равен -1, а переменной errno присваивается код ошибки.
Новый процесс наследует у процесса, вызвавшего exec, следующие основные
характеристики:
- Значение поправки приоритета.
- Идентификатор процесса.
- Идентификатор родительского процесса.
- Идентификатор группы процессов.
- Терминальную линию.
- Текущий каталог.
- Корневой каталог.
- Маску создания файлов.
- Ограничения ресурсов.
- Счетчики времени, потраченного системой на обслуживание этого процесса.
- Блокировки доступа к сегментам файлов.
Процесс обычно переводится в состояние сна при обработке системной функции. Если
для завершения обработки запроса требуется недоступный ресурс, процесс снимается с
процессора и переводится в состояние сна.
Состояние сна - это логическое состояние процесса, при этом он не перемещается
физически в памяти. Переход в состояние сна, в первую очередь, определяется занесением
в системную таблицу процессов соответствующего флага состояния и события,
пробуждающего процесс.
События информируют о доступности того или иного ресурса. Как правило, события
связаны с работой периферийных устройств. Наступление одного и того же события
может ожидать несколько процессов. Поскольку переход из состояния в состояние акт
скорее логический, то и пробуждаются все процессы ожидающие данное событие. Это
приводит к смене состояния со "сна" на "готов к выполнению", и соответствующие
процессы помещаются в очередь на запуск. Задачу выбора процесса для запуска решает
планировщик.
Поскольку планировщик принимает решение о запуске процесса, основываясь на
приоритетах, единственным способом установить "справедливый" порядок запуска
процессов является присвоение определенного приоритета каждому событию.
Процесс завершает работу при выполнении системного вызова exit. Процесс может
сам завершить свою работу, в соответствии с алгоритмом, либо может быть прекращен ядром.
При завершении процесса последовательно выполняются следующие действия:
- Отключаются все сигналы.
- В вызвавшем процессе закрываются все дескрипторы открытых файлов.
- Если родительский процесс находится в состоянии вызова wait, то системный вызов
wait завершается, выдавая родительскому процессу в качестве результата
идентификатор завершившегося процесса, и младшие 8 бит его кода завершения.
- Если родительский процесс не находится в состоянии вызова wait, то
завершающийся процесс переходит в состояние зомби.
У всех существующих потомков завершенных процессов, а также у зомби-процессов
идентификатор родительского процесса устанавливается равным 1. Таким образом, они
становятся потомками процесса инициализации (init).
Если идентификатор процесса, терминальная линия и идентификатор группы процессов у
завершающегося процесса совпадают, то всем процессам с тем же идентификатором
группы процессов посылается сигнал SIGHUP. Тем самым, завершаются и все
порожденные в приоритетном режиме процессы.
Родительскому процессу посылается сигнал SIGCHLD (завершение порожденного
процесса). Этот сигнал пробуждает родительский процесс, если тот ожидает завершения
порожденных процессов.
Для получения информации о состоянии процессов используется команда ps. Она имеет
следующий синтаксис:
-
ps [-acdelfjLP]
[-t список_терминалов]
[-p список_идентификаторов_процессов]
[-u|U список_идентификаторов_пользователей]
[-g список_идентификаторов_лидеров_групп]
[-G список_числовых_идентификаторов_групп]
Основные опции команды ps в системах SVR4 и BSD описаны в табл. 16.
Таблица 16. Опции команды ps
Опция |
Назначение |
-a |
Предоставляет информацию обо всех процессах, кроме групповых, и
не связанных с терминалом. |
-d |
Предоставляет информацию обо всех процессах, исключая лидеров
сеанса. |
-e |
Предоставляет информацию обо всех процессах. |
-l |
Генерирует длинный листинг. |
-f |
Генерирует полный листинг. |
-g список |
Выводит информацию только о процессах, для которых указаны
идентификаторы лидеров групп. Лидер группы - это процесс, номер
которого идентичен его идентификатору группы. Командный
интерпретатор, запускаемый при входе в систему, является
стандартным примером лидера группы. |
-G список |
Предоставляет информацию обо всех процессах, имеющих
отношение к указанным номерам групп. |
-p список |
Предоставляет информацию по процессам с указанными идентификаторами. |
-t список |
Предоставляет информацию по процессам, имеющим отношение к
указанным терминалам. |
-U список |
Предоставляет информацию обо всех процессах, имеющих
отношение к указанным идентификаторам пользователей. |
-u список |
Предоставляет информацию обо всех процессах, имеющих
отношение к указанным именам пользователей. |
Основные поля в результатах выполнения команды ps представлены в табл. 17.
Таблица 17. Основные характеристики процессов,
предоставляемые командой ps
Заголовок |
Значение |
ADDR |
Адрес процесса в памяти. |
С |
Доля выделенного планировщиком времени ЦП. |
COMD |
Имя команды и аргументы (для опции -f). |
F |
Флаги (шестнадцатеричные), логическая сумма которых дает следующие
сведения о процессе:
-
00 - процесс терминирован; элемент таблицы процессов свободен;
01 - системный процесс: всегда в основной памяти;
02 - процесс трассируется родительским процессом;
04 - родительский трассировочный сигнал остановил процесс;
родительский процесс ждет [см. ptrace(2)];
08 - процесс не может быть разбужен сигналом;
10 - процесс в основной памяти;
20 - процесс в основной памяти; блокирован до завершения события;
40 - идет сигнал к удаленной системе;
80 - процесс в очереди на ввод-вывод.
|
NI |
Поправка приоритета. |
PID |
Идентификатор процесса. |
PPID |
Идентификатор родительского процесса. |
PRI |
Текущий приоритет процесса. |
S |
Состояние процесса:
-
B,W - процесс находиться в состоянии ожидания;
I - создание процесса;
O - процесс выполняется;
R - находиться в очереди готовых к выполнению процессов;
S - процесс не активен;
T - процесс трассируется;
X - ожидает дополнительной оперативной памяти;
Z - процесс "зомби".
|
STIME |
Время запуска процесса. |
SZ |
Размер (в блоках по 512 байт) образа процесса в памяти. |
TIME |
Общее время выполнения для процесса |
TTY |
Терминальная линия процесса |
UID |
Идентификатор пользователя владельца процесса |
WCHAN |
Адрес события, которого ожидает процесс. У активного процесса этот
столбец - пустой. |
В зависимости от переданных опций и реализации, команда ps может выдавать и другие
атрибуты. Команду ps может выполнять любой пользователь. Рассмотрим простой
пример:
[kravchuk@arturo 15:59:30 /]$ ps
PID TTY TIME CMD
3697 pts/14 0:00 bash
[kravchuk@arturo 15:59:33 /]$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
8 S 31061 3697 3679 0 51 20 e3110048 499 e31100b4 pts/14 0:00 bash
[kravchuk@arturo 15:59:38 /]$ ps -p 5726
PID TTY TIME CMD
5726 pts/1 0:00 mc
Во всех UNIX-системах пользователи могут при запуске процесса задавать значение
поправки приоритета с помощью команды nice. (Говорят, что команда запускается "из-
под" nice.) Эта команда имеет следующий синтаксис:
-
nice [-инкремент | -n [-|+]инкремент] команда [аргумент...]
Диапазон значений инкремента в большинстве систем - от -20 до 20. Если инкремент
не задан, используется стандартное значение 10. Положительный инкремент означает
снижение текущего приоритета. Обычные пользователи могут задавать только
положительный инкремент и, тем самым, только снижать приоритет.
Пользователь root может задать отрицательный инкремент, который повышает
приоритета процесса и, тем самым, способствует его более быстрой работе:
# nice -n -10 make
Сигналы обеспечивают механизм вызова определенной процедуры при наступлении
некоторого события (аналогично прерываниям). Каждое событие имеет свой числовой
идентификатор (обычно в диапазоне от 1 до 36) и соответствующую символьную
константу - имя. При работе с сигналами необходимо различать две фазы:
- Генерация или посылка сигнала.
- Доставка и обработка сигнала.
Сигнал отправляется, когда происходит определенное событие, о наступлении которого
должен быть уведомлен процесс. Сигнал считается доставленным, когда процесс,
которому был отправлен сигнал, получает его и выполняет его обработку. В промежутке
между этими двумя событиями сигнал ожидает доставки.
Сигнал может посылаться одним процессом другому (с помощью соответствующего
системного вызова ) и будет доставлен, если оба процесса - одного пользователя или
сигнал послан от имени пользователя root. Сигналы посылаются также ядром.
Ядро генерирует и посылает процессу сигнал в ответ на ряд событий, которые могут быть
вызваны самим процессом, другим процессом, прерыванием или каким либо внешним
событием. Основные причины отправки сигнала:
- Исключительные ситуации
-
Выполнение процесса вызывает исключительну ситуацию, например, деление на 0.
- Терминальные прерывания
-
Нажатие клавиш терминала, например, <Del>, <Ctrl+C>, <Ctrl+\>,
вызывает посылку сигнала текущему процессу, связанному с терминалом.
- Другие процессы
-
Процесс может посылать сигнал другому процессу или группе процессов с
помощью системного вызова kill. В этом случае сигналы являются
элементарной формой межпроцессного взаимодействия.
- Управление заданиями
-
Командные интерпретаторы, поддерживающие средства управления
заданиями, используют сигналы для манипулирования фоновыми и
текущими процессами. Когда процесс, выполняющийся в фоновом режиме,
делает попытку чтения или записи на терминал, ему посылается сигнал
останова. Когда порожденный процесс завершает свою работу,
родительский процесс уведомляется об этом также с помощью сигнала.
- Квоты
-
Когда процесс превышает выделенную ему квоту вычислительных ресурсов
или ресурсов файловой системы, ему посылается соответствующий сигнал.
- Уведомления
-
Процесс может запросить уведомление о наступлении тех или иных
событий, например, готовности устройства и т.д. Такое уведомление
посылается процессу в виде сигнала.
- Будильники
-
Если процесс установил таймер, ему будет послан сигнал, когда значение
таймера станет равным 0.
Для каждого сигнала в системе определена обработка по умолчанию, которую выполняет
ядро, если процесс не указал другого действия. В общем случае возможны действия:
завершить выполнение процесса (с созданием образа памяти core и без), игнорировать
сигнал, остановить процесс и продолжить процесс.
Следует заметить, что любая обработка сигнала, в том числе и обработка по умолчанию,
подразумевает, что процесс выполняется. На системах с высокой загрузкой это может
привести к задержкам между отправлением и доставкой сигнала, т.к. процесс не может
получить сигнал, пока не будет выбран планировщиком, и ему не будут предоставлены
вычислительные ресурсы.
Доставка сигнала происходит после того, как ядро от имени процесса вызывает
системную процедуру issig(), которая проверяет, существуют ли ожидающие доставки
сигналы, адресованные данному процессу. Процедура issig() вызывается ядром в трех
случаях:
- Непосредственно перед возвращением из режима ядра в пользовательский режим
после обработки системного вызова или прерывания.
- Непосредственно перед переходом процесса в состояние сна с приоритетом,
допускающим прерывание сигналом.
- Сразу же после пробуждения после сна с приоритетом, допускающим прерывание
сигналом.
Если процедура issig() обнаруживает ожидание доставки сигнала, ядро вызывает функцию
доставки сигнала, которое выполняет действие по умолчанию или вызывает специальную
функцию sendsig(), запускающую обработчик сигнала, зарегистрированный процессом.
Функция sendsig() возвращает процесс в пользовательский режим, передает управление
обработчику сигнала, а затем восстанавливает контекст процесса для продолжения
прерванного сигналом выполнения.
Работа с сигналами, связанными с исключительными ситуациями, незначительно
отличается от описанной выше. Исключительная ситуация возникает при выполнении
процессом определенной инструкции, вызывающей в системе ошибку. Если такое
происходит, вызывается системный обработчик исключительной ситуации, и процесс переходит в
режим ядра, почти так же, как и при обработке любого другого прерывания. Обработчик
отправляет процессу соответствующий сигнал, который доставляется, когда процесс
возвращается в пользовательский режим.
В состоянии сна существуют две категории событий, вызвавших состояние сна процесса:
допускающие прерывание сигналом и не допускающие такого прерывания. В последнем
случае сигнал будет терпеливо ожидать нормального пробуждения процесса.
Информация об основных сигналах представлена в табл. 18.
Таблица 18. Основные сигналы
Сигнал |
Стандартная обработка |
Значение |
SIGTERM
15 |
Завершение процесса |
Стандартный сигнал, посылаемый для остановки процесса. |
SIGHUP
1 |
Завершение процесса |
Отключился терминал (или закрыто терминальное
окно). Сигнал посылается всем не фоновым
процессам, связанным с соответствующей
терминальной линией. |
SIGKILL
9 |
Завершение процесса |
Не перехватываемый сигнал, позволяющий завершить любой процесс. |
SIGILL
4 |
Завершение процесса и сброс образа памяти |
На центральный процессор была послана запрещенная инструкция. Это могло быть следствием
недопустимого перехода в машинном коде программы, например,
попытки выполнить строку данных. |
SIGTRAP
5 |
Завершение процесса и сброс образа памяти |
Была установлена ловушка точки прерывания процесса. Этим управляет системный
вызов ptrace, который полезен для отладки. |
SIGFPE
8 |
Завершение процесса и сброс образа памяти |
Была попытка выполнить запрещенную арифметическую операцию, например, взятие
логарифма отрицательного числа или деление на 0. |
SIGBUS
10 |
Завершение процесса и сброс образа памяти |
Ошибка на шине ввода-вывода. Обычно это является результатом попытки выполнить
чтение или запись вне границ памяти программы. |
SIGSEGV
11 |
Завершение процесса и сброс образа памяти |
Это нарушение сегментации - проклятие разработчиков программ! Оно означает, что
вы попытались получить доступ к сегменту памяти запрещенным образом. Может быть,
это было присваивание значения части сегмента кода или
чтение из нулевого адреса. |
SIGPIPE
13 |
Завершение процесса |
Программа попыталась выполнить чтение или запись в программный канал, другой конец
которого уже завершил работу. Этот сигнал помогает завершить
работу конвейера, когда одна из его команд дала сбой. |
SIGALRM
14 |
Завершение процесса |
Программист может установить будильник, чтобы позволить вам в определенный момент времени
выполнить какое-нибудь действие. |
SIGCHLD
18 |
Игнорируется |
Сначала это был сигнал завершения работы дочернего процесса, но сейчас он означает
изменение состояния дочернего процесса. |
SIGTSTP
24 |
Остановка процесса |
Это запрос от терминала на остановку процесса. Посылка этого сигнала процессу происходит при
нажатии комбинации клавиш Ctrl-Z. |
SIGCONT
25 |
Игнорируется |
Этот сигнал указывает процессу на возобновление его
работы. Процессу посылается либо команда fg, либо bg, а командный
интерпретатор выполняет внутренний системный вызов wait для
привилегированного процесса, либо не выполняет его для фонового процесса. |
Детальная информация о сигналах представлена на страницах справочного руководства
signal.
Процесс с помощью системного вызова signal() может задать нестандартный обработчик
любого сигнала, кроме SIGKILL (9).
Для посылки сигналов из командного интерпретатора используется команда kill. Она
имеет следующий синтаксис:
-
kill [ -сигнал ] pid ...
Эта команда посылает указанный сигнал (по умолчанию - SIGTERM) всем процессам с
указанными идентификаторами. Посылать сигнал можно и не существующему процессу -
выдается предупреждение, но другим процессам сигнал посылается. Посылаемый сигнал
задается по имени без префикса SIG или по номеру, например:
[kravchuk@arturo 16:56:55 /]$ echo $$
3697
[kravchuk@arturo 16:56:58 /]$ kill -STOP 3697
В результате текущий сеанс зависает.
Назад Оглавление Вперёд