
- •Глава 8
- •В.Г.Олифер, н.А.Олифер. Сетевые операционные системы. Учебное пособие.-сПб.:бхв-Петербург, 2006.-536с.
- •В.А.Шеховцов. Операційні системи. Підручник .-к.:Виканавча група внv. 2005. 576с.
- •Столлингс в. Операционные системы. М.: Вильямс, 2001. -672с.
- •Раздел 8 Взаимодействие с пользователем в операционных системах
- •8.1. Терминальный ввод-вывод
- •8.1.1. Организация терминального ввода-вывода
- •8.1.2. Терминальное ввод-вывод в unix и Linux
- •8.1.3. Терминальный ввод-вывод в Win32 арi
- •8.2. Командный интерфейс пользователя
- •8.2.1. Принципы работы командного интерпретатора
- •8.2.2. Перераспределение потоков ввода-вывода
- •8.3. Графический интерфейс пользователя
- •8.3.1. Интерфейс оконной и графической подсистемы Windows хр
- •Int winapi Winmain hinstance ih. Hinstance tp.
- •Int X. Int y. Int width, int height. Hwnd ph. Hmenu mh.
- •8.3.2. Система X Window
- •17.4. Процессы без взаимодействия с пользователем
- •17.4.1. Фоновые процессы на основе posix
- •17.4.2. Службы Windows xp
- •Void maino {
- •Void winapi svc_main(dword argc. Lptstr argv[]){
- •Void winapi svc_ctrlhandler(dword ctl) {
- •If (Ctl - Service_control_st0p) {
17.4. Процессы без взаимодействия с пользователем
Доныне мы рассматривали особенности организации взаимодействия с пользователем во время разработки интерактивных процессов. Еще одним видом такой организации является отсутствие взаимодействия, которое составляет основную характеристику фоновых процессов. Особенности их разработки являются темой этого раздела.
17.4.1. Фоновые процессы на основе posix
В этом разделе ознакомимся с особенностями разработки фоновых процессов в UNIX-совместимых системах. У них фоновые процессы по традиции называют демонами (daemons). К стандартным демонам Linux принадлежат: init, что является предком всех процессов системы; сгоп, что обеспечивает запуск программ в определенные моменты времени; sendmail, что обеспечивает отсылку и получение электронной почты и тому подобное.
Сессии и группы процессов
Каждый процесс принадлежит к группе процессов, которую помечают идентификатором группы процессов (pgid). Ядро может выполнять определенные действия над всеми процессами группы (например, отсылать им всем сигнал). Каждая группа может иметь лидера группы (у этого процесса идентификатор (pid) совпадает с идентификатором группы). Обычно процесс наследует идентификатор группы от своего предка, он может также явно изменить свою группу системным вызовом setpgrp().
Все процессы группы владеют одним и тем самым управляющим терминалом в конкретный момент времени, во время выполнения он может изменяться. В группы такого терминала может и совсем не быть - в этом случае ее процессы не будут получать сигналов от клавиатуры.
Несколько групп процессов объединяют в сессию. Для сессии задают идентификатор сессии (sid). Обычно процессы сессии отвечают набору процессов, которые создал пользователь во время интерактивного сеанса работы с системой.
Каждый керуючий терминал связан с сессией и с одной группой процессов этой сессии (такую группу называют еще интерактивной (foreground) группой, все другие называют фоновыми (background), с ними терминалы не связаны). Противоположное, как и для групп, не всегда верное - сессия может быть вообще не связана с управляющим терминалом, в этом случае у нее отсутствует интерактивная группа.
У каждой сессии есть лидер сессии, который отвечает за управление сессией и изоляцию ее от других; его идентификатор совпадает с идентификатором сессии. Если лидер сессии связан с терминалом, в случае выхода пользователя из системы этот процесс получает сигнал SIGHUP. Обычной реакцией на этот сигнал будет завершение работы процесса-лидера и всех процессов его сессии.
Когда лидер сессии с терминалом не связан, сигнала о выходе он не получит и сможет продлить выполнение по окончании сеанса работы. Это особенно важно для фоновых процессов.
Взаимосвязь между сессиями, группами процессов и управляющими терминалами показанная на рис. 8.3.
Рис.8.3 Сесии, группы процессов и управлдяющие терминалы
Создание новой сессии
Посмотрим, как пользователь может создать новую сессию и для чего это может понадобиться. Новую сессию создают с помощью системного вызова setsid(). Во время его выполнения
-
создают сессию, и текущий процесс становится её лидером;
-
создают новую группу процессов в рамках сессии, и текущий процесс становится ее лидером;
-
для текущего процесса разрывают связь с управляющим терминалом, если он был.
В итоге будет создана сессия без управляющего терминала и с одной фоновой группой внутри нее, что содержит на этот момент один процесс. Этим как текущий процесс, так и свои потомки будут защищены от сигналов из клавиатуры и сигнала о выходе из системы, то есть будут корректно переведены в фоновый режим. Именно так необходимо реализовывать фоновые процессы, которые предусматривают использовать независимо от наличия интерактивных сеансов пользователей в системе.
Отметим, что, если процесс уже является лидером группы процессов, вызов setsid() приведет к ошибке. Для того, чтобы ее избежать, рекомендуют сначала создать потомка процесса с помощью fork () (он гарантированно не будет лидером группы), в нем вызывать setsid(), а предка завершить.
Разработка фонового процесса
К фоновому процессу выставляют такие требования: он должен образовывать собственную сессию и группу процессов, не может принадлежать к ни одной из сессий и групп пользователя и иметь управляющий терминал.
Причины выдвижения этих требований приведены ниже.
Демон не может иметь управляющий терминал, поскольку не должен реагировать на прерывание в случае попыток введения-выведения с использованием такого терминала.
Демон должен быть лидером фоновой группы процессов и лидером новой сессии, чтобы он не мог получать сигналы (например, в случае нажатия Ctrl+С или выходу из системы).
После запуска демон закрывает все открыты файлы, особенно стандартные потоки ввода-вывода, поскольку они должны быть закрыты после выхода пользователя из системы, а демон должен продолжать работу и после этого.
Для того, чтобы придерживаться всех требований, в демоне нужно выполнить определенную последовательность действий.
-
Сразу после запуска процесс демона должен создать потомка:
if ((pid = forko) < 0) return -1;
Это нужно для того, чтобы сразу вернуться в командный процессор, выйдя из предка на шаге 2. Чтобы новый процесс гарантированно не мог стать лидером группы процессов, потому что он наследует эту группу от предка - это нужно позже для вызова setsid() на шаге 3.
2. После создания потомка предок должен завершить свою работу:
if (pid != 0) { // предок
printf ("демон стартовал из pid=%d\n". pid):
exit (0); }
3. Другие шаги происходят в потомке. В нем нужно выполнить определенную последовательность действий.
-
Создать новую сессию:
setsid();
Текущий процесс в результате вызова setsid(), как было сказано раньше, становится лидером новой сессии, лидером группы процессов и не имеет управляющего терминала. Главный смысл этого вызова - отключиться от управляющего терминала и потерять связь с текущей сессией, чтобы не получать никаких сигналов.
-
Изменить текущий каталог на корневой каталог системы или конкретный рабочий каталог демона:
chdir(“/"):
Если этого не сделать, текущий каталог демона всегда будет тем, из которого он запущен. Здесь есть риск, что текущим может оказаться каталог, который вмонтирован в файловую систему (в этом случае ее нельзя будет размонтировать, пока демон не закончит работу).
-
Возможно, закрыть все открыты файлы (файловые дескрипторы):
// закрыть заранее определеные дескрипторы
for (fd = 0: fd < 3; fd++) close(fd);
-
Перейти в режим ожидания (уже были рассмотрены разные способы задания ожидания в серверных процессах, самый простой способ - выполнить вызов pause () в цикле):
for (; :) pause();
После запуска демон будет лидером сессии (pid=sid), лидером группы процессов (pid=pgid) и не будет иметь управляющего терминала, а его предком станет init, поскольку непосредственный предок прекратил выполнение.