Организация UNIX-систем и ОС Solaris 9

Управление процессами

Разбить на страницы
Показывать лекцию целиком

Замечание о совместимости утилит

Несмотря на то что Solaris удовлетворяет многочисленным стандартам, некоторые программы в системе (точнее, их возможности и ключи) расходятся со стандартом XPG4. Этот стандарт (The X/Open Portability Guide, Issue 4 - XPG4) представляет собой спецификацию, описывающую программы, заголовки и интерфейсы. В частности, описывается ожидаемое поведение ряда программ UNIX и их ключи.

Что находится в каталоге /usr/bin/xpg4

В тех случаях, когда поведение и ключи программ Solaris расходились со спецификацией XPG4, изначальная версия программы под Solaris не изменялась. вместо этого программа, совместимая с XPG4 с примерно такими же функциональными особенностями и точно таким же именем, помещалась в каталог /usr/xpg4/bin. Таким образом, для того, чтобы выбрать, какие программы - оригинальные или XPG4-совместимые вы предпочитаете использовать в своей системе, достаточно указать первым в переменной среды окружения PATH тот каталог, в котором лежат нужные вам "по умолчанию" программы. Если первым указан каталог /usr/bin, то при вызове команды по ее короткому имени, например, grep, а не по полному имени файла, например, /usr/xpg4/bin/grep, будет вызываться /usr/bin/grep - оригинальная программа. Если указать в PATH первым /usr/xpg4/bin, то будет запускаться XPG4-совместимая версия. Помните, что оригинальные программы могут располагаться также в /bin, /usr/ucb и /usr/ccs/bin.

Спецификация XPG4 включает в себя спецификации программ из IEEE Std 1003.2-1992 и IEEE Std 1003.2a-1992 (которые вместе носят название POSIX 2).

Иерархия процессов в Solaris

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

Само ядро Solaris представляет собой множество потоков (threads), которые выполняются параллельно. Действительно, у ядра много разных дел, было бы странно, если бы ядро пыталось все делать последовательно, а не параллельно. Термин threads часто переводят как "нить", но мы будем говорить в контексте управления процессами именно о "потоках", понимая под этим "потоки команд", в отличие от "потоков данных", которые будут рассмотрены ниже.

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

Solaris реализует многоуровневую поточную модель. Ее назначение - разделить управление потоками пользовательского уровня и работу ядра. Потоки пользовательского уровня имеют свою схему приоритетов. Их планирование проводится с помощью потока-планировщика. Такой поток создается библиотекой потоков, когда многопоточное приложение компилируется и выполняется. Внутри одного пользовательского процесса могут работать свои потоки, передача управления между которыми осуществляется внутренним планировщиком этого процесса. Благодаря этому многопоточные приложения могут порождать тысячи потоков без существенной загрузки ядра. Оно будет видеть это приложение как один процесс. По сути, ядро не видит пользовательские потоки, пока они не присоединяются к легковесному процессу (lightweight process, LWP), имеющему определенное положение в операционной системе. Поток-планировщик отвечает за отображение пользовательских потоков в легковесный процесс (LWP), который связан с потоком ядра для выполнения процессором. Каждый LWP имеет поток ядра, но необязательно каждый поток ядра имеет LWP. Часть потоков ядра задействованы исключительно операционной системой, поэтому LWP здесь не требуется.

Свойства процесса

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

(рис 7.1) Взаимоотношения процессов в многопотоковой архитектуре

Идентификаторы процесса

Процесс всегда имеет свой уникальный номер - PID (process ID). PID - это целое число в диапазоне допустимых целых чисел (для 32-разрядных систем - от 0 до 65535). Процесс с номером 0 - это обычно процесс свопинга, фактически являющийся частью кода ядра. Процесс с номером 1 - это всегда init, процесс, который порождает все остальные процессы в системе при ее старте. У всех процессов, кроме init, есть родительский процесс, и каждому процессу, кроме его собственного идентификатора PID, соответствует идентификатор родительского процесса (PPID - parent process ID).

В таблице процессов, кроме идентификаторов PID и PPID, хранятся eUID (effective UID - эффективный идентификатор пользователя) владельца процесса и eGID (effective GID - эффективный идентификатор группы) группы процесса. Фактические (реальные) владелец и группа процесса - это пользователь и группа, которые запустили процесс, а эффективные владелец и группа процесса - это те, от имени которых запущен процесс. Для определения прав доступа используются эффективные идентификаторы, а для задач управления процессом (например, посылки сигнала процессам, которые запустил определенный пользователь, см. описание команды pkill ниже) - реальные. Эти идентификаторы передаются по наследству от родительского процесса дочернему.

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

Любой процесс относится к какой-либо терминальной группе, т.е. группе процессов, запущеных с одного терминала. Терминал определяется параметром TTYID.

Процесс имеет базовый и динамический приоритеты, в зависимости от приоритета запросы процесса к системе выполняются медленнее или быстрее.

Получить полный список процессов в системе с выводом их идентификаторов и ряда других параметров можно с помощью команды ps -ef.

Приоритеты процесса

Во многих системах UNIX процесс имеет базовый приоритет ( NICE ) и динамический приоритет ( PRI ). Базовый приоритет может принимать значение от -20 до +20. Чем меньше числовое значение базового приоритета NICE, тем выше приоритет. Процесс с отрицательным приоритетом -20 - самый высокоприоритетный. Динамический приоритет вычисляется планировщиком задач на основе базового приоритета по формуле, в которую входит общее потребленное процессом процессорное время. Чтобы дать возможность выполняться новым и более коротким процессам, динамический приоритет снижается с увеличением потребленного процессом времени процессора.

В Solaris применяется более сложная схема планирования приоритетов процессов, которая описывается ниже. Для процессов одного из классов планирования (с разделением времени) справедлива вышеописанная простая схема из базового и динамического приоритетов.

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

Приоритет базируется на классе планирования (scheduling class); всего различают четыре класса планирования: с разделением времени (timesharing), системный (system), реального времени (real-time) и планирование на основе справедливого раздела (fair Class scheduling, FCS). У процессов разных классов планирования свои уровни приоритета и свои очереди на выполнение. Стало быть, в системе мы имеем четыре очереди к процессору. Внутри каждого класса процессы, стоящие в очереди, имеют свои уровни приоритета. Эти уровни отображаются в глобальные приоритеты планирования (global scheduling priorities). Первым процессор займет процесс, который имеет наивысший глобальный приоритет. По умолчанию, процесс из класса планирования с разделением времени имеет более низкий глобальный приоритет, чем процесс из системного класса, а тот, в свою очередь, более низкий, чем процесс реального времени.

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

Получить информацию о текущих классах планирования процессов можно с помощью команды dispadmin.

Среда окружения

Каждый процесс имеет свою среду окружения - специальную область, в которой хранятся имена переменных и их значения. Среда окружения используется для модификации поведения процесса ; так, в зависимости от значения переменной TERM текстовый редактор будет выдавать разные коды управления экраном, поскольку переменная TERM используется для задания типа терминала. Переменные среды окружения могут быть помечены как экспортируемые, это означает, что такую переменную дочерний процесс унаследует от процесса-родителя. Такие переменные, как TERM, PATH, USER обычно являются экспортируемыми. Из командной строки пометить переменную как экспортируемую можно с помощью команды export:

export TERM PATH

К переменным среды окружения легко обратиться из прикладной программы на языке С - для этого предусмотрен специальный массив строк:

char *env[]

Аргументы

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

char *argv[]

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

int argc

Классы планирования

В Solaris 9 есть шесть классов планирования: с разделением времени (timesharing, TS), интерактивный (interactive, IA), системный (system, SYS), реального времени (real-time, RT),с фиксированным приоритетом (fixed priority, FX) и планирование на основе справедливого раздела (fair share scheduling, FSS).

Соотношение глобальных и относительных приоритетов
Диапазон глобальных приоритетов Очередь планирования
159–100 Процессы реального времени (0-59)
99–60 Системные процессы
59–0 Приоритеты процессов с разделением времени (0-59)

По умолчанию процессы попадают в класс с разделением времени.

С помощью команды

ps -cl

можно узнать глобальные приоритеты запущенных в данный момент процессов, а "внутренние" приоритеты процессов в разных классах планирования - с помощью команды dispadmin.

Планирование процессов реального времени

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

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

В нестрогой среде реального времени период реакции должен иметь гарантированную конечную продолжительность (например, верхний предел времени, за которое приложение должно освободить процессор; в Solaris такой период составляет 5 миллисекунд).

