Свойства процессов
Каждый процесс имеет уникальный идентификатор, владельца и группы, наследуемые от родителя, представленные эффективным идентификатором пользователя и эффективным идентификатором группы, реальных владельца и группу, класс планирования и приоритет и всегда нуждается в процессорном времени и определенном объеме оперативной памяти.
Процесс имеет уникальный номер - PID (process ID), целое число в диапазоне 0-2n, где n – разрядность системы. Например, процесс с номером 0 – свопинг, а с номером 1- init, порождающий все процессы в системе при ее загрузке. У всех процессов, кроме init, есть родительский процесс, и, следовательно, каждому процессу соответствует идентификатор родительского процесса (PPID - parent process ID).
Также в таблице процессов имеются eUID (effective UID - эффективный идентификатор пользователя) владельца процесса и eGID (effective GID - эффективный идентификатор группы) группы процесса. Реальные владелец и группа процесса – те, которые его запустили, а эффективные - те, от имени которых запущен процесс. Для определения прав доступа используются эффективные идентификаторы, а для управления процессом (например, pkill) – реальные, все идентификаторы передаются от родительского процесса к дочернему. Получить полный список процессов в системе с выводом их идентификаторов и ряда других параметров можно с помощью команды ps –ef (при использовании разных ключей выводимые параметры (но не их значения) могут отличаться):
# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 0 0 0 10:49:05 ? 0:13 sched
root 1 0 0 10:49:06 ? 0:01 /sbin/init
root 2 0 0 10:49:06 ? 0:00 pageout
root 3 0 0 10:49:06 ? 5:13 fsflush
root 7 1 0 10:49:09 ? 0:11 /lib/svc/bin/svc.startd
root 9 1 0 10:49:09 ? 0:26 /lib/svc/bin/svc.configd
daemon 315 1 0 10:49:40 ? 0:01 /usr/lib/nfs/nfsmapid
root 177 1 0 10:49:33 ? 0:10 /usr/sbin/nscd
root 166 1 0 10:49:30 ? 0:00 devfsadmd
<…>
UID - эффективный идентификатор владельца процесса (реальный выводится при использовании ключа -f),
F - flags (флаги) - флаги процесса, это поле, сохраненное для совместимости,
S - state (состояние) - состояние процесса, которое может быть следующим:
O (ON PROC) - процесс находится в процессоре и выполняется;
S (Sleeping) - процесс ждет завершения события (например, ввода-вывода);
R (Runnable) - процесс готов к выполнению, ждет своего кванта в очереди к процессору;
Z (Zombie) - процесс стал «зомби», так как завершился, а родительский процесс не подождал его завершения;
T (sTopped) - процесс остановлен по сигналу остановки или в процессе трассировки.
Идентификатор PID - уникальный идентификатор процесса, используется при передаче ему сигналов.
PPID - идентификатор родительского процесса.
C - загрузка процессора на планирование задачи.
CLS - класс планирования.
PRI - приоритет процесса; когда указан ключ -с, большие значения означают больший приоритет, без ключа -с большие значения означают меньший приоритет.
NI - значение NICE (показателя уступчивости), используется при вычислении глобального приоритета процессов в классе разделения времени.
ADDR - адрес в памяти.
SZ - размер процесса в виртуальной памяти, измеряемый в страницах памяти, для получения размера в килобайтах в большинстве случаев это значение надо умножить на 4.
WCHAN - адрес события, ради которого процесс перешел в состояние сна, если поле пусто, процесс запущен.
STIME - время запуска процесса, для запущенных более суток назад процессов указываются месяцы и дни.
TTY - управляющий терминал, символ "?" печатается для процесса без управляющего терминала.
TIME - сколько времени процесс отнял у процессора.
CMD - команда, которой был запущен процесс.
При указании ключа j выводятся дополнительные сведения:
PGID - идентификатор лидера группы процессов.
SID - идентификатор процесса-лидера сессии.
При указании ключа L выводятся дополнительные сведения, обычные однопоточные процессы соотносятся только с одним легковесным процессом:
LWP - идентификатор легковесного процесса.
NLWP - число легковесных процессов для процесса.
Завершившиеся процессы, код завершения которых не был востребован родительским процессом, помечаются как "defunct". Обычно процессы-зомби автоматически уничтожаются процессом init, но если этого не произошло, можно воспользоваться программой preap, которая примет код завершения процесса-зомби.
Кроме программы ps в UNIX для получения информации о запущенных в данный момент процессах используется команда top (соответствующая утилита устанавливается отдельно).
Команда prstat позволяет в динамике (как и top) отслеживать состояние процессов:
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
489 root 47M 29M sleep 59 0 0:00:06 1,9% Xorg/1
634 olga 6116K 3456K cpu0 59 0 0:00:00 2,2% prstat/1
<...>
Total: 70 processes, 226 lwps, load averages: 0,16, 0,24, 0,14
Приоритеты
Во многих UNIX-подобных ОС процесс имеет базовый приоритет (NICE), который принимает значения от +20 до -20, и чем меньше числовое значение – тем он выше, и динамический приоритет (PRI), вычисляемый планировщиком задач и снижающийся с увеличением потребленного процессорного времени.
В Solaris применяется более сложная схема планирования, но для класса с разделением времени справедлива вышеописанная.
Объектом назначения приоритета является поток ядра. Если процесс сопоставлен только одному потоку ядра, то приоритет процесса и приоритет этого потока ядра - это одно и то же.
Приоритет базируется на классе планирования (scheduling class). В Solaris шесть классов планирования:
с разделением времени (timesharing, TS),
интерактивный (interactive, IA),
системный (system, SYS),
реального времени (real-time, RT),
с фиксированным приоритетом (fixed priority, FX),
планирование на основе справедливого раздела (fair share scheduling, FSS).
С помощью команды
# ps -cl
F S UID PID PPID CLS PRI ADDR SZ WCHAN TTY TIME CMD
0 O 100 14817 14800 TS 49 ? 186 pts/1 0:00 ps
0 S 100 14800 14798 TS 49 ? 396 ? pts/1 0:00 bash
можно узнать глобальные приоритеты запущенных процессов, а внутренние приоритеты процессов в разных классах планирования - с помощью команды dispadmin.
У процессов разных классов планирования свои уровни приоритета и свои очереди на выполнение. Внутри каждого класса процессы, стоящие в очереди, имеют свои уровни приоритета, которые переходят в глобальные приоритеты планирования (global scheduling priorities). Первым процессор займет процесс с высшим глобальным приоритетом. Процесс из класса планирования с разделением времени имеет более низкий глобальный приоритет, чем процесс из системного класса, а тот, в свою очередь, более низкий, чем процесс реального времени.
Процесс получает свой класс планирования и приоритет от родительского процесса. Изменить класс планирования можно либо с помощью команды priocntl или посредством одноименного системного вызова. Получить информацию о текущих классах планирования процессов можно с помощью команды dispadmin.
Процессы реального времени
Планирование в реальном времени относится к средствам, с помощью которых процессу по мере необходимости обеспечивается квант процессора.
Существуют три варианта планирования процессов реального времени:
поддержки нет,
строгая поддержка реального времени (для приложений соблюдаются все предельные сроки),
нестрогая поддержка реального времени (поддерживается статистический минимум).
Solaris - ОС с нестрогой поддержкой реального времени, т.е. период реакции приложения должен иметь гарантированную конечную продолжительность (в Solaris – 5 мс).
Отсутствие поддержки реального времени в UNIX-подобных ОС связано с ошибкой обращения к ОП из-за отсутствия страниц в ней и существования «точек невыгружаемости» (nonpreemption points) – ситуаций, когда не допускается выгрузка ядра из процессора (например, обработка прерываний). Первая проблема в Solaris решается достаточно просто - страницы процесса реального времени в памяти блокируются и их выгрузка на диск запрещается, а вторая решается за счет того, что обработчики прерываний реализованы как отдельные потоки, что делает возможным установить для них отдельный приоритет, а также возможности «одалживания приоритета» у более приоритетного процесса.
Проверка приоритета процесса
Выяснить, с каким легковесным процессом ассоциирован конкретный процесс и какой класс планирования ему назначен, можно с помощью команды ps и ключей -L и -с:
# ps -L
PID LWP TTY LTIME CMD
616 1 pts/2 0:00 bash
624 1 pts/2 0:00 ps
# ps -c
PID CLS PRI TTY TIME CMD
616 IA 32 pts/2 0:00 bash
629 IA 59 pts/2 0:00 ps
Чем больше числовое значение глобального приоритета (значение PRI), тем выше глобальный приоритет процесса.
Настройка таблиц диспетчера
Вначале таблица диспетчера конкретного класса выводится в файл (с использованием команды dispadmin), затем файл редактируется в текстовом редакторе и загружается обратно в таблицу диспетчера.
Активные классы планирования:
# dispadmin -l
CONFIGURED CLASSES
==================
SYS (System Class)
TS (Time Sharing)
IA (Interactive)
Далее выводится таблица диспетчера для выбранного класса:
# dispadmin -c IA -g
# Interactive Dispatcher Configuration
RES=1000
# ia_quantum ia_tqexp ia_slpret ia_maxwait ia_lwait PRIORITY LEVEL
200 0 50 0 50 # 0
200 0 50 0 50 # 1
200 0 50 0 50 # 2
200 0 50 0 50 # 3
<…>
Смысл значений, приведенных в столбцах таблицы диспетчера:
ia_quantum - максимальный период времени (квант), в течение которого поток может оставаться в процессоре до того, как диспетчер изменит его приоритет;
ia_tqexp - приоритет, который будет назначен потоку после того, как истечет его квант времени и он будет удален из процессора;
ia_slpret указывает приоритет, который будет иметь процесс, когда он будет обрабатываться после ожидания завершения ввода-вывода или когда он дождется снятия блокировки с требуемого ресурса;
ia_maxwait указывает время в секундах, которое процесс будет оставаться в очереди,
ia_lswait обозначает присваиваемый процессу приоритет, когда процесс на долгое время был вытеснен из процессора.
В Solaris стандартный планировщик задач старается предоставить процессам (которые по умолчанию запускаются с классом планирования timesharing) примерно одинаковый доступ к процессору. Если некоторые процессы в системе более важны, чем другие, можно использовать планирование на основе справедливого раздела (fair share scheduler - FSS), тогда можно будет назначить группам процессов разный процент процессорного времени, которые они будут получать в единицу времени.
Распределение памяти, swaping
Если запущенные процессы и процессы, ожидающие возможности продолжить свое выполнение, занимают больший объем памяти, чем объем ОП, в системе используется виртуальная память, складывается из оперативной памяти и swap-разделов. В UNIX вся память разделена на страницы одинакового размера и выделение памяти осуществляется постранично для каждого процесса. Узнать размер страницы памяти можно по команде pagesize, и это свойство зависит не только от ОС, но и от архитектуры (в Solaris x86 – 4 Кб).
Для описания процесса обмена страницами между памятью и диском используется термин "свопинг" (swaping), означающий полную выгрузку страниц процесса на диск, но на самом деле обычно выполняется "пейджинг" (paging) - постраничная выгрузка процесса на диск, а свопинг выполняется лишь при критическом недостатке памяти. Если в течение определенного периода времени к странице памяти не произошло обращения, она выгружается на диск.
Для планирования размера swap-разделов нужно представлять, сколько памяти может потребоваться тем программам, которые будут одновременно работать в системе. Определяется объем памяти эмпирически: запускается по одной копии каждой программы, занятый каждой из них объем памяти умножается на число программ такого типа, эти значения суммируются, а сумма удваивается – для получения запаса. Если получившийся объем ОП установить физически невозможно, нужно предположить, какой объем памяти критически важен и скольким программам придется остаться в swap-разделе.
Интерактивные и фоновые процессы
Процесс, имеющий доступ к вводу с терминала и к выводу на него, называется интерактивным (foreground), например, редактор vi. Фоновый процесс не имеет доступа к вводу с терминала, а к выводу имеет условный доступ - вывод на терминал разрешен, если терминал настроен для работы в режиме tostop:
# stty -tostop
Обратная настройка выполняется командой
# stty tostop
Если фоновый процесс начинает выполнять вывод на терминал во время работы текстового редактора или подобных программ, достаточно нажать Ctrl-L, чтобы обновить экран, и выводимые сообщения исчезнут.
Для запуска фонового процесса из командного интерпретатора нужно дать команду, завершив ее амперсандом (&).
Взаимодействие процессов
Процессы могут асинхронно или синхронно передавать друг другу данные и управление доступом к ресурсам системы. С каждым процессом связаны три независимых потока данных: стандартный ввод (stdin), стандартный вывод (stdout) и стандартный поток сообщений об ошибках (stderr), а каждому из этих потоков сопоставляются внутренние дескрипторы файлов: входному потоку - 0, выходному потоку - 1, потоку сообщений об ошибках - 2. Внутренний дескриптор файла существует только в пределах процесса, с которым он связан. Внутренние дескрипторы в разных процессах имеют одинаковые номера, но они физически разные.
Перенаправление потоков
Поток данных, связанный с процессом, может быть перенаправлен в файл или другой поток данных. Например, чтобы программа find выводила список имен файлов в файл names, следует выполнить команду
# find / -name "file name" > names
Символ правой угловой скобки означает перенаправление выходного потока запущенной программы в файл, следовательно, будет создан файл names, а если файл с таким именем уже существует, то он будет уничтожен и затем будет создан новый файл с таким именем и новым содержимым.
Для добавления вывода программы в конец файла следует использовать конструкцию "две правые угловые скобки».
Также существует возможность перенаправить выходной поток одного процесса во входной поток другого. Например, направить выходной поток программы ls во входной поток программы more, чтобы список файлов выводился поэкранно, можно так:
# ls -l | more
Такая конструкция, называемая конвейером, применяется, когда одновременно запускается несколько программ, передающих данные друг другу.
Сигналы
Процессы взаимодействуют, посылая друг другу сигналы. Список сигналов в Solaris ограничен сорока двумя сигналами, а, например, стандарт POSIX 1.1 определяет 31 сигнал, но наиболее употребительны сигналы TERM, KILL и HUP.. Каждый сигнал имеет свое мнемоническое обозначение и номер, который может различаться в зависимости от системы.
Обычный процесс может послать сигнал только тому процессу, который запущен тем же пользователем. Процесс, работающий от имени root, может послать любой сигнал любому процессу в системе.
С помощью команды kill можно послать сигнал с номером этого сигнала процессу с идентификатором PID:
В некоторых системах можно посылать сигнал процессу с определенным именем посредством программы killall:
killall –номер сигнала имя процесса
Но в Solaris эта программа выполняет отправку сигнала завершения всем активным процессам, а отправить сигнал процессам с определенным именем можно командой pkill.
Но отправка сигнала процессу с определенным именем - не единственное умение pkill. Например,
отправит сигнал HUP всем процессам, относящимся к группе daemon.
Конструкцию «ps -ef | grep команда» в Solaris можно заменить более короткой формой – «pgrep команда».
Команды управления процессами
Основным средством управления процессами является команда kill, передающая процессу сигналы. Команда kill и сигнал KILL – омонимы, но не синонимы, потому что с помощью одноименной команды можно передать процессу как сигнал KILL, так и любые другие сигналы.
Будучи запущенной без ключей, она передает процессу сигнал TERM, требующий завершения процесса:
kill [-ключи] номер_процесса
Сообщение «No such pid» (при повторении команды для проверки) говорит о том, что процесс уже завершился.
При запуске процесса можно менять его базовый приоритет внутри класса планирования, но такая возможность имеется только для класса разделения времени. Обычный пользователь может только понижать приоритет процесса, а root может менять NICE в обе стороны, для чего используется команда nice, которая в Solaris выглядит так:
nice -n приращение команда
Например, nice -n 5 ls, в результате чего будет проведено снижение приоритета на 5 единиц.
Базовый приоритет уже запущенного процесса можно изменить командой renice:
Каналы и сокеты
В UNIX предусмотрены механизмы обмена данными между процессами. Прежде всего, это каналы (pipes) и сокеты (sockets), служащие для межпроцессной коммуникации.
Канал - это последовательность байт, используемая как однонаправленный поток ввода/вывода. Существуют именованные и неименованные каналы, способы обращения к которым отличаются. При использовании канала один процесс открывает канал для чтения, другой - для записи.
Сокет - это объект, который используется для межпроцессных коммуникаций, и он существует, пока процесс хранит дескриптор, ссылающийся на него. Сокет создается системным вызовом socket, который возвращает его дескриптор.
Для каждого процесса ядро хранит таблицу внутренних дескрипторов ("descriptor table"), наследуемую от родительского процесса, поэтому вместе с ней наследуется и доступ к объектам, на которые ссылаются дескрипторы (файлам, каналам и сокетам).
Семафоры
Семафор - переменная, в зависимости от значения которой доступ к ресурсу разрешается или блокируется до его освобождения. Для настройки подсистемы семафоров в Solaris нужно внести изменения в файл конфигурации ядра /etc/system.
Узнать текущие значения параметров семафоров в Solaris можно с помощью команды sysdef | tail -25, а текущие наборы семафоров в системе покажет команда ipcs –sb, удалить соответствующие наборы семафоров можно командой ipcrm -s semsetID, где semsetID - идентификатор набора семафоров.
Планирование запуска процессов
Для планирования однократных действий в любом UNIX используется программа at, а для регулярных - crontab.
Для планирования однократного запуска задач в определенное время (точность - одна минута) используется программа at. Она создает и изменяет список задач, размещая его в каталоге /var/spool/cron/atjobs/.
Список задач ежеминутно проверяется демоном cron, отвечающим за своевременный запуск задач. (Во многих других системах демон cron не отвечает за задания, запланированные с помощью at, для них имеется специальный демон - atd.)
Чтобы at могла верно запланировать задачи, следует указать ей время и дату запуска задачи:
# at time date
Параметр time может быть задан в форме HH:MM или словами midnight, noon, now, также можно указать временя с суффиксом AM или PM. Дата должна быть в формате название месяца день [год] или MMDDYY, MM/DD/YY, DD.MM.YY. Также можно указать время в виде now+ n единицы, где единицы - это minutes, hours, days, weeks. Допускается использовать суффикс today или tomorrow.
Программа at принимает список задач для выполнения во входной поток.
at -l (или atq) распечатывает список поставленных в очередь задач.
at -r позволяет удалить задачу по идентификатору, который показывает at -l.
В некоторых системах at -r называется atrm, в Solaris используются оба варианта.
Суперпользователь всегда может воспользоваться at, а имя обычного пользователя должно быть указано в /usr/lib/cron/at.allow. Если этого файла нет, то проверяется наличие имени пользователя в /usr/lib/cron/at.deny. Если ни одного из двух файлов нет, пользоваться at разрешается только пользователям, которым назначена роль solaris.jobs.user (по умолчанию - root). Если есть только файл /usr/lib/cron/at.deny и он пуст, то всем разрешено пользоваться at. Задания at и crontab заблокированного пользователя не запускаются.
Задание, запущенное на выполнение демоном cron, выполняется от имени пользователя, поставившего задание в очередь. Запланированные задачи выполняются в среде командного процессора /bin/sh без назначения управляющего терминала.
Cron
Демон cron ежеминутно инспектирует таблицу запланированных задач и выполняет те задачи, время которых наступило, но в Solaris - не более 100 задач в минуту. Программа crontab служит для планирования периодически запускаемых процессов и совместно с at подготавливаtт таблицу заданий для cron. У каждого пользователя есть своя таблица crontab и ее можно отредактировать командой crontab -e.
Формат таблицы crontab: каждая строка описывает одну задачу, в строке содержится шесть полей:
mm hh dd mo dw command
mm - минуты от 0 до 59;
hh - часы от 0 до 23;
dd - числа от 1 до 31;
mo - месяцы от 1 до 12;
dw - дни недели от 0 до 7, 0 и 7 - это воскресенье;
command - команда, которую надо запустить.
В первых строках таблицы могут быть установлены переменные среды окружения. Для просмотра таблицы crontab используется команда crontab -l, для удаления таблицы - crontab -r. Можно создать файл с таблицей crontab заранее и установить ее в систему командой
crontab имя файла таблицы.
В Solaris нет стандартных регулярно выполняемых скриптов, но можно создать их и расположить в каталоге /var/admin/cron/ или /etc/periodic/.
Примечание: Совместимость утилит
Возможности и ключи некоторых программ в системе расходятся со стандартом XPG4 (The X/Open Portability Guide, Issue 4), который описывает поведение и ключи программ, а также заголовки и интерфейсы. В случаях расхождения со спецификацией XPG4 версия программы под Solaris не изменяется, а совместимая с XPG4 программа с аналогичными функциями и таким же именем помещается в каталог /usr/xpg4/bin. Для выбора оригинальных или XPG-совместимых программ в переменной PATH первым указывается каталог с нужными программами. Оригинальные программы могут располагаться не только в /usr/bin, но и в /bin, /usr/ucb и /usr/ccs/bin.