В большинстве систем UNIX поддержки реального времени нет. Это связано с тем, что:

  • "промахи" обращения к памяти из-за отсутствия страниц в оперативной памяти могут вызвать непредсказуемую задержку вследствие необходимости подгрузить требуемую страницу в память из swap-раздела;
  • хотя ядро является выгружаемым (preemptable) - т.е. оно может быть смещено из процессора при запуске другого процесса, - в некоторых ситуациях все же не допускается выгрузка ядра из процессора, например, при обработке прерывания; элементы кода, которые не могут быть выгружены из процессора во время выполнения, называются "точками невыгружаемости" (nonpreemption points).
  • Решение первой из этих проблем в Solaris состоит в том, что все страницы процесса реального времени в памяти блокируются и их выгрузка на диск запрещается. Вторая проблема решается за счет того, что ядро Solaris - многопотоковое, обработчики прерываний реализованы как отдельные потоки, что делает возможным установить для них отдельный приоритет ; более того, в Solaris есть возможность priority lending - "одалживание приоритета ". Это означает, что когда более приоритетный процесс нуждается в результатах работы менее приоритетного процесса, он может "одолжить" последнему на время свой высокий приоритет для выполнения требуемой задачи.

    Диспетчер

    Когда поток готов к выполнению, он помещается в очередь отправки на выполнение. Каждый процессор (в многопроцессорной системе) имеет отдельный набор очередей отправки. Состояние ожидания в очереди отправки называется состоянием выполнения (RUN). Когда процессор освобождается, диспетчер берет поток с наивысшим приоритетом из очереди отправки этого процессора и помещает его в процессор. Теперь поток в состоянии "внутри процессора" (ONPROC) и может выполнять вычисления.

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

  • поток занимает процессор, пока не закончится отведенный ему период времени (определяемый приоритетом потока). Такой период называется квантом. Поскольку процессы с большим приоритетом выбираются чаще, то квант обычно обратно пропорционален приоритету ( процессы с более высоким приоритетом имеют меньшие кванты). Когда квант исчерпан, потоку присваивается приоритет нового уровня (значение tqexp ). Такой уровень почти всегда ниже приоритета потока при старте. Это сделано для обеспечения справедливости при планировании;
  • поток ждет завершения ввода-вывода или разблокировки нужного ему ресурса, тогда он переходит в состояние "сна" (SLEEP). Проснувшимся потокам назначается более высокий приоритет, чем у них был до сна, чтобы они могли "наверстать упущенное";
  • ядро прервало поток; если прерванный поток долго ожидает внимания процессора, то его приоритет повышается до значения lwait. Так потоки компенсируют ожидание в очереди после прерывания.
  • Проверка приоритета процесса

    Выяснить, с каким легковесным процессом ассоциирован конкретный процесс и какой класс планирования ему назначен, можно с помощью команды ps и ключей -L и :

    /usr/bin/ps -efcL
    
    UID	PID	PPID	LWP	NLWP	CLS	PRI	STIME	TTY	LTIME 	CMD
    root	0	0	1	1	SYS	96	00:23:03	?	0:03	sched
    root	1	0	1	1	TS	59	00:23:03	?	0:00	/etc/init -
    root	2	0	1	1	SYS	98	00:23:03	?	0:00	pageout
    root	3	0	1	1	SYS	60	00:23:03	?	0:00	fsflush
    root	314	1	1	1	TS	59	00:23:35	?	0:00	/usr/lib/saf/sac 
    											-t 300
    root	289	1	1	1	TS	59	00:23:32	?	0:00	/usr/lib/snmp/snmpdx
     										-y -c /etc/snmp/conf
    root	182	1	1	3	TS	59	00:23:22	?	0:00	/usr/lib/autofs
    										/automountd
    root	182	1	2	3	TS	59	00:23:23	?	0:00	/usr/lib/autofs
    										/automountd
    root	182	1	3	3	TS	59	00:25:23	?	0:00	/usr/lib/autofs
    										/automountd
    root	207	1	3	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	4	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	5	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	6	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	7	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	8	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	9	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	193	1	11	13	TS	59	00:23:24	?	0:00	/usr/sbin/syslogd
    root	193	1	12	13	TS	59	00:23:24	?	0:00	/usr/sbin/syslogd
    root	193	1	13	13	TS	59	00:23:26	?	0:00	/usr/sbin/syslogd
    root	439	419	1	1	IA	39	00:24:42	pts/4	0:00	bash

    Вывод этой команды здесь сильно сокращен: процессов в системе на самом деле всегда значительно больше. Сейчас нам интересны прежде всего колонки LWP, CLS и PRI, в которых показаны номер легковесного процесса, класс планирования и глобальный приоритет соответственно.

    Чем больше числовое значение глобального приоритета (значение PRI), тем выше глобальный приоритет процесса.

    Мы видим, что многопоточные процессы (например, демон автомонтирования /usr/lib/autofs/automountd и демон протоколирования /usr/sbin/syslogd ) могут одновременно иметь несколько LWP (в колонке NLWP указано количество LWP, с которыми ассоциирован процесс ).

    Настройка таблиц диспетчера

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

    Чтобы узнать, какие классы доступны для редактирования, следует запустить dispadmin с ключом -l и определить активные классы планирования:

    dispadmin -l
    CONFIGURED CLASSES ==================
    SYS			(System Class)
    TS			(Time Sharing)
    FX			(Fixed Priority)
    IA			(Interactive)
    RT			(Real Time)

    Далее выводим таблицу диспетчера для выбранного класса (попробуем это на классе планирования с разделением времени - TS ):

    dispadmin -c TS -g
    # Time Sharing Dispatcher Configuration
    RES=1000
    
    ts_quantum	ts_tqexp	ts_slpret	ts_maxwait	ts_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
    200	0	50	0	50	#	4
    200	0	50	0	50	#	5
    200	0	50	0	50	#	6
    200	0	50	0	50	#	7
    200	0	50	0	50	#	8
    200	0	50	0	50	#	9
    160	0	51	0	51	#	10
    160	1	51	0	51	#	11
    160	2	51	0	51	#	12
    160	3	51	0	51	#	13
    160	4	51	0	51	#	14
    160	5	51	0	51	#	15
    160	6	51	0	51	#	16
    160	7	51	0	51	#	17
    160	8	51	0	51	#	18
    160	9	51	0	51	#	19
    120	10	52	0	52	#	20
    120	11	52	0	52	#	21
    120	12	52	0	52	#	22
    120	13	52	0	52	#	23
    120	14	52	0	52	#	24
    120	15	52	0	52	#	25
    120	16	52	0	52	#	26
    120	17	52	0	52	#	27
    120	18	52	0	52	#	28
    120	19	52	0	52	#	29
    80	20	53	0	53	#	30
    80	21	53	0	53	#	31
    80	22	53	0	53	#	32
    80	23	53	0	53	#	33
    80	24	53	0	53	#	34
    80	25	54	0	54	#	35
    80	26	54	0	54	#	36
    80	27	54	0	54	#	37
    80	28	54	0	54	#	38
    80	29	54	0	54	#	39
    40	30	55	0	55	#	40
    40	31	55	0	55	#	41
    40	32	55	0	55	#	42
    40	33	55	0	55	#	43
    40	34	55	0	55	#	44
    40	35	56	0	56	#	45
    40	36	57	0	57	#	46
    40	37	58	0	58	#	47
    40	38	58	0	58	#	48
    40	39	58	0	59	#	49
    40	40	58	0	59	#	50
    40	41	58	0	59	#	51
    40	42	58	0	59	#	52
    40	43	58	0	59	#	53
    40	44	58	0	59	#	54
    40	45	58	0	59	#	55
    40	46	58	0	59	#	56
    40	47	58	0	59	#	57
    40	48	58	0	59	#	58
    20	49	59	32000	59	#	59

    Первая строка, в которой указано значение RES, определяет, в чем измеряется время во всей таблице приоритетов данного класса. Величина RES фактически задает дискретность измерения времени для столбца ts_quantum таблицы диспетчера. Ее значение по умолчанию - 1000. Изменять дискретность не рекомендуется. Обратная к RES величина равна 0,001, и это интерпретируется как одна тысячная секунды, т.е. одна миллисекунда. Стало быть, по умолчанию время в столбце ts_quantum измеряется в миллисекундах.

    Как было показано в разделе "Диспетчер" выше, смысл значений, приведенных в столбцах таблицы диспетчера, следующий:

  • ts_quantum представляет собой максимальный период времени (квант), в течение которого поток может оставаться в процессоре до того, как диспетчер изменит его приоритет ;
  • ts_tqexp задает приоритет, который будет назначен потоку после того, как истечет его квант времени и он будет удален из процессора;
  • ts_slpret указывает приоритет, который будет иметь процесс, когда он будет обрабатываться после "сна", т.е. после ожидания завершения ввода-вывода или когда он дождется снятия блокировки с требуемого ему ресурса;
  • ts_maxwait указывает время в секундах, которое процесс будет оставаться в очереди, в случае, если его квант времени еще не истек; если он не использует свой квант времени в течение этого числа секунд, ему будет присвоен новый приоритет ts_lswait. Если ts_maxwait равно нулю, то принимается значение по умолчанию (одна секунда);
  • ts_lswait обозначает присваиваемый процессу приоритет, когда процесс на долгое время был вытеснен из процессора.
  • В таблицах диспетчера указываются относительные приоритеты (которые имеют силу внутри класса планирования ). Глобальный (иначе говоря - абсолютный) приоритет вычисляется из относительного в соответствии с табл. 7.1.

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

    Посмотрим, как работает эта схема динамического назначения приоритетов. Предположим, процесс начал выполняться с приоритетом 0. Подождав, пока ему дадут управление в течение одной секунды ( ts_maxwait ), процесс получил новый приоритет 50 ( ts_lwait ).

    Вместе с новым приоритетом процесс обрел новое значение кванта (меньшее, так как чем выше приоритет, тем меньше квант, чтобы высокоприоритетные задачи не забивали процессор). Вместо прежних 200 миллисекунд процесс получил квант в 40 миллисекунд. Зато с этим приоритетом процесс получил возможность вытеснять из процессора менее приоритетные процессы.

    Если процесс продолжает постоянно использовать процессорное время, не отвлекаясь на ввод-вывод (например, это вычислительный процесс программы моделирования полета ракеты), то по истечении кванта времени он получит новый приоритет 40 ( ts_tqexp ).

    Дальнейшие назначения приоритетов показаны ниже:

    приоритет квант
    40 40
    30 80
    20 120
    10 160
    0 200
    50 40
    40 40
    30 80
    и т.д. и т.д.

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

    Класс реального времени ( RT ) описывается более простой таблицей диспетчера:

    # Real Time Dispatcher Configuration RES=1000
    TIME QUANTUM(rt_quantum)        PRIORITY LEVEL
    1000                       #    0
    1000                       #    1
    1000                       #    2
    1000                       #    3
    1000                       #    4
    1000                       #    5
    1000                       #    6
    1000                       #    7
    1000                       #    8
    1000                       #    9
    800                        #    10
    800                        #    11
    800                        #    12
    800                        #    13
    800                        #    14
    800                        #    15
    800                        #    16
    800                        #    17
    800                        #    18
    800                        #    19
    600                        #    20
    600                        #    21
    600                        #    22
    600                        #    23
    600                        #    24
    600                        #    25
    600                        #    26
    600                        #    27
    600                        #    28
    600                        #    29
    400                        #    30
    400                        #    31
    400                        #    32
    400                        #    33
    400                        #    34
    400                        #    35
    400                        #    36
    400                        #    37
    400                        #    38
    400                        #    39
    200                        #    40
    200                        #    41
    200                        #    42
    200                        #    43
    200                        #    44
    200                        #    45
    200                        #    46
    200                        #    47
    200                        #    48
    200                        #    49
    100                        #    50
    100                        #    51
    100                        #    52
    100                        #    53
    100                        #    54
    100                        #    55
    100                        #    56
    100                        #    57
    100                        #    58
    100                        #    59

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

    Планирование на основе справедливого раздела

    В Solaris стандартный планировщик задач (диспетчер) старается предоставить процессам, которые по умолчанию запускаются с классом планирования timesharing (в режиме с разделением времени), примерно одинаковый доступ к процессору. Однако, если на самом деле некоторые процессы в системе более важны, чем другие (сервер баз данных, web-сервер крупного портала и т.п.), можно использовать иной метод планирования - планирование на основе справедливого раздела (fair share scheduler - FSS). В этом случае можно назначить группам процессов разные "порции" процессорного времени, которые те будут получать в единицу времени. Грубо говоря, можно потребовать от планировщика отдать 70% времени web-серверу, а 30% - всем остальным процессам. Если этого не сделать, время будет делиться поровну. Кроме соответствующего алгоритма, в Solaris 9 появился новый класс планирования, который тоже называется планированием на основе справедливого раздела.

    В более ранних версиях Solaris этот алгоритм планирования (и соответствующий ему класс) отсутствовал, хотя в других системах аналогичный алгоритм был реализован в середине 1990-х годов, например, в IRIX 6.2.

    Более детальное описание этой возможности дано по адресу http://docs.sun.com/db/doc/816-4882/6mb2ipq5n?q=scheduling+classa=view

    Распределение памяти. Swaping

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

    В UNIX вся память разделена на страницы определенного одинакового размера. Каждый процесс получает от системы запрошенное количество памяти, выделение памяти в UNIX осуществляется постранично. Процессы реального времени и часть кода ядра (например, та, что отвечает за обмен страницами между оперативной памятью и диском) всегда находятся в памяти, страницы остальных процессов могут быть выгружены на диск. В большинстве систем UNIX размер страницы составляет 4 Кбайт. В Solaris для x86 он ровно такой же, но на платформе SPARC может быть другой размер страницы, т.к. это свойство системы зависит от платформы. Узнать размер страницы памяти в Solaris можно по команде pagesize.

    Традиционно в литературе по системам UNIX для описания процесса обмена страницами между памятью и диском используют термин "свопинг" (swaping). Этот термин в действительности означает полную выгрузку страниц процесса на диск. На самом деле менеджер виртуальной памяти в UNIX обычно выполняет "пейджинг" (paging), что означает постраничную (частичную) выгрузку процесса на диск. Свопинг выполняется в том случае, если памяти критически не хватает, чего при нормальной работе системы не наблюдается.

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

    Более подробно алгоритм работы менеджера виртуальной памяти рассмотрен в лекции 7 курса "Администрирование ОС Solaris".

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

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

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

    Доступ процессов к файлам

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

    То, какие права доступа к файлу получит процесс, зависит от эффективных идентификатора владельца (eUID ) и группы (eGID) этого процесса. При обращении процесса к файлу ядро проверяет, кем по отношению к этому файлу является владелец процесса. Если эффективный идентификатор владельца процесса совпадает с идентификатором владельца файла, то процесс получает права доступа к файлу, определенные для владельца файла. Если владелец процесса входит в группу файла, но не является владельцем файла, он получает права, определенные для группы файла. Если не имеет место ни то, ни другое, то процесс получает права доступа к файлу, определенные для "всех остальных".

    Новый файл по умолчанию получает идентификаторы владельца и группы по наследству от процесса, который его создал, а права доступа к нему - по умолчанию - исходя из маски прав доступа umask.

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

    Запуск приложения от имени владельца файла приложения

    Обычно эффективные идентификаторы владельца и группы процесса достаются процессу по наследству от процесса-родителя. Но в некоторых ситуациях необходимо запустить программу с правами, большими, нежели права запускающего ее пользователя. Например, вам надо изменить свой пароль. Для этого требуется осуществить запись в файл /etc/shadow. С другой стороны, нельзя давать каждому пользователю такое право: вдруг он поменяет не только свой пароль? Кто откажется сделать милый сюрприз коллеге? Как быть? Если вы подумали, что выход в том, чтобы все пароли менял только администратор, вы далеки от истины.

    Идея в том, чтобы право записи в /etc/shadow дать не конкретному пользователю, а программе passwd (как нам известно, пароль меняет именно эта программа). К сожалению, в UNIX нет механизма, который позволяет давать какие-либо права отдельному процессу или приложению. Поэтому право записи в /etc/shadow дали пользователю root (назначив его владельцем этого файла и разрешив запись в файл владельцу - вы помните, как это сделать с помощью chmod?), а программу passwd разрешили всем запускать от имени ее владельца - root.

    Это право (запускать программу от имени владельца) является специальным правом доступа к файлу, оно называется SUID (set User ID). Фактически, файл с установленным битом SUID, отвечающим за это право доступа, всегда запускается на выполнение с эффективным идентификатором владельца процесса, равным идентификатору владельца файла.

    Как мы помним, полный вид слова прав доступа таков:

    su sg  t   r  w  x  r   w  x  r   w  x

    Старшие три бита - SUID ( su ), SGID ( sg ) и sticky bit ( t ).

    Suid и Sgid

    Установить бит suid или sgid можно, указав chmod права доступа в числовом виде:

    chmod 4755 файл

    или в мнемоническом виде:

    chmod u+s файл

    В некоторых системах UNIX доступна только одна из этих двух форм.

    Бит установки эффективного группового идентификатора (SGID) при запуске файла на выполнение действует сходным с SUID образом: как и в случае бита SUID, установленный SGID вызывает присвоение процессу, исполняемый код которого содержится в запущенном файле, эффективного идентификатора группы, равного идентификатору группы этого файла.

    В выводе команды ls файлы с установленными битами SUID и SGID отличаются от прочих тем, что в поле, где обычно стоит "x" (бит выполняемости), оказывается символ "s":

    -r-xr-sr-x 1 roottty 10040 Nov 4 2002 /usr/sbin/wall
    -r-sr-sr-x 1 rootsys 22168 Nov 4 2002 /usr/bin/passwd

    Это означает, что присутствуют оба бита: и бит запускаемости, и бит SUID (или SGID, соответственно). Если попытаться установить бит SUID или SGID на файл, для которого в соответствующем праве доступа (владельца или группы) не будет бита запускаемости, то система не даст это сделать. Поскольку для каталога биты SUID и SGID имеют другое значение, то биты SUID/SGID и биты права поиска в каталоге могут быть установлены по отдельности. В выводе ls в правах доступа к каталогу при отсутствии права поиска и наличии битов SUID/SGID буква S в выводе прав доступа будет заглавной:

    dr-Sr-xr-x  2  root  other  512  May  10  01:48  enum
    -rw-r--r--  1  root  other  0    May  10  01:47  q

    Обратите внимание на права доступа к каталогу enum. Объяснение смысла SUID/SGID для каталога дано в лекции 6.

    Найти все файлы, у которых установлен бит SUID, можно с помощью команды

    find / -perm -u+s

    а файлы с установленным битом SGID - по команде

    find / -perm -g+s

    Чтобы не допустить взлома системы, относитесь внимательно к файлам, права доступа к которым разрешают запускать их от чужого имени. Появление таких файлов в системе может облегчить жизнь взломщику. Программа passwd, например, написана таким образом, что запускающий ее пользователь не сможет с ее помощью сделать ничего, кроме изменения собственного пароля. Поэтому ей можно доверить запускаться с правами пользователя root. Но где гарантия, что все остальные программы с установленным SUID такие же? Устанавливайте бит SUID только тем программам, которым доверяете на все сто!

    Появление новых файлов с <подозрительными> правами доступа может говорить о попытке взлома системы, поэтому при инсталляции некоторых ОС автоматически устанавливается простой сценарий, использующий вышеописанную команду поиска таких файлов для отслеживания добавленных за последние сутки файлов с установленным битом SUID. Например, во FreeBSD это делается в сценарии /etc/daily, ежедневно проверяющем состояние системы.

    Имеет смысл удостовериться в том, что все эти новые файлы появились по известной вам причине.

    Интерактивные и фоновые процессы

    Процесс в UNIX может быть интерактивным и фоновым. Процесс, который имеет доступ к вводу с терминала и к выводу на него, называется интерактивным (foreground). Таким процессом является почтовая программа mail, редактор текста vi и другие программы. Фоновый процесс не имеет доступа к вводу с терминала, и имеет условный доступ к выводу на терминал. Условие состоит в том, что вывод на терминал разрешен фоновому процессу, если терминал настроен для работы в режиме tostop . Эту настройку можно выполнить командой

    stty -tostop

    Обратная настройка выполняется командой

    stty tostop

    Если фоновый процесс пытается выводить что-либо на терминал, настроенный для работы в режиме tostop, то процессу посылается сигнал SIGSTOP. Процесс, получивший такой сигнал, останавливается (переводится в состояние STOPPED ).

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

    Для запуска фонового процесса из командного интерпретатора следует дать команду, завершив ее знаком "" (амперсэнд):

    команда 

    Можно запустить сборку пакета программ в фоновом режиме, и пока он собирается, выполнять другую работу:

    make all 

    Взаимодействие процессов

    Процессы взаимодействуют друг с другом, используя при этом разные механизмы. Процессы могут асинхронно или синхронно передавать друг другу данные и управление доступом к ресурсам системы.

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

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

    Перенаправление потоков

    Поток данных, связанный с процессом, может быть перенаправлен в файл или другой поток данных. Например, если требуется, чтобы программа find выдала список имен файлов в файл names, а не на терминал, следует выполнить команду

    find / -name "some_name" > names

    Символ правой угловой скобки > означает перенаправление выходного потока запущенной программы в файл. При использовании этой конструкции будет создан файл names ; если файл с таким именем уже существует, то он будет уничтожен и затем будет создан новый файл с этим именем и новым содержимым.

    Для добавления вывода программы в конец файла следует использовать конструкцию "две правые угловые скобки" >>

    find / -name "some_name" >> names

    В этом случае файл names будет создан, если он не существует, а если существует, выходной поток программы find добавится в конец файла.

    Можно перенаправить текст из файла во входной поток.

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

    mail пользователь@компьютер < файл_с_письмом

    Бывает необходимо отправить пользователям не совершенно одинаковые сообщения, а письма, в которых стандартный текст перемешан с личными обращениями и конкретными подробностями. Тогда на помощь приходит перенаправление потока посредством конструкции "документ здесь".

    Это дает возможность перенаправить ввод в процесс не из файла, а прямо из командной строки (или тела скрипта):

    mail пользователь@компьютер <<FINAL
    Дорогой(ая) $TARGETUSER,
    Вы превысили допустимый размер домашнего каталога на 
    $OVERSIZE килобайт. Удалите ненужные Вам файлы, 
    иначе это сделает робот!
    	Системный администратор
    FINAL

    Такой скрипт отправит по указанному адресу письмо, в котором вместо $TARGETUSER и $OVERSIZE будут подставлены имя и превышение лимита того пользователя, которому предназначается письмо. Естественно, этим переменным следует присвоить какое-то значение перед выполнением команды, но тот фрагмент скрипта, в котором это делается, вы с легкостью додумаете самостоятельно.

    Указание в тексте значков << показывает, что все, что следует непосредственно за ними до ближайшего символа-разделителя, является ограничителем текста. Символ-разделитель - это любой пустой символ: пробел, табуляция или конец строки. Все, что идет за ограничителем текста, передается во входной поток запущенного командой процесса вплоть до момента, когда в начале новой строки не встретится такой же ограничитель текста. Ограничитель может представлять собой любой набор непустых символов - неважно, просто ли это символ "точка", слово FINAL или что-то еще.

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

    ls -l | more

    Символ вертикальной черты "|" означает перенаправление выходного потока программы, команда вызова которой находится слева от этого символа, во входной поток программы, вызываемой справа.

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

    Например, для подсчета запущенных демонов httpd можно использовать такую конструкцию:

    ps -auxw | grep httpd | wc -l

    Программа ps выводит список всех процессов, запущенных в системе, grep выбирает из этого списка строки, в которых есть подстрока httpd, а wc с ключом l подсчитывает, сколько строк оказалось в ее входном потоке.

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

    Сигналы

    Процессы могут взаимодействовать, посылая друг другу сигналы. Список сигналов в Solaris ограничен сорока двумя сигналами, из которых наиболее употребительны сигналы TERM, KILL и HUP. В разных вариантах UNIX может быть разное количество сигналов, стандарт POSIX 1.1 определяет тридцать один сигнал. Каждый сигнал имеет свое мнемоническое обозначение и номер. В разных системах мнемонические обозначения остаются одинаковыми, а номер может быть разным.

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

    С помощью команды

    kill

    можно послать сигнал с номером номер_сигнала процессу с идентификатором PID:

    kill -номер_сигнала PID

    В некоторых системах UNIX есть возможность послать сигнал процессу с определенным именем посредством программы killall:

    killall -номер_сигнала имя_процесса

    В Solaris эта программа имеет другое значение, а именно выполняет отправку сигнала завершения всем активным процессам:

    killall

    А отправить сигнал процессам с определенным именем в Solaris следует командой pkill:

    pkill sendmail

    С помощью pkill можно отправлять сигнал завершения TERM процессу с тем или иным признаком, так что отправка сигнала процессу с определенным именем - не единственное умение pkill. Например,

    pkill -HUP -G other,daemon

    отправит сигнал HUP (SIGHUP) всем процессам, чья фактическая группа - other или daemon.

    В табл. 7.2 приведен список сигналов, определенный стандартом POSIX 1.1, а в табл. 7.3 - список сигналов, определенных в Solaris 9.

    Кроме команды pkill системный администратор может найти удобной команду pgrep, которая заменяет конструкцию

    ps -ef | grep команда

    В Solaris для получения того же результата можно ввести более короткую команду

    pgrep команда
    Сигналы POSIX 1.1
    Сигнал НомерЗначение
    SIGHUP 1 Разрыв связи с управляющим терминалом или управляющим процессом
    SIGINT 2 Прерывание с клавиатуры
    SIGQUIT 3 Сигнал выхода дан с клавиатуры
    SIGILL 4 Недопустимая инструкция
    SIGABRT 6 Сигнал abort получен от вызванной кем-то функции abort
    SIGFPE 8 exception: ошибка вычислений с плавающей запятой
    SIGKILL 9 Безусловное завершение процесса
    SIGSEGV 11 Неверный адрес памяти
    SIGPIPE 13 Запись в несуществующий канал
    SIGALRM 14 Сигнал timer от функции alarm
    SIGTERM 15 Завершение
    SIGUSR1 30,10,16первое значение для архитектур alpha и sparc, второе — для i386, третье — для mips. Определяется пользователем
    SIGUSR2 31,12,17 Определяется пользователем
    SIGCHLD2 20,17,18 Дочерний процесс остановлен или принудительно завершен
    SIGCONT1 19,18,25 Продолжить выполнение, если оно было остановлено
    SIGSTOP 17,19,23 Остановить процесс
    SIGTSTP 18,20,24 Останов введен с терминала
    SIGTTIN 21,21,26 Ввод с терминала для фонового процесса
    SIGTTOU 22,22,27 Вывод на терминала для фонового процесса
    Сигналы Solaris 9
    НазваниеЗнач.Действие поСобытие
    SIGHUP 1 завершение разрыв связи с терминалом
    SIGINT 2 завершение прерывание
    SIGQUIT 3 аварийное завершение (core) Quit (требование завершения)
    SIGILL 4 аварийное завершение (core) недопустимая команда процессора
    SIGTRAP 5 аварийное завершение (core) прерывание при трассировке или точка останова
    SIGABRT 6 аварийное завершение (core) аварийное принудительное завершение
    SIGEMT 7 аварийное завершение (core) прерывание эмуляции
    SIGFPE 8 аварийное завершение (core) arithmetic exception: ошибка вычислений с плавающей запятой
    SIGKILL 9 безусловное завершение требование безусловного завершения
    SIGBUS 10 аварийное завершение (core) ошибка шины
    SIGSEGV 11 аварийное завершение (core) ошибка сегментации (выход за пределы выделенной памяти)
    SIGSYS 12 аварийное завершение (core) неверный системный вызов
    SIGPIPE 13 завершение запись в несуществующий канал
    SIGALRM 14 завершение Сигнал timer от функции alarm
    SIGTERM 15 завершение завершение
    SIGUSR1 16 завершение программируемый сигнал 1
    SIGUSR2 17 завершение программируемый сигнал 2
    SIGCHLD 18 действия не выполняются изменение статуса дочернего процесса
    SIGPWR 19 действия не выполняются сбой питания или перезагрузка
    SIGWINCH 20 действия не выполняются изменение размера окна
    SIGURG 21 действия не выполняются состояние сокета (Urgent Socket Condition)
    SIGPOLL 22 завершение Pollable Event (см. streamio (7I) )
    SIGSTOP 23 остановка требование остановки
    SIGTSTP 24 остановка остановка ввода с терминала
    SIGCONT 25 действия не выполняются требование продолжения
    SIGTTIN 26 остановка ввода ввод с терминала для фонового процесса
    SIGTTOU 27 остановка вывода вывод на терминал для фонового процесса
    SIGVTALRM 28 завершение Virtual Timer Expired
    SIGPROF 29 завершение Profiling Timer Expired
    SIGXCPU 30 аварийное завершение (core) достижение лимита времени использования процессора (CPU time limit exceeded)
    SIGXFSZ 31 аварийное завершение (core) превышение допустимого размера файла – getrlimit (см. getrlimit (2) )
    SIGWAITING 32 действия не выполняются зарезервировано библиотекой потоков
    SIGLWP 33 действия не выполняются межпроцессный (LWP) сигнал – зарезервировано библиотекой потоков
    SIGFREEZE 34 действия не выполняются Check point Freeze
    SIGTHAW 35 действия не выполняются Check point Thaw
    SIGCANCEL 36 действия не выполняются сигнал отмены, зарезервировано библиотекой потоков
    SIGXRES 37 действия не выполняются выход за границу блока управления ресурсом
    SIGRTMIN * завершение первый сигнал реального времени
    (SIGRTMIN+1) * завершение второй сигнал реального времени
    (SIGRTMAX-1) * завершение предпоследний сигнал реального времени
    SIGRTMAX * завершение последний сигнал реального времени

    Каналы и сокеты

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

    Канал - это последовательность байт, используемая как однонаправленный поток ввода/вывода.

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

    Сокет - это объект, который используется для межпроцессных коммуникаций; он существует, пока какой-либо процесс хранит дескриптор, ссылающийся на него. Сокет создается системным вызовом socket, который возвращает его дескриптор. Имеется несколько типов сокетов, которые поддерживают различные возможности передачи данных.

    Для каждого процесса ядро хранит таблицу внутренних дескрипторов. По-английски эта таблица называется "descriptor table", и чтобы не путать ее с таблицей дескрипторов в файловой системе, мы называем внутреннюю таблицу дескрипторов, относящуюся к конкретному процессу, "таблицей внутренних дескрипторов". Слово "внутренних" подчеркивает то, что эти дескрипторы существуют только в пределах процесса, который пользуется ими для обращения к файлам. Эта таблица наследуется от родительского процесса, поэтому вместе с ней наследуется и доступ к объектам, на которые ссылаются дескрипторы (файлам, каналам, сокетам).

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

    Подробнее о сокетах можно прочесть в Как вы помните, такая запись означает, что следует обратиться к странице руководства в третьем разделе, т.е. дать команду man 3 socket ..

    Семафоры

    Семафоры - это механизм, который принято использовать для контроля доступа нескольких процессов к одному ресурсу. Есть несколько реализаций программного интерфейса (API), связанного с семафорами:

  • вариант System V IPC (inter-process communication);
  • BSD;
  • POSIX 1003.1b.
  • Семафор по сути - это переменная, в зависимости от значения которой доступ к тому или иному ресурсу разрешается или блокируется до его освобождения. Семафоры широко используются в Oracle. Чтобы настроить подсистему семафоров в Solaris (обеспечить достаточное количество семафоров в ядре), может потребоваться внести изменения в файл конфигурации ядра /etc/system. Для уточнения того, какие настройки требуются именно вашему программному обеспечению под Solaris, обратитесь к руководству по этому ПО.

    Для Oracle8i в Oracle8i Installation Guide Release 3 рекомендуются следующие начальные значения параметров:

  • set semsys:seminfo_semmni=100
  • set semsys:seminfo_semmsl=<10 + самое большое значение PROCESSES среди ваших БД>
  • set semsys:seminfo_semmns=<столько, сколько объяснено ниже>
  • set semsys:seminfo_semopm=100
  • set semsys:seminfo_semvmx=32767
  • Значение seminfo_semmns рекомендуется установить равным сумме параметров PROCESSES всех баз данных сервера, причем самый большой из них должен быть просуммирован с коэффициентом 2, плюс еще 10 на каждую базу данных.

    Узнать текущие значения параметров семафоров (Solaris) можно с помощью команды:

    sysdef | tail -25

    Текущие наборы семафоров в системе (Solaris) покажет команда:

    ipcs -sb

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

    ipcrm -s semsetID

    semsetID здесь означает идентификатор набора семафоров.

    Управление процессами

    Команды наблюдения за процессами

    Для просмотра текущего списка и состояния процессов следует использовать программу ps. Она выдает "мгновенный снимок" таблицы процессов, которые запущены в системе.

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

    ps -ef

    В системах BSD и System V программа ps имеет разные ключи, поэтому если вы переходите от одной системы к другой, надо помнить об этих различиях или обращаться к man ps.

    Разберем подробнее, какую информацию выдает программа ps:

    ps -ef | more
    UID	PID	PPID	C	STIME	TTY	TIME	CMD
    root	0	0	0	17:43:30	?	0:03	sched
    root	1	0	0	17:43:30	?	0:00	/etc/init -s
    root	2	0	0	17:43:30	?	0:00	pageout
    root	3	0	0	17:43:30	?	0:00	fsflush
    root	349	1	0	17:43:53	?	0:00	/usr/lib/saf/sac -t 300
    root	277	276	0	17:43:49	?	0:00	htt_server -port 9010 -syslog -message_locale C
    root	180	1	0	17:43:45	?	0:00	/usr/lib/autofs/automountd
    root	59	1	0	17:43:39	?	0:00	/usr/lib/sysevent/syseventd
    root	73	1	0	17:43:40	?	0:00	/usr/lib/picl/picld
    root	133	1	0	17:43:43	?	0:00	/usr/sbin/rpcbind
    root	229	1	0	17:43:48	?	0:00	/usr/lib/power/powerd
    root	172	1	0	17:43:44	?	0:00	/usr/lib/nfs/lockd
    root	156	1	0	17:43:44	?	0:00	/usr/sbin/inetd -s
    root	217	1	0	17:43:47	?	0:00	/usr/lib/lpsched
    daemon	168	1	0	17:43:44	?	0:00	/usr/lib/nfs/statd
    root	189	1	0	17:43:45	?	0:00	/usr/sbin/syslogd
    root	203	1	0	17:43:46	?	0:00	/usr/sbin/cron
    root	205	1	0	17:43:46	?	0:00	/usr/sbin/nscd
    root	343	1	0	17:43:53	?	0:00	/usr/sbin/vold
    root	240	1	0	17:43:48	?	0:00	/usr/lib/utmpd
    root	324	1	0	17:43:51	?	0:00	/usr/lib/snmp/snmpdx -y -c /etc/snmp/conf
    root	261	1	0	17:43:49	?	0:00	/usr/sadm/lib/smc/bin/smcboot
    root	355	329	0	17:43:56	?	0:00	/usr/dt/bin/dtlogin -daemon
    root	329	1	0	17:43:52	?	0:00	/usr/dt/bin/dtlogin -daemon
    root	262	261	0	17:43:49	?	0:00	/usr/sadm/lib/smc/bin/smcboot
    root	263	261	0	17:43:49	?	0:00	/usr/sadm/lib/smc/bin/smcboot
    root	354	1	0	17:43:55	?	0:00	/usr/lib/ssh/sshd
    root	338	1	0	17:43:52	?	0:00	/usr/lib/dmi/snmpXdmid -s sunny
    root	352	349	0	17:43:53	?	0:00	/usr/lib/saf/ttymon
    root	353	329	2	17:43:54	?	1:41	/usr/openwin/bin/Xsun :0 -nobanner -auth /var/dt/A:0-KtaiPa
    root	356	329	0	17:43:56	?	0:00	/usr/openwin/bin/fbconsole -d :0
    root	358	324	0	17:43:57	?	0:00	mibiisa -r -p 5248
    root	337	1	0	17:43:52	?	0:00	/usr/lib/dmi/dmispd

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

    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, точнее - см. команду pagesize.

    WCHAN - адрес события, ради которого процесс перешел в состояние сна; если поле пусто, процесс запущен.

    STIME - время запуска процесса, в часах, минутах и секундах, для запущенных более суток назад процессов указываются месяцы и дни.

    TTY - управляющий терминал (то же, что и терминальная группа), символ вопросительного знака "?" печатается для процесса без управляющего терминала.

    TIME - число минут и секунд, указывающее, сколько времени процесс отнял у процессора.

    CMD - команда, которой был запущен процесс.

    При указании ключа j выводятся дополнительные сведения:

    PGID - идентификатор лидера группы процессов.

    SID - идентификатор процесса - лидера сессии.

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

    LWP - идентификатор легковесного процесса.

    NLWP - число легковесных процессов для процесса.

    Завершившиеся процессы, код завершения которых не был востребован родительским процессом, помечаются как "defunct".

    Кроме программы ps в UNIX для получения информации о запущенных в данный момент процессах широко используется команда top:

    top
    last pid: 923; load averages: 4.56, 1.18, 0.50    17:54:22
    64 processes: 63 sleeping, 1 on cpu
    CPU states: 0.0% idle, 0.5% user, 99.5% kernel, 0.0% iowait, 0.0% swap
    Memory: 128M real, 18M free, 101M swap in use, 499M swap free
    
    PID	USERNAME	LWP	PRI	NICE	SIZE	RES	STATE	TIME	CPU 	COMMAND
    909	root 		1 	60 	0 	17M 	3340K 	sleep 	0:00 	0.92% 	pagein
    353	root		1	58	0	32M	16M	sleep	0:05	0.37% 	Xsun
    893	root 		1	49	0	2228K	1172K	cpu	0:00	0.15%	top
    753	root 		1 	49	0 	15M 	8112K 	sleep  	0:00 	0.13% 	dtterm
    911	root 		1 	59	0 	3352K 	752K 	sleep  	0:00 	0.03% 	sh
    912	root 		1 	49	0 	3360K 	600K 	sleep  	0:00 	0.03% 	sh
    894	root 		1 	59	0 	3064K 	1816K 	sleep  	0:00 	0.03% 	dtexec
    656	root 		5 	59	0 	22M  	10M 	sleep  	0:01 	0.02% 	dtwm
    648	root 		1 	59	0 	6644K 	2280K 	sleep  	0:00 	0.02% 	ttsession
    667	root 		1 	59	0 	1844K 	512K 	sleep  	0:00 	0.02% 	rpc.rstatd
    277	root 		29	59	0 	5612K 	1724K 	sleep  	0:00 	0.01% 	htt_server
    895	root 		1 	59	0 	3360K 	756K 	sleep  	0:00 	0.01% 	soffice
    720	root 		4 	49	0 	42M  	26M 	sleep  	0:03 	0.00% 	mozilla-bin
    649	root 		1 	49	0 	18M 	6288K 	sleep  	0:00 	0.00% 	dtsession
    760	root 		1 	49	0 	4752K 	1656K 	sleep  	0:00 	0.00% 	bash

    В Solaris для удобства получения информации о процессах с определенными именами есть команда

    pgrep имя

    Она является эквивалентом команды

    ps -ef | grep имя

    С помощью pargs можно посмотреть, какие аргументы переданы конкретному процессу и какая у него среда окружения:

    pargs 2793
    2793:  dtterm -name Run -xrm *menuBar: False -iconic -map 
    -e /usr/dt/bin/dtexec -open 
    argv[0]: dtterm
    argv[1]: -e
    argv[2]: /usr/dt/bin/dtexec
    argv[3]: -open
    argv[4]: -1
    argv[5]: -ttprocid
    argv[6]: 2.10fX-r 01 648 1289637086 1 1 0 192.168.5.33 5 
    sunny_105_1
    argv[7]: /export/home/mozilla_bin/sfw/bin/mozilla
    argv[8]: <NULL>
    argv[9]: -open
    argv[10]: -1
    argv[11]: -ttprocid
    argv[12]: 2.10fX-r 01 648 1289637086 1 1 0 192.168.5.33 5 
    sunny_105_1
    argv[13]: /export/home/mozilla_bin/sfw/bin/mozilla
    
    pargs -e 2793
    2793:  dtterm -name Run -xrm *menuBar: False -iconic -map -e /usr/dt/bin/dtexec -open 
    envp[0]: AB_CARDCATALOG=/usr/dt/share/answerbooks/ru_RU.UTF-8/ab_cardcatalog
    envp[1]: DISPLAY=:0.0
    envp[2]: DTAPPSEARCHPATH=//.dt/appmanager:/etc/dt/appconfig/appmanager/%L:/etc/dt/appconfig/appmanager/C:/usr/dt/appconfig/appmanager/%L:/usr/dt/appconfig/appmanager/C
    envp[3]: DTDATABASESEARCHPATH=//.dt/types,/etc/dt/appconfig/types/%L,/etc/dt/appconfig/types/C,/usr/dt/appconfig/types/%L,/usr/dt/appconfig/types/C

    Вывод команды pargs значительно сокращен, ключ -e требует вывести все содержимое среды окружения, а для графических программ типа dtterm, как в нашем примере, среда окружения весьма велика.

    Команда prstat позволяет в динамике, подобно команде top, отслеживать состояние процессов:

    prstat
    PID	USERNAME	SIZE	RSS	STATE	PRI	NICE	TIME	CPU	PROCESS/NLWP
    3576	root	3412K	868K	run	13	0	0:00:02	6,3%	find/1
    353	root	45M	19M	sleep	59	0	0:02:30	0,2%	Xsun/1
    753	root	15M	3620K	run	49	0	0:00:02	0,1%	dtterm/1
    3577	root	6640K	4108K	cpu0	49	0	0:00:00	0,1%	prstat/1
    205	root	2872K	624K	sleep	59	0	0:00:00	0,0%	nscd/18
    895	root	123M	21M	sleep	49	0	0:00:49	0,0%	soffice.bin/4
    667	root	1844K	488K	sleep	59	0	0:00:00	0,0%	rpc.rstatd/1
    217	root	5364K	536K	sleep	59	0	0:00:00	0,0%	lpsched/1
    324	root	4360K	196K	sleep	59	0	0:00:00	0,0%	snmpdx/1
    240	root	1100K	288K	sleep	59	0	0:00:00	0,0%	utmpd/1
    343	root	4892K	0K	sleep	59	0	0:00:00	0,0%	vold/3
    276	root	3240K	0K	sleep	59	0	0:00:00	0,0% 	htt/1
    633	root	3784K	0K	sleep	59	0	0:00:00 	0,0% 	sdt_shell/1
    657	root	16M	2496K	sleep	49	0	0:00:00 	0,0% 	dtfile/1
    203	root	4484K	568K	sleep	59	0	0:00:00 	0,0% 	cron/1
    189	root	5636K	1092K	sleep	59	0	0:00:00 	0,0% 	syslogd/13
    168	daemon	2444K	820K	sleep	59	0	0:00:00 	0,0% 	statd/1
    156	root 	2412K	688K	sleep	59	0 	0:00:00 	0,0% 	inetd/1
    172	root 	2160K	748K	sleep	59	0	0:00:00 	0,0% 	lockd/2
    229	root 	1348K	0K	sleep	59	0	0:00:00 	0,0% 	powerd/2
    133	root 	2212K	604K	sleep	59	0	0:00:00 	0,0% 	rpcbind/1
    Total: 61 processes, 161 lwps, load averages: 0,25, 0,17, 0,27

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

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

    В Solaris 9 появилась новая программа preap, которая позволяет убрать из системы "мнимые" (defunct), не до конца завершившиеся процессы, которые также носят название "зомби" (zombie). Эти процессы совершенно безобидны, так как это - самые обыкновенные процессы, код завершения которых не был принят родительскими процессами (например, в результате преждевременного завершения родительского процесса или иного сбоя). Несмотря на безобидность, они могут попусту занимать ресурсы системы, если таких процессов будет много. Обычно процессы-зомби автоматически уничтожаются процессом init, но если этого почему-либо не произошло, можно воспользоваться программой preap, которая примет код завершения процесса-зомби и даст ему упокоиться с миром.

    Команды управления процессами

    Основным средством управления процессами является команда kill, передающая процессу сигналы. Также можно использовать вышеописанные программы изменения приоритета процесса, прежде всего, команду nice, для управления приоритетом.

    Не следует путать команду kill с сигналом KILL - они просто тезки; с помощью одноименной команды можно передать процессу как сигнал KILL, так и любые другие сигналы.

    Будучи запущенной без ключей, она передает процессу сигнал TERM, требующий завершения процесса:

    kill [-ключи] номер_процесса

    Например, для завершения процесса sendmail можно выполнить следующие действия:

    :
    ps auxw | grep sendmail 
    root  2057 0.0 0.2 2664 444 ? S Jul08 3:24 sendmail: 
                                   accepting connections

    Как видно, sendmail имеет PID 2057. Посылаем сигнал, требующий завершения процесса:

    kill 2057

    И повторяем последнее действие для проверки (контрольный выстрел):

    kill 2057
    kill: (2057) - No such pid

    Сообщение No such pid говорит о том, что процесс уже завершился.

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

    Например, после изменений, внесенных в файл конфигурации /etc/inetd.conf, следует потребовать от демона inetd перечитать этот файл конфигурации.

    Это можно сделать, послав демону сигнал HUP (номер один), так как известно, что этот демон перечитывает файлы конфигурации, если получает сигнал с номером 1. Вначале надо узнать идентификатор процесса, которому будем посылать сигнал:

    ps -ef | grep inetd 
    root   156     1  0  17:43:44     ?   0:00  /usr/sbin/inetd -s
    root   4555  760  0  19:15:16  pts/5  0:00  grep inetd

    Мы видим два процесса, в строках информации о которых есть слово inetd. Первая строка, grep inetd - это тот самый процесс grep, который мы только что сами запустили. Программы ps и grep запустились одновременно, и ps показал "мгновенный снимок" таблицы процессов.

    Строка grep inetd в таком случае должна была бы показываться всегда, но на практике иногда мы не видим ее при запуске такой команды. Проведите эксперимент: возможно, что в вашей системе (это зависит от ее скорости и текущей загрузки) вы никогда не увидите строку grep или наоборот, будете ее видеть всегда.

    Это связано с тем, что физически запуск grep происходит чуть-чуть позже, чем ps, последняя может успеть завершиться раньше, чем grep начнется (ведь таблица процессов может оказаться маленькой и работы у ps будет мало). Тогда строки про grep в списке найденных процессов не будет.

    Теперь пошлем сигнал процессу inetd:

    kill -1 156

    Помните, не все демоны и не во всех системах по сигналу HUP перечитывают свой файл конфигурации. Прежде чем посылать демону сигналы, выясните, как он на них собирается реагировать: почитайте в man о его повадках.

    Владелец процесса может посылать сигналы своему процессу, но привилегированный пользователь ( root ) может отправить любой сигнал любому процессу.

    Посылка сигнала KILL (номер 9) вызывает безусловное немедленное завершение процесса:

    kill -9 PID

    или

    kill -KILL PID

    При выполнении команды kill лучше указывать мнемонические обозначения сигналов, а не числовые: в разных системах UNIX сигналы с одним и тем же числовым номером могут иметь разный смысл. Впрочем, можно смело руководствоваться вышеприведенными таблицами в разделе "сигналы" в отношении сигналов в Solaris.

    Для посылки сигнала нескольким процессам одновременно следует использовать программы pkill или killall (их подробное описание приведено в разделе "Сигналы" выше в этой лекции).

    При запуске процесса можно менять его базовый приоритет внутри класса планирования. Это возможно только для класса планирования разделения времени. Обычный пользователь может только понижать приоритет процесса, а привилегированный пользователь может менять NICE в обе стороны. Для этого используется команда nice, которая в разных системах имеет разные ключи и немного разный синтаксис.

    В Solaris она выглядит так:

    nice -n приращение команда

    например

    nice -n 5 ls

    Это "5" воспринимается как увеличение значения NICE на 5, т.е. снижение приоритета на 5 единиц. Пользователь root может дать команду вида nice -n -4 ls. Это будет воспринято как увеличение базового приоритета, т.е. уменьшение значения NICE на 4.

    Базовый приоритет уже запущенного процесса можно менять командой renice:

    renice -n приращение PID

    Команда renice может быть использована также для изменения приоритета группы процессов по разным признакам, для уточнения обратитесь к man renice.

    Работа с заданиями

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

    Более подробно о работе с заданиями говорится в лекции 9.

    Планирование запуска процессов

    Вынесете ли вы сегодня мусор или пойдете в магазин, поедете на заправку кормить своего железного коня бензином или просто ляжете спать пораньше - так или иначе, какое-нибудь дело вы сегодня сделаете. Дела, которые вы делаете, могут быть однократными (купить щенка) или регулярными (погулять с собакой). Может быть, "однократные" - не совсем точное прилагательное, потому что щенка вы можете купить и раз, и два, и еще много раз в жизни. Но вряд ли это дело можно назвать регулярным - не станете же вы раз в год ровно в полночь 13 марта покупать щенка.

    Все-таки станете? Вы не сатанист, часом?

    Еще приятнее запланировать выполнение нерегулярного или регулярного дела так, чтобы его делал кто-то другой. Например, сообщите сыну, что вы просите его завтра в полдень отправиться в клуб собаководов и купить там щеночка. Однократно. А потом (когда купит) скажите, что вы запланировали его (сына) прогулки с ним (щеночком) ежедневно - на годы вперед.

    Системный администратор, даже если у него нет сына и щеночка, тоже не лишен радостей планирования. Так, для планирования однократных действий в любом UNIX используется программа at, а для регулярных - crontab.

    at

    Для планирования однократного запуска задач в строго определенное время (точность - одна минута) используется программа at. Она создает и изменяет список задач для выполнения, размещая его в каталоге /var/spool/cron/atjobs/. В Solaris это именно такой каталог, в других системах местоположение очереди задач может быть иным. Список задач ежеминутно инспектируется демоном cron, который отвечает за своевременный запуск задач. Во многих других системах UNIX демон 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.

    Указание time без date означает выполнение задачи в текущие сутки, а если time сегодня уже прошло, - назавтра в указанное время.

    Программа at принимает список задач для выполнения во входной поток.

    at -l (или atq ) распечатывает список поставленных в очередь задач.

    at -r позволяет удалить задачу по идентификатору, который показывает at -l.

    В некоторых системах at -r называется atrm. В Solaris приемлемы оба варианта.

    Суперпользователь всегда может воспользоваться at.

    Обычному пользователю разрешается использовать at в случае, если его имя указано в файле /usr/lib/cron/at.allow. Если этого файла нет, то проверяется, нет ли имени пользователя в /usr/lib/cron/at.deny (если есть, ему запрещается использование at ). Если ни одного из этих двух файлов нет, пользоваться at разрешается только пользователям, которым назначена роль solaris.jobs.user (по умолчанию - root ). Если есть только файл /usr/lib/cron/at.deny и он пуст, то по умолчанию всем разрешено пользоваться at. В файлах at.deny и at.allow имена пользователей пишутся по одному в строке.

    Задания at и crontab заблокированного пользователя не запускаются - демон cron запустит задания только того пользователя, который имеет легальный доступ в систему в настоящее время, как отражено в файле /etc/shadow.

    Задание, запущенное на выполнение демоном cron, выполняется от имени пользователя, который поставил задание в очередь. Стандартный вывод и стандартный поток ошибок задания cron высылает почтой этому пользователю. Можно указать иное место для вывода информации с помощью ключа m команды at или с помощью параметра в файле crontab (см. ниже). Запланированные задачи выполняются в среде командного процессора /bin/sh без назначения управляющего терминала (т.е. вне терминальной группы, связанной с конкретным терминалом).

    Проведем небольшой эксперимент. Вначале убедимся, что каталог, где сохраняются задания at, пуст:

    #ls /var/spool/cron/atjobs/
    #

    Проверим время и дату:

    date
    Сбт 15 Май 2004 19:10:29

    Запланируем создание файла в корневом каталоге через две минуты:

    at 1912
    at> touch /tuition
    at> <Ctrl-D>
    commands will be executed using /sbin/sh
    job 1084633920.a at Сбт Май 15 19:12:00 2004

    В каталоге, где собираются задания в очереди на выполнение, появился новый файл:

    ls /var/spool/cron/atjobs/
    1084633920.a

    И по команде at -l мы получаем информацию о поставленном в очередь задании (указывается имя пользователя, инициировавшего задание, идентификатор задания, по которому его можно удалить, и время планируемого запуска):

    at -l
    user = root   1084633920.a  Сбт Май 15 19:12:00 2004

    Пока в корневом каталоге файла tuition нет:

    ls /
    bin 	devices 	lib 	opt 	tmp 	xfn
    boot 	etc 	lost+found 	platform	TT_DB
    cdrom 	export 	mnt 	proc 	usr
    core 	home 	net 	sbin 	var
    dev 	kernel 	nsmail 	test 	vol

    Почему? Да время еще не наступило:

    date
    Сбт 15 Май 2004 19:11:42

    Дожидаемся заданного времени и (о чудо!) файл /tuition появился! Смотрите:

    date
    Сбт 15 Май 2004 19:12:12
    
    ls /
    bin 	devices 	lib 	opt 	tmp 	vol
    boot 	etc 	lost+found 	platform 	TT_DB 	xfn
    cdrom 	export 	mnt 	proc 	tuition
    core 	home 	net 	sbin 	usr
    dev 	kernel 	nsmail 	test 	var

    cron

    Демон cron ежеминутно инспектирует таблицу запланированных задач и выполняет те задачи, время которых наступило (в Solaris - не более 100 задач в минуту). Программа at нужна, как видно из раздела "at" выше, для планирования однократных задач, а программа crontab служит для планирования периодически запускаемых процессов. Они подготавливают таблицу заданий для cron.

    У каждого пользователя есть своя таблица crontab. Ее можно отредактировать командой crontab -e. По этой команде вызывается текстовый редактор (обычно - vi ), а в качестве файла для редактирования окажется таблица crontab. Если вы раньше не задавали никаких периодических задач, файл будет пустым.

    Формат таблицы 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 - команда командному процессору, которую надо запустить (возможно, с аргументами).

    Каждое числовое поле в таблице может содержать число, несколько чисел через запятую, диапазон (начало и конец диапазона через дефис) или звездочку. Звездочка в соответствующем поле означает "каждую единицу времени", например в поле часов она означает "каждый час".

    Если в строке указаны определенное число месяца и определенный день недели, то для выполнения команды достаточно, чтобы наступило либо это число, либо этот день недели.

    Так, строка

    12 10 * * 0 rm -rf /var/log/*.[0-9]

    означает, что в 10:12 каждое воскресенье нужно удалять файлы *.[0-9] из /var/log.

    Однако, если было бы написано

    12 10 10 * 0 rm -rf /var/log/*.[0-9]

    то требовалось бы выполнять такое удаление "в 10:12 по воскресеньям и десятым числам", а не "в 10:12 десятого числа, если оно приходится на воскресенье".

    Как и в случае с at, команда запускается от имени владельца таблицы, в качестве командного процессора используется /bin/sh.

    В первых строках таблицы могут быть установлены переменные среды окружения. Наиболее полезной может оказаться переменная среды окружения PATH:

    PATH=/usr/bin:/usr/sbin:/usr/local/bin

    В ней можно задать каталоги, которые по умолчанию не входят в PATH.

    Кроме PATH можно установить переменные SHELL и HOME, а также MAILTO. По умолчанию HOME (домашний каталог) берется из /etc/passwd. Переменная LOGNAME устанавливается автоматически при запуске команды. Ей присваивается имя пользователя, от имени которого запускается команда. В BSD-системах она может называться USER, в Solaris есть обе переменные. LOGNAME и USER нельзя переопределить, HOME и SHELL - можно. Программа cron отправит сообщение владельцу таблицы crontab, если найдет повод это сделать (например, произошла ошибка выполнения команды). Если переменная MAILTO существует и ее значение отлично от пустой строки, то cron расценит это значение как имя адресата, которому надо послать письмо вместо пользователя, запланировавшего задачу. Если значение переменной MAILTO - пустая строка, то почта послана не будет. Установка любой переменной среды окружения в таблице crontab осуществляется так:

    имя_переменной = значение

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

    Для просмотра таблицы crontab используйте команду crontab -l, для удаления таблицы - crontab -r. Можно создать файл с таблицей crontab заранее и установить ее в систему командой

    crontab имя_файла_таблицы.

    Такая команда потенциально опасна: если раньше существовали какие-либо команды в таблице crontab, то они потеряются навсегда.

    Регулярно выполняемые системные скрипты

    В Solaris нет стандартно принятых по умолчанию регулярно выполняемых скриптов. Однако рекомендуется их создать и расположить в каталоге /var/admin/cron/ или /etc/periodic/.

    crontab -e 
    22 * * * * /var/admin/cron/hourly 
    22 22 * * * /var/admin/cron/daily 
    2 22 * * 0 /var/admin/cron/weekly 
    2 2 1 * * /var/admin/cron/monthly

    В скрипт hourly рекомендуется включать проверку состояния сетевого подсоединения ( ping ), проверку и при необходимости установку прав доступа к почтовым ящикам пользователей, проверку состояния основных демонов ( syslog, sendmail, named, sshd ) с помощью ps, архивацию и обновление файлов протоколов ( log rotation ), которые достаточно выросли за час (рекомендуемый размер файла протокола для архивации - 1-2 мегабайта, но вы можете выбрать иное, исходя из удобства последующего анализа этого файла).

    В скрипт daily включают проверку очереди сообщений (не слишком ли велика - запустите mailq ), синхронизацию системного времени ( ntpdate, rdate ).

    В скрипт weekly включают проверку свободного места на диске (если у вас это приходится делать чаще, чем раз в неделю, имеет смысл подумать о покупке нового диска, а может быть, и двух сразу), проверку файлов passwd, shadow, hosts.allow и hosts.deny, файлов конфигурации ftpd, sendmail, протоколов utmp и wtmp на предмет прав доступа и размера.

    Ежемесячный скрипт monthly обычно содержит архивацию и обновление тех файлов протоколов, которые растут медленно.

    Вы можете включить в эти скрипты свои задачи, которые являются специфическими для конкретной системы - проверку конфигурации smbd для файлового сервера samba, проверку дисковых квот пользователей, контроль появления свежих файлов с установленным битом SUID и так далее.

    Страницы:

    Замечание о совместимости утилит

    Несмотря на то что Solaris удовлетворяет многочисленным стандартам, некоторые программы в системе (точнее, их возможности и ключи) расходятся со стандартом XPG4. Этот стандарт (The X/Open Portability Guide, Issue 4 - XPG4) представляет собой спецификацию, описывающую программы, заголовки и интерфейсы. В частности, описывается ожидаемое поведение ряда программ UNIX и их ключи.

    Что находится в каталоге /usr/bin/xpg4

    В тех случаях, когда поведение и ключи программ Solaris расходились со спецификацией XPG4, изначальная версия программы под Solaris не изменялась. вместо этого программа, совместимая с XPG4 с примерно такими же функциональными особенностями и точно таким же именем, помещалась в каталог /usr/xpg4/bin. Таким образом, для того, чтобы выбрать, какие программы - оригинальные или XPG4-совместимые вы предпочитаете использовать в своей системе, достаточно указать первым в переменной среды окружения PATH тот каталог, в котором лежат нужные вам "по умолчанию" программы. Если первым указан каталог /usr/bin, то при вызове команды по ее короткому имени, например, grep, а не по полному имени файла, например, /usr/xpg4/bin/grep, будет вызываться /usr/bin/grep - оригинальная программа. Если указать в PATH первым /usr/xpg4/bin, то будет запускаться XPG4-совместимая версия. Помните, что оригинальные программы могут располагаться также в /bin, /usr/ucb и /usr/ccs/bin.

    Спецификация XPG4 включает в себя спецификации программ из IEEE Std 1003.2-1992 и IEEE Std 1003.2a-1992 (которые вместе носят название POSIX 2).

    Иерархия процессов в Solaris

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

    Само ядро Solaris представляет собой множество потоков (threads), которые выполняются параллельно. Действительно, у ядра много разных дел, было бы странно, если бы ядро пыталось все делать последовательно, а не параллельно. Термин threads часто переводят как "нить", но мы будем говорить в контексте управления процессами именно о "потоках", понимая под этим "потоки команд", в отличие от "потоков данных", которые будут рассмотрены ниже.

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

    Solaris реализует многоуровневую поточную модель. Ее назначение - разделить управление потоками пользовательского уровня и работу ядра. Потоки пользовательского уровня имеют свою схему приоритетов. Их планирование проводится с помощью потока-планировщика. Такой поток создается библиотекой потоков, когда многопоточное приложение компилируется и выполняется. Внутри одного пользовательского процесса могут работать свои потоки, передача управления между которыми осуществляется внутренним планировщиком этого процесса. Благодаря этому многопоточные приложения могут порождать тысячи потоков без существенной загрузки ядра. Оно будет видеть это приложение как один процесс. По сути, ядро не видит пользовательские потоки, пока они не присоединяются к легковесному процессу (lightweight process, LWP), имеющему определенное положение в операционной системе. Поток-планировщик отвечает за отображение пользовательских потоков в легковесный процесс (LWP), который связан с потоком ядра для выполнения процессором. Каждый LWP имеет поток ядра, но необязательно каждый поток ядра имеет LWP. Часть потоков ядра задействованы исключительно операционной системой, поэтому LWP здесь не требуется.

    Свойства процесса

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

    (рис 7.1) Взаимоотношения процессов в многопотоковой архитектуре

    Идентификаторы процесса

    Процесс всегда имеет свой уникальный номер - PID (process ID). PID - это целое число в диапазоне допустимых целых чисел (для 32-разрядных систем - от 0 до 65535). Процесс с номером 0 - это обычно процесс свопинга, фактически являющийся частью кода ядра. Процесс с номером 1 - это всегда init, процесс, который порождает все остальные процессы в системе при ее старте. У всех процессов, кроме init, есть родительский процесс, и каждому процессу, кроме его собственного идентификатора PID, соответствует идентификатор родительского процесса (PPID - parent process ID).

    В таблице процессов, кроме идентификаторов PID и PPID, хранятся eUID (effective UID - эффективный идентификатор пользователя) владельца процесса и eGID (effective GID - эффективный идентификатор группы) группы процесса. Фактические (реальные) владелец и группа процесса - это пользователь и группа, которые запустили процесс, а эффективные владелец и группа процесса - это те, от имени которых запущен процесс. Для определения прав доступа используются эффективные идентификаторы, а для задач управления процессом (например, посылки сигнала процессам, которые запустил определенный пользователь, см. описание команды pkill ниже) - реальные. Эти идентификаторы передаются по наследству от родительского процесса дочернему.

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

    Любой процесс относится к какой-либо терминальной группе, т.е. группе процессов, запущеных с одного терминала. Терминал определяется параметром TTYID.

    Процесс имеет базовый и динамический приоритеты, в зависимости от приоритета запросы процесса к системе выполняются медленнее или быстрее.

    Получить полный список процессов в системе с выводом их идентификаторов и ряда других параметров можно с помощью команды ps -ef.

    Приоритеты процесса

    Во многих системах UNIX процесс имеет базовый приоритет ( NICE ) и динамический приоритет ( PRI ). Базовый приоритет может принимать значение от -20 до +20. Чем меньше числовое значение базового приоритета NICE, тем выше приоритет. Процесс с отрицательным приоритетом -20 - самый высокоприоритетный. Динамический приоритет вычисляется планировщиком задач на основе базового приоритета по формуле, в которую входит общее потребленное процессом процессорное время. Чтобы дать возможность выполняться новым и более коротким процессам, динамический приоритет снижается с увеличением потребленного процессом времени процессора.

    В Solaris применяется более сложная схема планирования приоритетов процессов, которая описывается ниже. Для процессов одного из классов планирования (с разделением времени) справедлива вышеописанная простая схема из базового и динамического приоритетов.

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

    Приоритет базируется на классе планирования (scheduling class); всего различают четыре класса планирования: с разделением времени (timesharing), системный (system), реального времени (real-time) и планирование на основе справедливого раздела (fair Class scheduling, FCS). У процессов разных классов планирования свои уровни приоритета и свои очереди на выполнение. Стало быть, в системе мы имеем четыре очереди к процессору. Внутри каждого класса процессы, стоящие в очереди, имеют свои уровни приоритета. Эти уровни отображаются в глобальные приоритеты планирования (global scheduling priorities). Первым процессор займет процесс, который имеет наивысший глобальный приоритет. По умолчанию, процесс из класса планирования с разделением времени имеет более низкий глобальный приоритет, чем процесс из системного класса, а тот, в свою очередь, более низкий, чем процесс реального времени.

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

    Получить информацию о текущих классах планирования процессов можно с помощью команды dispadmin.

    Среда окружения

    Каждый процесс имеет свою среду окружения - специальную область, в которой хранятся имена переменных и их значения. Среда окружения используется для модификации поведения процесса ; так, в зависимости от значения переменной TERM текстовый редактор будет выдавать разные коды управления экраном, поскольку переменная TERM используется для задания типа терминала. Переменные среды окружения могут быть помечены как экспортируемые, это означает, что такую переменную дочерний процесс унаследует от процесса-родителя. Такие переменные, как TERM, PATH, USER обычно являются экспортируемыми. Из командной строки пометить переменную как экспортируемую можно с помощью команды export:

    export TERM PATH

    К переменным среды окружения легко обратиться из прикладной программы на языке С - для этого предусмотрен специальный массив строк:

    char *env[]

    Аргументы

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

    char *argv[]

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

    int argc

    Классы планирования

    В Solaris 9 есть шесть классов планирования: с разделением времени (timesharing, TS), интерактивный (interactive, IA), системный (system, SYS), реального времени (real-time, RT),с фиксированным приоритетом (fixed priority, FX) и планирование на основе справедливого раздела (fair share scheduling, FSS).

    Соотношение глобальных и относительных приоритетов
    Диапазон глобальных приоритетов Очередь планирования
    159–100 Процессы реального времени (0-59)
    99–60 Системные процессы
    59–0 Приоритеты процессов с разделением времени (0-59)

    По умолчанию процессы попадают в класс с разделением времени.

    С помощью команды

    ps -cl

    можно узнать глобальные приоритеты запущенных в данный момент процессов, а "внутренние" приоритеты процессов в разных классах планирования - с помощью команды dispadmin.

    Планирование процессов реального времени

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

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

    В нестрогой среде реального времени период реакции должен иметь гарантированную конечную продолжительность (например, верхний предел времени, за которое приложение должно освободить процессор; в Solaris такой период составляет 5 миллисекунд).

    В большинстве систем UNIX поддержки реального времени нет. Это связано с тем, что:

  • "промахи" обращения к памяти из-за отсутствия страниц в оперативной памяти могут вызвать непредсказуемую задержку вследствие необходимости подгрузить требуемую страницу в память из swap-раздела;
  • хотя ядро является выгружаемым (preemptable) - т.е. оно может быть смещено из процессора при запуске другого процесса, - в некоторых ситуациях все же не допускается выгрузка ядра из процессора, например, при обработке прерывания; элементы кода, которые не могут быть выгружены из процессора во время выполнения, называются "точками невыгружаемости" (nonpreemption points).
  • Решение первой из этих проблем в Solaris состоит в том, что все страницы процесса реального времени в памяти блокируются и их выгрузка на диск запрещается. Вторая проблема решается за счет того, что ядро Solaris - многопотоковое, обработчики прерываний реализованы как отдельные потоки, что делает возможным установить для них отдельный приоритет ; более того, в Solaris есть возможность priority lending - "одалживание приоритета ". Это означает, что когда более приоритетный процесс нуждается в результатах работы менее приоритетного процесса, он может "одолжить" последнему на время свой высокий приоритет для выполнения требуемой задачи.

    Диспетчер

    Когда поток готов к выполнению, он помещается в очередь отправки на выполнение. Каждый процессор (в многопроцессорной системе) имеет отдельный набор очередей отправки. Состояние ожидания в очереди отправки называется состоянием выполнения (RUN). Когда процессор освобождается, диспетчер берет поток с наивысшим приоритетом из очереди отправки этого процессора и помещает его в процессор. Теперь поток в состоянии "внутри процессора" (ONPROC) и может выполнять вычисления.

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

  • поток занимает процессор, пока не закончится отведенный ему период времени (определяемый приоритетом потока). Такой период называется квантом. Поскольку процессы с большим приоритетом выбираются чаще, то квант обычно обратно пропорционален приоритету ( процессы с более высоким приоритетом имеют меньшие кванты). Когда квант исчерпан, потоку присваивается приоритет нового уровня (значение tqexp ). Такой уровень почти всегда ниже приоритета потока при старте. Это сделано для обеспечения справедливости при планировании;
  • поток ждет завершения ввода-вывода или разблокировки нужного ему ресурса, тогда он переходит в состояние "сна" (SLEEP). Проснувшимся потокам назначается более высокий приоритет, чем у них был до сна, чтобы они могли "наверстать упущенное";
  • ядро прервало поток; если прерванный поток долго ожидает внимания процессора, то его приоритет повышается до значения lwait. Так потоки компенсируют ожидание в очереди после прерывания.
  • Проверка приоритета процесса

    Выяснить, с каким легковесным процессом ассоциирован конкретный процесс и какой класс планирования ему назначен, можно с помощью команды ps и ключей -L и :

    /usr/bin/ps -efcL
    
    UID	PID	PPID	LWP	NLWP	CLS	PRI	STIME	TTY	LTIME 	CMD
    root	0	0	1	1	SYS	96	00:23:03	?	0:03	sched
    root	1	0	1	1	TS	59	00:23:03	?	0:00	/etc/init -
    root	2	0	1	1	SYS	98	00:23:03	?	0:00	pageout
    root	3	0	1	1	SYS	60	00:23:03	?	0:00	fsflush
    root	314	1	1	1	TS	59	00:23:35	?	0:00	/usr/lib/saf/sac 
    											-t 300
    root	289	1	1	1	TS	59	00:23:32	?	0:00	/usr/lib/snmp/snmpdx
     										-y -c /etc/snmp/conf
    root	182	1	1	3	TS	59	00:23:22	?	0:00	/usr/lib/autofs
    										/automountd
    root	182	1	2	3	TS	59	00:23:23	?	0:00	/usr/lib/autofs
    										/automountd
    root	182	1	3	3	TS	59	00:25:23	?	0:00	/usr/lib/autofs
    										/automountd
    root	207	1	3	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	4	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	5	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	6	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	7	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	8	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	207	1	9	18	TS	59	00:23:25	?	0:00	/usr/sbin/nscd
    root	193	1	11	13	TS	59	00:23:24	?	0:00	/usr/sbin/syslogd
    root	193	1	12	13	TS	59	00:23:24	?	0:00	/usr/sbin/syslogd
    root	193	1	13	13	TS	59	00:23:26	?	0:00	/usr/sbin/syslogd
    root	439	419	1	1	IA	39	00:24:42	pts/4	0:00	bash

    Вывод этой команды здесь сильно сокращен: процессов в системе на самом деле всегда значительно больше. Сейчас нам интересны прежде всего колонки LWP, CLS и PRI, в которых показаны номер легковесного процесса, класс планирования и глобальный приоритет соответственно.

    Чем больше числовое значение глобального приоритета (значение PRI), тем выше глобальный приоритет процесса.

    Мы видим, что многопоточные процессы (например, демон автомонтирования /usr/lib/autofs/automountd и демон протоколирования /usr/sbin/syslogd ) могут одновременно иметь несколько LWP (в колонке NLWP указано количество LWP, с которыми ассоциирован процесс ).

    Настройка таблиц диспетчера

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

    Чтобы узнать, какие классы доступны для редактирования, следует запустить dispadmin с ключом -l и определить активные классы планирования:

    dispadmin -l
    CONFIGURED CLASSES ==================
    SYS			(System Class)
    TS			(Time Sharing)
    FX			(Fixed Priority)
    IA			(Interactive)
    RT			(Real Time)

    Далее выводим таблицу диспетчера для выбранного класса (попробуем это на классе планирования с разделением времени - TS ):

    dispadmin -c TS -g
    # Time Sharing Dispatcher Configuration
    RES=1000
    
    ts_quantum	ts_tqexp	ts_slpret	ts_maxwait	ts_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
    200	0	50	0	50	#	4
    200	0	50	0	50	#	5
    200	0	50	0	50	#	6
    200	0	50	0	50	#	7
    200	0	50	0	50	#	8
    200	0	50	0	50	#	9
    160	0	51	0	51	#	10
    160	1	51	0	51	#	11
    160	2	51	0	51	#	12
    160	3	51	0	51	#	13
    160	4	51	0	51	#	14
    160	5	51	0	51	#	15
    160	6	51	0	51	#	16
    160	7	51	0	51	#	17
    160	8	51	0	51	#	18
    160	9	51	0	51	#	19
    120	10	52	0	52	#	20
    120	11	52	0	52	#	21
    120	12	52	0	52	#	22
    120	13	52	0	52	#	23
    120	14	52	0	52	#	24
    120	15	52	0	52	#	25
    120	16	52	0	52	#	26
    120	17	52	0	52	#	27
    120	18	52	0	52	#	28
    120	19	52	0	52	#	29
    80	20	53	0	53	#	30
    80	21	53	0	53	#	31
    80	22	53	0	53	#	32
    80	23	53	0	53	#	33
    80	24	53	0	53	#	34
    80	25	54	0	54	#	35
    80	26	54	0	54	#	36
    80	27	54	0	54	#	37
    80	28	54	0	54	#	38
    80	29	54	0	54	#	39
    40	30	55	0	55	#	40
    40	31	55	0	55	#	41
    40	32	55	0	55	#	42
    40	33	55	0	55	#	43
    40	34	55	0	55	#	44
    40	35	56	0	56	#	45
    40	36	57	0	57	#	46
    40	37	58	0	58	#	47
    40	38	58	0	58	#	48
    40	39	58	0	59	#	49
    40	40	58	0	59	#	50
    40	41	58	0	59	#	51
    40	42	58	0	59	#	52
    40	43	58	0	59	#	53
    40	44	58	0	59	#	54
    40	45	58	0	59	#	55
    40	46	58	0	59	#	56
    40	47	58	0	59	#	57
    40	48	58	0	59	#	58
    20	49	59	32000	59	#	59

    Первая строка, в которой указано значение RES, определяет, в чем измеряется время во всей таблице приоритетов данного класса. Величина RES фактически задает дискретность измерения времени для столбца ts_quantum таблицы диспетчера. Ее значение по умолчанию - 1000. Изменять дискретность не рекомендуется. Обратная к RES величина равна 0,001, и это интерпретируется как одна тысячная секунды, т.е. одна миллисекунда. Стало быть, по умолчанию время в столбце ts_quantum измеряется в миллисекундах.

    Как было показано в разделе "Диспетчер" выше, смысл значений, приведенных в столбцах таблицы диспетчера, следующий:

  • ts_quantum представляет собой максимальный период времени (квант), в течение которого поток может оставаться в процессоре до того, как диспетчер изменит его приоритет ;
  • ts_tqexp задает приоритет, который будет назначен потоку после того, как истечет его квант времени и он будет удален из процессора;
  • ts_slpret указывает приоритет, который будет иметь процесс, когда он будет обрабатываться после "сна", т.е. после ожидания завершения ввода-вывода или когда он дождется снятия блокировки с требуемого ему ресурса;
  • ts_maxwait указывает время в секундах, которое процесс будет оставаться в очереди, в случае, если его квант времени еще не истек; если он не использует свой квант времени в течение этого числа секунд, ему будет присвоен новый приоритет ts_lswait. Если ts_maxwait равно нулю, то принимается значение по умолчанию (одна секунда);
  • ts_lswait обозначает присваиваемый процессу приоритет, когда процесс на долгое время был вытеснен из процессора.
  • В таблицах диспетчера указываются относительные приоритеты (которые имеют силу внутри класса планирования ). Глобальный (иначе говоря - абсолютный) приоритет вычисляется из относительного в соответствии с табл. 7.1.

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

    Посмотрим, как работает эта схема динамического назначения приоритетов. Предположим, процесс начал выполняться с приоритетом 0. Подождав, пока ему дадут управление в течение одной секунды ( ts_maxwait ), процесс получил новый приоритет 50 ( ts_lwait ).

    Вместе с новым приоритетом процесс обрел новое значение кванта (меньшее, так как чем выше приоритет, тем меньше квант, чтобы высокоприоритетные задачи не забивали процессор). Вместо прежних 200 миллисекунд процесс получил квант в 40 миллисекунд. Зато с этим приоритетом процесс получил возможность вытеснять из процессора менее приоритетные процессы.

    Если процесс продолжает постоянно использовать процессорное время, не отвлекаясь на ввод-вывод (например, это вычислительный процесс программы моделирования полета ракеты), то по истечении кванта времени он получит новый приоритет 40 ( ts_tqexp ).

    Дальнейшие назначения приоритетов показаны ниже:

    приоритет квант
    40 40
    30 80
    20 120
    10 160
    0 200
    50 40
    40 40
    30 80
    и т.д. и т.д.

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

    Класс реального времени ( RT ) описывается более простой таблицей диспетчера:

    # Real Time Dispatcher Configuration RES=1000
    TIME QUANTUM(rt_quantum)        PRIORITY LEVEL
    1000                       #    0
    1000                       #    1
    1000                       #    2
    1000                       #    3
    1000                       #    4
    1000                       #    5
    1000                       #    6
    1000                       #    7
    1000                       #    8
    1000                       #    9
    800                        #    10
    800                        #    11
    800                        #    12
    800                        #    13
    800                        #    14
    800                        #    15
    800                        #    16
    800                        #    17
    800                        #    18
    800                        #    19
    600                        #    20
    600                        #    21
    600                        #    22
    600                        #    23
    600                        #    24
    600                        #    25
    600                        #    26
    600                        #    27
    600                        #    28
    600                        #    29
    400                        #    30
    400                        #    31
    400                        #    32
    400                        #    33
    400                        #    34
    400                        #    35
    400                        #    36
    400                        #    37
    400                        #    38
    400                        #    39
    200                        #    40
    200                        #    41
    200                        #    42
    200                        #    43
    200                        #    44
    200                        #    45
    200                        #    46
    200                        #    47
    200                        #    48
    200                        #    49
    100                        #    50
    100                        #    51
    100                        #    52
    100                        #    53
    100                        #    54
    100                        #    55
    100                        #    56
    100                        #    57
    100                        #    58
    100                        #    59

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

    Планирование на основе справедливого раздела

    В Solaris стандартный планировщик задач (диспетчер) старается предоставить процессам, которые по умолчанию запускаются с классом планирования timesharing (в режиме с разделением времени), примерно одинаковый доступ к процессору. Однако, если на самом деле некоторые процессы в системе более важны, чем другие (сервер баз данных, web-сервер крупного портала и т.п.), можно использовать иной метод планирования - планирование на основе справедливого раздела (fair share scheduler - FSS). В этом случае можно назначить группам процессов разные "порции" процессорного времени, которые те будут получать в единицу времени. Грубо говоря, можно потребовать от планировщика отдать 70% времени web-серверу, а 30% - всем остальным процессам. Если этого не сделать, время будет делиться поровну. Кроме соответствующего алгоритма, в Solaris 9 появился новый класс планирования, который тоже называется планированием на основе справедливого раздела.

    В более ранних версиях Solaris этот алгоритм планирования (и соответствующий ему класс) отсутствовал, хотя в других системах аналогичный алгоритм был реализован в середине 1990-х годов, например, в IRIX 6.2.

    Более детальное описание этой возможности дано по адресу http://docs.sun.com/db/doc/816-4882/6mb2ipq5n?q=scheduling+classa=view

    Распределение памяти. Swaping

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

    В UNIX вся память разделена на страницы определенного одинакового размера. Каждый процесс получает от системы запрошенное количество памяти, выделение памяти в UNIX осуществляется постранично. Процессы реального времени и часть кода ядра (например, та, что отвечает за обмен страницами между оперативной памятью и диском) всегда находятся в памяти, страницы остальных процессов могут быть выгружены на диск. В большинстве систем UNIX размер страницы составляет 4 Кбайт. В Solaris для x86 он ровно такой же, но на платформе SPARC может быть другой размер страницы, т.к. это свойство системы зависит от платформы. Узнать размер страницы памяти в Solaris можно по команде pagesize.

    Традиционно в литературе по системам UNIX для описания процесса обмена страницами между памятью и диском используют термин "свопинг" (swaping). Этот термин в действительности означает полную выгрузку страниц процесса на диск. На самом деле менеджер виртуальной памяти в UNIX обычно выполняет "пейджинг" (paging), что означает постраничную (частичную) выгрузку процесса на диск. Свопинг выполняется в том случае, если памяти критически не хватает, чего при нормальной работе системы не наблюдается.

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

    Более подробно алгоритм работы менеджера виртуальной памяти рассмотрен в лекции 7 курса "Администрирование ОС Solaris".

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

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

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

    Доступ процессов к файлам

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

    То, какие права доступа к файлу получит процесс, зависит от эффективных идентификатора владельца (eUID ) и группы (eGID) этого процесса. При обращении процесса к файлу ядро проверяет, кем по отношению к этому файлу является владелец процесса. Если эффективный идентификатор владельца процесса совпадает с идентификатором владельца файла, то процесс получает права доступа к файлу, определенные для владельца файла. Если владелец процесса входит в группу файла, но не является владельцем файла, он получает права, определенные для группы файла. Если не имеет место ни то, ни другое, то процесс получает права доступа к файлу, определенные для "всех остальных".

    Новый файл по умолчанию получает идентификаторы владельца и группы по наследству от процесса, который его создал, а права доступа к нему - по умолчанию - исходя из маски прав доступа umask.

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

    Запуск приложения от имени владельца файла приложения

    Обычно эффективные идентификаторы владельца и группы процесса достаются процессу по наследству от процесса-родителя. Но в некоторых ситуациях необходимо запустить программу с правами, большими, нежели права запускающего ее пользователя. Например, вам надо изменить свой пароль. Для этого требуется осуществить запись в файл /etc/shadow. С другой стороны, нельзя давать каждому пользователю такое право: вдруг он поменяет не только свой пароль? Кто откажется сделать милый сюрприз коллеге? Как быть? Если вы подумали, что выход в том, чтобы все пароли менял только администратор, вы далеки от истины.

    Идея в том, чтобы право записи в /etc/shadow дать не конкретному пользователю, а программе passwd (как нам известно, пароль меняет именно эта программа). К сожалению, в UNIX нет механизма, который позволяет давать какие-либо права отдельному процессу или приложению. Поэтому право записи в /etc/shadow дали пользователю root (назначив его владельцем этого файла и разрешив запись в файл владельцу - вы помните, как это сделать с помощью chmod?), а программу passwd разрешили всем запускать от имени ее владельца - root.

    Это право (запускать программу от имени владельца) является специальным правом доступа к файлу, оно называется SUID (set User ID). Фактически, файл с установленным битом SUID, отвечающим за это право доступа, всегда запускается на выполнение с эффективным идентификатором владельца процесса, равным идентификатору владельца файла.

    Как мы помним, полный вид слова прав доступа таков:

    su sg  t   r  w  x  r   w  x  r   w  x

    Старшие три бита - SUID ( su ), SGID ( sg ) и sticky bit ( t ).

    Suid и Sgid

    Установить бит suid или sgid можно, указав chmod права доступа в числовом виде:

    chmod 4755 файл

    или в мнемоническом виде:

    chmod u+s файл

    В некоторых системах UNIX доступна только одна из этих двух форм.

    Бит установки эффективного группового идентификатора (SGID) при запуске файла на выполнение действует сходным с SUID образом: как и в случае бита SUID, установленный SGID вызывает присвоение процессу, исполняемый код которого содержится в запущенном файле, эффективного идентификатора группы, равного идентификатору группы этого файла.

    В выводе команды ls файлы с установленными битами SUID и SGID отличаются от прочих тем, что в поле, где обычно стоит "x" (бит выполняемости), оказывается символ "s":

    -r-xr-sr-x 1 roottty 10040 Nov 4 2002 /usr/sbin/wall
    -r-sr-sr-x 1 rootsys 22168 Nov 4 2002 /usr/bin/passwd

    Это означает, что присутствуют оба бита: и бит запускаемости, и бит SUID (или SGID, соответственно). Если попытаться установить бит SUID или SGID на файл, для которого в соответствующем праве доступа (владельца или группы) не будет бита запускаемости, то система не даст это сделать. Поскольку для каталога биты SUID и SGID имеют другое значение, то биты SUID/SGID и биты права поиска в каталоге могут быть установлены по отдельности. В выводе ls в правах доступа к каталогу при отсутствии права поиска и наличии битов SUID/SGID буква S в выводе прав доступа будет заглавной:

    dr-Sr-xr-x  2  root  other  512  May  10  01:48  enum
    -rw-r--r--  1  root  other  0    May  10  01:47  q

    Обратите внимание на права доступа к каталогу enum. Объяснение смысла SUID/SGID для каталога дано в лекции 6.

    Найти все файлы, у которых установлен бит SUID, можно с помощью команды

    find / -perm -u+s

    а файлы с установленным битом SGID - по команде

    find / -perm -g+s

    Чтобы не допустить взлома системы, относитесь внимательно к файлам, права доступа к которым разрешают запускать их от чужого имени. Появление таких файлов в системе может облегчить жизнь взломщику. Программа passwd, например, написана таким образом, что запускающий ее пользователь не сможет с ее помощью сделать ничего, кроме изменения собственного пароля. Поэтому ей можно доверить запускаться с правами пользователя root. Но где гарантия, что все остальные программы с установленным SUID такие же? Устанавливайте бит SUID только тем программам, которым доверяете на все сто!

    Появление новых файлов с <подозрительными> правами доступа может говорить о попытке взлома системы, поэтому при инсталляции некоторых ОС автоматически устанавливается простой сценарий, использующий вышеописанную команду поиска таких файлов для отслеживания добавленных за последние сутки файлов с установленным битом SUID. Например, во FreeBSD это делается в сценарии /etc/daily, ежедневно проверяющем состояние системы.

    Имеет смысл удостовериться в том, что все эти новые файлы появились по известной вам причине.

    Интерактивные и фоновые процессы

    Процесс в UNIX может быть интерактивным и фоновым. Процесс, который имеет доступ к вводу с терминала и к выводу на него, называется интерактивным (foreground). Таким процессом является почтовая программа mail, редактор текста vi и другие программы. Фоновый процесс не имеет доступа к вводу с терминала, и имеет условный доступ к выводу на терминал. Условие состоит в том, что вывод на терминал разрешен фоновому процессу, если терминал настроен для работы в режиме tostop . Эту настройку можно выполнить командой

    stty -tostop

    Обратная настройка выполняется командой

    stty tostop

    Если фоновый процесс пытается выводить что-либо на терминал, настроенный для работы в режиме tostop, то процессу посылается сигнал SIGSTOP. Процесс, получивший такой сигнал, останавливается (переводится в состояние STOPPED ).

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

    Для запуска фонового процесса из командного интерпретатора следует дать команду, завершив ее знаком "" (амперсэнд):

    команда 

    Можно запустить сборку пакета программ в фоновом режиме, и пока он собирается, выполнять другую работу:

    make all 

    Взаимодействие процессов

    Процессы взаимодействуют друг с другом, используя при этом разные механизмы. Процессы могут асинхронно или синхронно передавать друг другу данные и управление доступом к ресурсам системы.

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

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

    Перенаправление потоков

    Поток данных, связанный с процессом, может быть перенаправлен в файл или другой поток данных. Например, если требуется, чтобы программа find выдала список имен файлов в файл names, а не на терминал, следует выполнить команду

    find / -name "some_name" > names

    Символ правой угловой скобки > означает перенаправление выходного потока запущенной программы в файл. При использовании этой конструкции будет создан файл names ; если файл с таким именем уже существует, то он будет уничтожен и затем будет создан новый файл с этим именем и новым содержимым.

    Для добавления вывода программы в конец файла следует использовать конструкцию "две правые угловые скобки" >>

    find / -name "some_name" >> names

    В этом случае файл names будет создан, если он не существует, а если существует, выходной поток программы find добавится в конец файла.

    Можно перенаправить текст из файла во входной поток.

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

    mail пользователь@компьютер < файл_с_письмом

    Бывает необходимо отправить пользователям не совершенно одинаковые сообщения, а письма, в которых стандартный текст перемешан с личными обращениями и конкретными подробностями. Тогда на помощь приходит перенаправление потока посредством конструкции "документ здесь".

    Это дает возможность перенаправить ввод в процесс не из файла, а прямо из командной строки (или тела скрипта):

    mail пользователь@компьютер <<FINAL
    Дорогой(ая) $TARGETUSER,
    Вы превысили допустимый размер домашнего каталога на 
    $OVERSIZE килобайт. Удалите ненужные Вам файлы, 
    иначе это сделает робот!
    	Системный администратор
    FINAL

    Такой скрипт отправит по указанному адресу письмо, в котором вместо $TARGETUSER и $OVERSIZE будут подставлены имя и превышение лимита того пользователя, которому предназначается письмо. Естественно, этим переменным следует присвоить какое-то значение перед выполнением команды, но тот фрагмент скрипта, в котором это делается, вы с легкостью додумаете самостоятельно.

    Указание в тексте значков << показывает, что все, что следует непосредственно за ними до ближайшего символа-разделителя, является ограничителем текста. Символ-разделитель - это любой пустой символ: пробел, табуляция или конец строки. Все, что идет за ограничителем текста, передается во входной поток запущенного командой процесса вплоть до момента, когда в начале новой строки не встретится такой же ограничитель текста. Ограничитель может представлять собой любой набор непустых символов - неважно, просто ли это символ "точка", слово FINAL или что-то еще.

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

    ls -l | more

    Символ вертикальной черты "|" означает перенаправление выходного потока программы, команда вызова которой находится слева от этого символа, во входной поток программы, вызываемой справа.

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

    Например, для подсчета запущенных демонов httpd можно использовать такую конструкцию:

    ps -auxw | grep httpd | wc -l

    Программа ps выводит список всех процессов, запущенных в системе, grep выбирает из этого списка строки, в которых есть подстрока httpd, а wc с ключом l подсчитывает, сколько строк оказалось в ее входном потоке.

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

    Сигналы

    Процессы могут взаимодействовать, посылая друг другу сигналы. Список сигналов в Solaris ограничен сорока двумя сигналами, из которых наиболее употребительны сигналы TERM, KILL и HUP. В разных вариантах UNIX может быть разное количество сигналов, стандарт POSIX 1.1 определяет тридцать один сигнал. Каждый сигнал имеет свое мнемоническое обозначение и номер. В разных системах мнемонические обозначения остаются одинаковыми, а номер может быть разным.

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

    С помощью команды

    kill

    можно послать сигнал с номером номер_сигнала процессу с идентификатором PID:

    kill -номер_сигнала PID

    В некоторых системах UNIX есть возможность послать сигнал процессу с определенным именем посредством программы killall:

    killall -номер_сигнала имя_процесса

    В Solaris эта программа имеет другое значение, а именно выполняет отправку сигнала завершения всем активным процессам:

    killall

    А отправить сигнал процессам с определенным именем в Solaris следует командой pkill:

    pkill sendmail

    С помощью pkill можно отправлять сигнал завершения TERM процессу с тем или иным признаком, так что отправка сигнала процессу с определенным именем - не единственное умение pkill. Например,

    pkill -HUP -G other,daemon

    отправит сигнал HUP (SIGHUP) всем процессам, чья фактическая группа - other или daemon.

    В табл. 7.2 приведен список сигналов, определенный стандартом POSIX 1.1, а в табл. 7.3 - список сигналов, определенных в Solaris 9.

    Кроме команды pkill системный администратор может найти удобной команду pgrep, которая заменяет конструкцию

    ps -ef | grep команда

    В Solaris для получения того же результата можно ввести более короткую команду

    pgrep команда
    Сигналы POSIX 1.1
    Сигнал НомерЗначение
    SIGHUP 1 Разрыв связи с управляющим терминалом или управляющим процессом
    SIGINT 2 Прерывание с клавиатуры
    SIGQUIT 3 Сигнал выхода дан с клавиатуры
    SIGILL 4 Недопустимая инструкция
    SIGABRT 6 Сигнал abort получен от вызванной кем-то функции abort
    SIGFPE 8 exception: ошибка вычислений с плавающей запятой
    SIGKILL 9 Безусловное завершение процесса
    SIGSEGV 11 Неверный адрес памяти
    SIGPIPE 13 Запись в несуществующий канал
    SIGALRM 14 Сигнал timer от функции alarm
    SIGTERM 15 Завершение
    SIGUSR1 30,10,16первое значение для архитектур alpha и sparc, второе — для i386, третье — для mips. Определяется пользователем
    SIGUSR2 31,12,17 Определяется пользователем
    SIGCHLD2 20,17,18 Дочерний процесс остановлен или принудительно завершен
    SIGCONT1 19,18,25 Продолжить выполнение, если оно было остановлено
    SIGSTOP 17,19,23 Остановить процесс
    SIGTSTP 18,20,24 Останов введен с терминала
    SIGTTIN 21,21,26 Ввод с терминала для фонового процесса
    SIGTTOU 22,22,27 Вывод на терминала для фонового процесса
    Сигналы Solaris 9
    НазваниеЗнач.Действие поСобытие
    SIGHUP 1 завершение разрыв связи с терминалом
    SIGINT 2 завершение прерывание
    SIGQUIT 3 аварийное завершение (core) Quit (требование завершения)
    SIGILL 4 аварийное завершение (core) недопустимая команда процессора
    SIGTRAP 5 аварийное завершение (core) прерывание при трассировке или точка останова
    SIGABRT 6 аварийное завершение (core) аварийное принудительное завершение
    SIGEMT 7 аварийное завершение (core) прерывание эмуляции
    SIGFPE 8 аварийное завершение (core) arithmetic exception: ошибка вычислений с плавающей запятой
    SIGKILL 9 безусловное завершение требование безусловного завершения
    SIGBUS 10 аварийное завершение (core) ошибка шины
    SIGSEGV 11 аварийное завершение (core) ошибка сегментации (выход за пределы выделенной памяти)
    SIGSYS 12 аварийное завершение (core) неверный системный вызов
    SIGPIPE 13 завершение запись в несуществующий канал
    SIGALRM 14 завершение Сигнал timer от функции alarm
    SIGTERM 15 завершение завершение
    SIGUSR1 16 завершение программируемый сигнал 1
    SIGUSR2 17 завершение программируемый сигнал 2
    SIGCHLD 18 действия не выполняются изменение статуса дочернего процесса
    SIGPWR 19 действия не выполняются сбой питания или перезагрузка
    SIGWINCH 20 действия не выполняются изменение размера окна
    SIGURG 21 действия не выполняются состояние сокета (Urgent Socket Condition)
    SIGPOLL 22 завершение Pollable Event (см. streamio (7I) )
    SIGSTOP 23 остановка требование остановки
    SIGTSTP 24 остановка остановка ввода с терминала
    SIGCONT 25 действия не выполняются требование продолжения
    SIGTTIN 26 остановка ввода ввод с терминала для фонового процесса
    SIGTTOU 27 остановка вывода вывод на терминал для фонового процесса
    SIGVTALRM 28 завершение Virtual Timer Expired
    SIGPROF 29 завершение Profiling Timer Expired
    SIGXCPU 30 аварийное завершение (core) достижение лимита времени использования процессора (CPU time limit exceeded)
    SIGXFSZ 31 аварийное завершение (core) превышение допустимого размера файла – getrlimit (см. getrlimit (2) )
    SIGWAITING 32 действия не выполняются зарезервировано библиотекой потоков
    SIGLWP 33 действия не выполняются межпроцессный (LWP) сигнал – зарезервировано библиотекой потоков
    SIGFREEZE 34 действия не выполняются Check point Freeze
    SIGTHAW 35 действия не выполняются Check point Thaw
    SIGCANCEL 36 действия не выполняются сигнал отмены, зарезервировано библиотекой потоков
    SIGXRES 37 действия не выполняются выход за границу блока управления ресурсом
    SIGRTMIN * завершение первый сигнал реального времени
    (SIGRTMIN+1) * завершение второй сигнал реального времени
    (SIGRTMAX-1) * завершение предпоследний сигнал реального времени
    SIGRTMAX * завершение последний сигнал реального времени

    Каналы и сокеты

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

    Канал - это последовательность байт, используемая как однонаправленный поток ввода/вывода.

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

    Сокет - это объект, который используется для межпроцессных коммуникаций; он существует, пока какой-либо процесс хранит дескриптор, ссылающийся на него. Сокет создается системным вызовом socket, который возвращает его дескриптор. Имеется несколько типов сокетов, которые поддерживают различные возможности передачи данных.

    Для каждого процесса ядро хранит таблицу внутренних дескрипторов. По-английски эта таблица называется "descriptor table", и чтобы не путать ее с таблицей дескрипторов в файловой системе, мы называем внутреннюю таблицу дескрипторов, относящуюся к конкретному процессу, "таблицей внутренних дескрипторов". Слово "внутренних" подчеркивает то, что эти дескрипторы существуют только в пределах процесса, который пользуется ими для обращения к файлам. Эта таблица наследуется от родительского процесса, поэтому вместе с ней наследуется и доступ к объектам, на которые ссылаются дескрипторы (файлам, каналам, сокетам).

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

    Подробнее о сокетах можно прочесть в Как вы помните, такая запись означает, что следует обратиться к странице руководства в третьем разделе, т.е. дать команду man 3 socket ..

    Семафоры

    Семафоры - это механизм, который принято использовать для контроля доступа нескольких процессов к одному ресурсу. Есть несколько реализаций программного интерфейса (API), связанного с семафорами:

  • вариант System V IPC (inter-process communication);
  • BSD;
  • POSIX 1003.1b.
  • Семафор по сути - это переменная, в зависимости от значения которой доступ к тому или иному ресурсу разрешается или блокируется до его освобождения. Семафоры широко используются в Oracle. Чтобы настроить подсистему семафоров в Solaris (обеспечить достаточное количество семафоров в ядре), может потребоваться внести изменения в файл конфигурации ядра /etc/system. Для уточнения того, какие настройки требуются именно вашему программному обеспечению под Solaris, обратитесь к руководству по этому ПО.

    Для Oracle8i в Oracle8i Installation Guide Release 3 рекомендуются следующие начальные значения параметров:

  • set semsys:seminfo_semmni=100
  • set semsys:seminfo_semmsl=<10 + самое большое значение PROCESSES среди ваших БД>
  • set semsys:seminfo_semmns=<столько, сколько объяснено ниже>
  • set semsys:seminfo_semopm=100
  • set semsys:seminfo_semvmx=32767
  • Значение seminfo_semmns рекомендуется установить равным сумме параметров PROCESSES всех баз данных сервера, причем самый большой из них должен быть просуммирован с коэффициентом 2, плюс еще 10 на каждую базу данных.

    Узнать текущие значения параметров семафоров (Solaris) можно с помощью команды:

    sysdef | tail -25

    Текущие наборы семафоров в системе (Solaris) покажет команда:

    ipcs -sb

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

    ipcrm -s semsetID

    semsetID здесь означает идентификатор набора семафоров.

    Управление процессами

    Команды наблюдения за процессами

    Для просмотра текущего списка и состояния процессов следует использовать программу ps. Она выдает "мгновенный снимок" таблицы процессов, которые запущены в системе.

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

    ps -ef

    В системах BSD и System V программа ps имеет разные ключи, поэтому если вы переходите от одной системы к другой, надо помнить об этих различиях или обращаться к man ps.

    Разберем подробнее, какую информацию выдает программа ps:

    ps -ef | more
    UID	PID	PPID	C	STIME	TTY	TIME	CMD
    root	0	0	0	17:43:30	?	0:03	sched
    root	1	0	0	17:43:30	?	0:00	/etc/init -s
    root	2	0	0	17:43:30	?	0:00	pageout
    root	3	0	0	17:43:30	?	0:00	fsflush
    root	349	1	0	17:43:53	?	0:00	/usr/lib/saf/sac -t 300
    root	277	276	0	17:43:49	?	0:00	htt_server -port 9010 -syslog -message_locale C
    root	180	1	0	17:43:45	?	0:00	/usr/lib/autofs/automountd
    root	59	1	0	17:43:39	?	0:00	/usr/lib/sysevent/syseventd
    root	73	1	0	17:43:40	?	0:00	/usr/lib/picl/picld
    root	133	1	0	17:43:43	?	0:00	/usr/sbin/rpcbind
    root	229	1	0	17:43:48	?	0:00	/usr/lib/power/powerd
    root	172	1	0	17:43:44	?	0:00	/usr/lib/nfs/lockd
    root	156	1	0	17:43:44	?	0:00	/usr/sbin/inetd -s
    root	217	1	0	17:43:47	?	0:00	/usr/lib/lpsched
    daemon	168	1	0	17:43:44	?	0:00	/usr/lib/nfs/statd
    root	189	1	0	17:43:45	?	0:00	/usr/sbin/syslogd
    root	203	1	0	17:43:46	?	0:00	/usr/sbin/cron
    root	205	1	0	17:43:46	?	0:00	/usr/sbin/nscd
    root	343	1	0	17:43:53	?	0:00	/usr/sbin/vold
    root	240	1	0	17:43:48	?	0:00	/usr/lib/utmpd
    root	324	1	0	17:43:51	?	0:00	/usr/lib/snmp/snmpdx -y -c /etc/snmp/conf
    root	261	1	0	17:43:49	?	0:00	/usr/sadm/lib/smc/bin/smcboot
    root	355	329	0	17:43:56	?	0:00	/usr/dt/bin/dtlogin -daemon
    root	329	1	0	17:43:52	?	0:00	/usr/dt/bin/dtlogin -daemon
    root	262	261	0	17:43:49	?	0:00	/usr/sadm/lib/smc/bin/smcboot
    root	263	261	0	17:43:49	?	0:00	/usr/sadm/lib/smc/bin/smcboot
    root	354	1	0	17:43:55	?	0:00	/usr/lib/ssh/sshd
    root	338	1	0	17:43:52	?	0:00	/usr/lib/dmi/snmpXdmid -s sunny
    root	352	349	0	17:43:53	?	0:00	/usr/lib/saf/ttymon
    root	353	329	2	17:43:54	?	1:41	/usr/openwin/bin/Xsun :0 -nobanner -auth /var/dt/A:0-KtaiPa
    root	356	329	0	17:43:56	?	0:00	/usr/openwin/bin/fbconsole -d :0
    root	358	324	0	17:43:57	?	0:00	mibiisa -r -p 5248
    root	337	1	0	17:43:52	?	0:00	/usr/lib/dmi/dmispd

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

    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, точнее - см. команду pagesize.

    WCHAN - адрес события, ради которого процесс перешел в состояние сна; если поле пусто, процесс запущен.

    STIME - время запуска процесса, в часах, минутах и секундах, для запущенных более суток назад процессов указываются месяцы и дни.

    TTY - управляющий терминал (то же, что и терминальная группа), символ вопросительного знака "?" печатается для процесса без управляющего терминала.

    TIME - число минут и секунд, указывающее, сколько времени процесс отнял у процессора.

    CMD - команда, которой был запущен процесс.

    При указании ключа j выводятся дополнительные сведения:

    PGID - идентификатор лидера группы процессов.

    SID - идентификатор процесса - лидера сессии.

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

    LWP - идентификатор легковесного процесса.

    NLWP - число легковесных процессов для процесса.

    Завершившиеся процессы, код завершения которых не был востребован родительским процессом, помечаются как "defunct".

    Кроме программы ps в UNIX для получения информации о запущенных в данный момент процессах широко используется команда top:

    top
    last pid: 923; load averages: 4.56, 1.18, 0.50    17:54:22
    64 processes: 63 sleeping, 1 on cpu
    CPU states: 0.0% idle, 0.5% user, 99.5% kernel, 0.0% iowait, 0.0% swap
    Memory: 128M real, 18M free, 101M swap in use, 499M swap free
    
    PID	USERNAME	LWP	PRI	NICE	SIZE	RES	STATE	TIME	CPU 	COMMAND
    909	root 		1 	60 	0 	17M 	3340K 	sleep 	0:00 	0.92% 	pagein
    353	root		1	58	0	32M	16M	sleep	0:05	0.37% 	Xsun
    893	root 		1	49	0	2228K	1172K	cpu	0:00	0.15%	top
    753	root 		1 	49	0 	15M 	8112K 	sleep  	0:00 	0.13% 	dtterm
    911	root 		1 	59	0 	3352K 	752K 	sleep  	0:00 	0.03% 	sh
    912	root 		1 	49	0 	3360K 	600K 	sleep  	0:00 	0.03% 	sh
    894	root 		1 	59	0 	3064K 	1816K 	sleep  	0:00 	0.03% 	dtexec
    656	root 		5 	59	0 	22M  	10M 	sleep  	0:01 	0.02% 	dtwm
    648	root 		1 	59	0 	6644K 	2280K 	sleep  	0:00 	0.02% 	ttsession
    667	root 		1 	59	0 	1844K 	512K 	sleep  	0:00 	0.02% 	rpc.rstatd
    277	root 		29	59	0 	5612K 	1724K 	sleep  	0:00 	0.01% 	htt_server
    895	root 		1 	59	0 	3360K 	756K 	sleep  	0:00 	0.01% 	soffice
    720	root 		4 	49	0 	42M  	26M 	sleep  	0:03 	0.00% 	mozilla-bin
    649	root 		1 	49	0 	18M 	6288K 	sleep  	0:00 	0.00% 	dtsession
    760	root 		1 	49	0 	4752K 	1656K 	sleep  	0:00 	0.00% 	bash

    В Solaris для удобства получения информации о процессах с определенными именами есть команда

    pgrep имя

    Она является эквивалентом команды

    ps -ef | grep имя

    С помощью pargs можно посмотреть, какие аргументы переданы конкретному процессу и какая у него среда окружения:

    pargs 2793
    2793:  dtterm -name Run -xrm *menuBar: False -iconic -map 
    -e /usr/dt/bin/dtexec -open 
    argv[0]: dtterm
    argv[1]: -e
    argv[2]: /usr/dt/bin/dtexec
    argv[3]: -open
    argv[4]: -1
    argv[5]: -ttprocid
    argv[6]: 2.10fX-r 01 648 1289637086 1 1 0 192.168.5.33 5 
    sunny_105_1
    argv[7]: /export/home/mozilla_bin/sfw/bin/mozilla
    argv[8]: <NULL>
    argv[9]: -open
    argv[10]: -1
    argv[11]: -ttprocid
    argv[12]: 2.10fX-r 01 648 1289637086 1 1 0 192.168.5.33 5 
    sunny_105_1
    argv[13]: /export/home/mozilla_bin/sfw/bin/mozilla
    
    pargs -e 2793
    2793:  dtterm -name Run -xrm *menuBar: False -iconic -map -e /usr/dt/bin/dtexec -open 
    envp[0]: AB_CARDCATALOG=/usr/dt/share/answerbooks/ru_RU.UTF-8/ab_cardcatalog
    envp[1]: DISPLAY=:0.0
    envp[2]: DTAPPSEARCHPATH=//.dt/appmanager:/etc/dt/appconfig/appmanager/%L:/etc/dt/appconfig/appmanager/C:/usr/dt/appconfig/appmanager/%L:/usr/dt/appconfig/appmanager/C
    envp[3]: DTDATABASESEARCHPATH=//.dt/types,/etc/dt/appconfig/types/%L,/etc/dt/appconfig/types/C,/usr/dt/appconfig/types/%L,/usr/dt/appconfig/types/C

    Вывод команды pargs значительно сокращен, ключ -e требует вывести все содержимое среды окружения, а для графических программ типа dtterm, как в нашем примере, среда окружения весьма велика.

    Команда prstat позволяет в динамике, подобно команде top, отслеживать состояние процессов:

    prstat
    PID	USERNAME	SIZE	RSS	STATE	PRI	NICE	TIME	CPU	PROCESS/NLWP
    3576	root	3412K	868K	run	13	0	0:00:02	6,3%	find/1
    353	root	45M	19M	sleep	59	0	0:02:30	0,2%	Xsun/1
    753	root	15M	3620K	run	49	0	0:00:02	0,1%	dtterm/1
    3577	root	6640K	4108K	cpu0	49	0	0:00:00	0,1%	prstat/1
    205	root	2872K	624K	sleep	59	0	0:00:00	0,0%	nscd/18
    895	root	123M	21M	sleep	49	0	0:00:49	0,0%	soffice.bin/4
    667	root	1844K	488K	sleep	59	0	0:00:00	0,0%	rpc.rstatd/1
    217	root	5364K	536K	sleep	59	0	0:00:00	0,0%	lpsched/1
    324	root	4360K	196K	sleep	59	0	0:00:00	0,0%	snmpdx/1
    240	root	1100K	288K	sleep	59	0	0:00:00	0,0%	utmpd/1
    343	root	4892K	0K	sleep	59	0	0:00:00	0,0%	vold/3
    276	root	3240K	0K	sleep	59	0	0:00:00	0,0% 	htt/1
    633	root	3784K	0K	sleep	59	0	0:00:00 	0,0% 	sdt_shell/1
    657	root	16M	2496K	sleep	49	0	0:00:00 	0,0% 	dtfile/1
    203	root	4484K	568K	sleep	59	0	0:00:00 	0,0% 	cron/1
    189	root	5636K	1092K	sleep	59	0	0:00:00 	0,0% 	syslogd/13
    168	daemon	2444K	820K	sleep	59	0	0:00:00 	0,0% 	statd/1
    156	root 	2412K	688K	sleep	59	0 	0:00:00 	0,0% 	inetd/1
    172	root 	2160K	748K	sleep	59	0	0:00:00 	0,0% 	lockd/2
    229	root 	1348K	0K	sleep	59	0	0:00:00 	0,0% 	powerd/2
    133	root 	2212K	604K	sleep	59	0	0:00:00 	0,0% 	rpcbind/1
    Total: 61 processes, 161 lwps, load averages: 0,25, 0,17, 0,27

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

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

    В Solaris 9 появилась новая программа preap, которая позволяет убрать из системы "мнимые" (defunct), не до конца завершившиеся процессы, которые также носят название "зомби" (zombie). Эти процессы совершенно безобидны, так как это - самые обыкновенные процессы, код завершения которых не был принят родительскими процессами (например, в результате преждевременного завершения родительского процесса или иного сбоя). Несмотря на безобидность, они могут попусту занимать ресурсы системы, если таких процессов будет много. Обычно процессы-зомби автоматически уничтожаются процессом init, но если этого почему-либо не произошло, можно воспользоваться программой preap, которая примет код завершения процесса-зомби и даст ему упокоиться с миром.

    Команды управления процессами

    Основным средством управления процессами является команда kill, передающая процессу сигналы. Также можно использовать вышеописанные программы изменения приоритета процесса, прежде всего, команду nice, для управления приоритетом.

    Не следует путать команду kill с сигналом KILL - они просто тезки; с помощью одноименной команды можно передать процессу как сигнал KILL, так и любые другие сигналы.

    Будучи запущенной без ключей, она передает процессу сигнал TERM, требующий завершения процесса:

    kill [-ключи] номер_процесса

    Например, для завершения процесса sendmail можно выполнить следующие действия:

    :
    ps auxw | grep sendmail 
    root  2057 0.0 0.2 2664 444 ? S Jul08 3:24 sendmail: 
                                   accepting connections

    Как видно, sendmail имеет PID 2057. Посылаем сигнал, требующий завершения процесса:

    kill 2057

    И повторяем последнее действие для проверки (контрольный выстрел):

    kill 2057
    kill: (2057) - No such pid

    Сообщение No such pid говорит о том, что процесс уже завершился.

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

    Например, после изменений, внесенных в файл конфигурации /etc/inetd.conf, следует потребовать от демона inetd перечитать этот файл конфигурации.

    Это можно сделать, послав демону сигнал HUP (номер один), так как известно, что этот демон перечитывает файлы конфигурации, если получает сигнал с номером 1. Вначале надо узнать идентификатор процесса, которому будем посылать сигнал:

    ps -ef | grep inetd 
    root   156     1  0  17:43:44     ?   0:00  /usr/sbin/inetd -s
    root   4555  760  0  19:15:16  pts/5  0:00  grep inetd

    Мы видим два процесса, в строках информации о которых есть слово inetd. Первая строка, grep inetd - это тот самый процесс grep, который мы только что сами запустили. Программы ps и grep запустились одновременно, и ps показал "мгновенный снимок" таблицы процессов.

    Строка grep inetd в таком случае должна была бы показываться всегда, но на практике иногда мы не видим ее при запуске такой команды. Проведите эксперимент: возможно, что в вашей системе (это зависит от ее скорости и текущей загрузки) вы никогда не увидите строку grep или наоборот, будете ее видеть всегда.

    Это связано с тем, что физически запуск grep происходит чуть-чуть позже, чем ps, последняя может успеть завершиться раньше, чем grep начнется (ведь таблица процессов может оказаться маленькой и работы у ps будет мало). Тогда строки про grep в списке найденных процессов не будет.

    Теперь пошлем сигнал процессу inetd:

    kill -1 156

    Помните, не все демоны и не во всех системах по сигналу HUP перечитывают свой файл конфигурации. Прежде чем посылать демону сигналы, выясните, как он на них собирается реагировать: почитайте в man о его повадках.

    Владелец процесса может посылать сигналы своему процессу, но привилегированный пользователь ( root ) может отправить любой сигнал любому процессу.

    Посылка сигнала KILL (номер 9) вызывает безусловное немедленное завершение процесса:

    kill -9 PID

    или

    kill -KILL PID

    При выполнении команды kill лучше указывать мнемонические обозначения сигналов, а не числовые: в разных системах UNIX сигналы с одним и тем же числовым номером могут иметь разный смысл. Впрочем, можно смело руководствоваться вышеприведенными таблицами в разделе "сигналы" в отношении сигналов в Solaris.

    Для посылки сигнала нескольким процессам одновременно следует использовать программы pkill или killall (их подробное описание приведено в разделе "Сигналы" выше в этой лекции).

    При запуске процесса можно менять его базовый приоритет внутри класса планирования. Это возможно только для класса планирования разделения времени. Обычный пользователь может только понижать приоритет процесса, а привилегированный пользователь может менять NICE в обе стороны. Для этого используется команда nice, которая в разных системах имеет разные ключи и немного разный синтаксис.

    В Solaris она выглядит так:

    nice -n приращение команда

    например

    nice -n 5 ls

    Это "5" воспринимается как увеличение значения NICE на 5, т.е. снижение приоритета на 5 единиц. Пользователь root может дать команду вида nice -n -4 ls. Это будет воспринято как увеличение базового приоритета, т.е. уменьшение значения NICE на 4.

    Базовый приоритет уже запущенного процесса можно менять командой renice:

    renice -n приращение PID

    Команда renice может быть использована также для изменения приоритета группы процессов по разным признакам, для уточнения обратитесь к man renice.

    Работа с заданиями

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

    Более подробно о работе с заданиями говорится в лекции 9.

    Планирование запуска процессов

    Вынесете ли вы сегодня мусор или пойдете в магазин, поедете на заправку кормить своего железного коня бензином или просто ляжете спать пораньше - так или иначе, какое-нибудь дело вы сегодня сделаете. Дела, которые вы делаете, могут быть однократными (купить щенка) или регулярными (погулять с собакой). Может быть, "однократные" - не совсем точное прилагательное, потому что щенка вы можете купить и раз, и два, и еще много раз в жизни. Но вряд ли это дело можно назвать регулярным - не станете же вы раз в год ровно в полночь 13 марта покупать щенка.

    Все-таки станете? Вы не сатанист, часом?

    Еще приятнее запланировать выполнение нерегулярного или регулярного дела так, чтобы его делал кто-то другой. Например, сообщите сыну, что вы просите его завтра в полдень отправиться в клуб собаководов и купить там щеночка. Однократно. А потом (когда купит) скажите, что вы запланировали его (сына) прогулки с ним (щеночком) ежедневно - на годы вперед.

    Системный администратор, даже если у него нет сына и щеночка, тоже не лишен радостей планирования. Так, для планирования однократных действий в любом UNIX используется программа at, а для регулярных - crontab.

    at

    Для планирования однократного запуска задач в строго определенное время (точность - одна минута) используется программа at. Она создает и изменяет список задач для выполнения, размещая его в каталоге /var/spool/cron/atjobs/. В Solaris это именно такой каталог, в других системах местоположение очереди задач может быть иным. Список задач ежеминутно инспектируется демоном cron, который отвечает за своевременный запуск задач. Во многих других системах UNIX демон 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.

    Указание time без date означает выполнение задачи в текущие сутки, а если time сегодня уже прошло, - назавтра в указанное время.

    Программа at принимает список задач для выполнения во входной поток.

    at -l (или atq ) распечатывает список поставленных в очередь задач.

    at -r позволяет удалить задачу по идентификатору, который показывает at -l.

    В некоторых системах at -r называется atrm. В Solaris приемлемы оба варианта.

    Суперпользователь всегда может воспользоваться at.

    Обычному пользователю разрешается использовать at в случае, если его имя указано в файле /usr/lib/cron/at.allow. Если этого файла нет, то проверяется, нет ли имени пользователя в /usr/lib/cron/at.deny (если есть, ему запрещается использование at ). Если ни одного из этих двух файлов нет, пользоваться at разрешается только пользователям, которым назначена роль solaris.jobs.user (по умолчанию - root ). Если есть только файл /usr/lib/cron/at.deny и он пуст, то по умолчанию всем разрешено пользоваться at. В файлах at.deny и at.allow имена пользователей пишутся по одному в строке.

    Задания at и crontab заблокированного пользователя не запускаются - демон cron запустит задания только того пользователя, который имеет легальный доступ в систему в настоящее время, как отражено в файле /etc/shadow.

    Задание, запущенное на выполнение демоном cron, выполняется от имени пользователя, который поставил задание в очередь. Стандартный вывод и стандартный поток ошибок задания cron высылает почтой этому пользователю. Можно указать иное место для вывода информации с помощью ключа m команды at или с помощью параметра в файле crontab (см. ниже). Запланированные задачи выполняются в среде командного процессора /bin/sh без назначения управляющего терминала (т.е. вне терминальной группы, связанной с конкретным терминалом).

    Проведем небольшой эксперимент. Вначале убедимся, что каталог, где сохраняются задания at, пуст:

    #ls /var/spool/cron/atjobs/
    #

    Проверим время и дату:

    date
    Сбт 15 Май 2004 19:10:29

    Запланируем создание файла в корневом каталоге через две минуты:

    at 1912
    at> touch /tuition
    at> <Ctrl-D>
    commands will be executed using /sbin/sh
    job 1084633920.a at Сбт Май 15 19:12:00 2004

    В каталоге, где собираются задания в очереди на выполнение, появился новый файл:

    ls /var/spool/cron/atjobs/
    1084633920.a

    И по команде at -l мы получаем информацию о поставленном в очередь задании (указывается имя пользователя, инициировавшего задание, идентификатор задания, по которому его можно удалить, и время планируемого запуска):

    at -l
    user = root   1084633920.a  Сбт Май 15 19:12:00 2004

    Пока в корневом каталоге файла tuition нет:

    ls /
    bin 	devices 	lib 	opt 	tmp 	xfn
    boot 	etc 	lost+found 	platform	TT_DB
    cdrom 	export 	mnt 	proc 	usr
    core 	home 	net 	sbin 	var
    dev 	kernel 	nsmail 	test 	vol

    Почему? Да время еще не наступило:

    date
    Сбт 15 Май 2004 19:11:42

    Дожидаемся заданного времени и (о чудо!) файл /tuition появился! Смотрите:

    date
    Сбт 15 Май 2004 19:12:12
    
    ls /
    bin 	devices 	lib 	opt 	tmp 	vol
    boot 	etc 	lost+found 	platform 	TT_DB 	xfn
    cdrom 	export 	mnt 	proc 	tuition
    core 	home 	net 	sbin 	usr
    dev 	kernel 	nsmail 	test 	var

    cron

    Демон cron ежеминутно инспектирует таблицу запланированных задач и выполняет те задачи, время которых наступило (в Solaris - не более 100 задач в минуту). Программа at нужна, как видно из раздела "at" выше, для планирования однократных задач, а программа crontab служит для планирования периодически запускаемых процессов. Они подготавливают таблицу заданий для cron.

    У каждого пользователя есть своя таблица crontab. Ее можно отредактировать командой crontab -e. По этой команде вызывается текстовый редактор (обычно - vi ), а в качестве файла для редактирования окажется таблица crontab. Если вы раньше не задавали никаких периодических задач, файл будет пустым.

    Формат таблицы 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 - команда командному процессору, которую надо запустить (возможно, с аргументами).

    Каждое числовое поле в таблице может содержать число, несколько чисел через запятую, диапазон (начало и конец диапазона через дефис) или звездочку. Звездочка в соответствующем поле означает "каждую единицу времени", например в поле часов она означает "каждый час".

    Если в строке указаны определенное число месяца и определенный день недели, то для выполнения команды достаточно, чтобы наступило либо это число, либо этот день недели.

    Так, строка

    12 10 * * 0 rm -rf /var/log/*.[0-9]

    означает, что в 10:12 каждое воскресенье нужно удалять файлы *.[0-9] из /var/log.

    Однако, если было бы написано

    12 10 10 * 0 rm -rf /var/log/*.[0-9]

    то требовалось бы выполнять такое удаление "в 10:12 по воскресеньям и десятым числам", а не "в 10:12 десятого числа, если оно приходится на воскресенье".

    Как и в случае с at, команда запускается от имени владельца таблицы, в качестве командного процессора используется /bin/sh.

    В первых строках таблицы могут быть установлены переменные среды окружения. Наиболее полезной может оказаться переменная среды окружения PATH:

    PATH=/usr/bin:/usr/sbin:/usr/local/bin

    В ней можно задать каталоги, которые по умолчанию не входят в PATH.

    Кроме PATH можно установить переменные SHELL и HOME, а также MAILTO. По умолчанию HOME (домашний каталог) берется из /etc/passwd. Переменная LOGNAME устанавливается автоматически при запуске команды. Ей присваивается имя пользователя, от имени которого запускается команда. В BSD-системах она может называться USER, в Solaris есть обе переменные. LOGNAME и USER нельзя переопределить, HOME и SHELL - можно. Программа cron отправит сообщение владельцу таблицы crontab, если найдет повод это сделать (например, произошла ошибка выполнения команды). Если переменная MAILTO существует и ее значение отлично от пустой строки, то cron расценит это значение как имя адресата, которому надо послать письмо вместо пользователя, запланировавшего задачу. Если значение переменной MAILTO - пустая строка, то почта послана не будет. Установка любой переменной среды окружения в таблице crontab осуществляется так:

    имя_переменной = значение

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

    Для просмотра таблицы crontab используйте команду crontab -l, для удаления таблицы - crontab -r. Можно создать файл с таблицей crontab заранее и установить ее в систему командой

    crontab имя_файла_таблицы.

    Такая команда потенциально опасна: если раньше существовали какие-либо команды в таблице crontab, то они потеряются навсегда.

    Регулярно выполняемые системные скрипты

    В Solaris нет стандартно принятых по умолчанию регулярно выполняемых скриптов. Однако рекомендуется их создать и расположить в каталоге /var/admin/cron/ или /etc/periodic/.

    crontab -e 
    22 * * * * /var/admin/cron/hourly 
    22 22 * * * /var/admin/cron/daily 
    2 22 * * 0 /var/admin/cron/weekly 
    2 2 1 * * /var/admin/cron/monthly

    В скрипт hourly рекомендуется включать проверку состояния сетевого подсоединения ( ping ), проверку и при необходимости установку прав доступа к почтовым ящикам пользователей, проверку состояния основных демонов ( syslog, sendmail, named, sshd ) с помощью ps, архивацию и обновление файлов протоколов ( log rotation ), которые достаточно выросли за час (рекомендуемый размер файла протокола для архивации - 1-2 мегабайта, но вы можете выбрать иное, исходя из удобства последующего анализа этого файла).

    В скрипт daily включают проверку очереди сообщений (не слишком ли велика - запустите mailq ), синхронизацию системного времени ( ntpdate, rdate ).

    В скрипт weekly включают проверку свободного места на диске (если у вас это приходится делать чаще, чем раз в неделю, имеет смысл подумать о покупке нового диска, а может быть, и двух сразу), проверку файлов passwd, shadow, hosts.allow и hosts.deny, файлов конфигурации ftpd, sendmail, протоколов utmp и wtmp на предмет прав доступа и размера.

    Ежемесячный скрипт monthly обычно содержит архивацию и обновление тех файлов протоколов, которые растут медленно.

    Вы можете включить в эти скрипты свои задачи, которые являются специфическими для конкретной системы - проверку конфигурации smbd для файлового сервера samba, проверку дисковых квот пользователей, контроль появления свежих файлов с установленным битом SUID и так далее.

    Вернуться к учебному плану