27.Какие циклические конструкции можно использовать в командной оболочке
BASH?
28.Как определяются функции использовать в командной оболочке BASH?
29.Что такое скрипт? Как запустить скрипт на выполнение?
30.Как передать аргументы скрипту? Чем опция отличается от аргумента?
31.Какая команда служит для распознавания опций?
32.Опишите специальные файлы командной оболочки BASH.
56
ГЛАВА 5. «ПРОЦЕСС» И «НИТЬ»
«В UNIX всё, что что-то делает - процесс».
Линус Торвальдс.
Из книги «Just for fun».
Функционирование любой ЭВМ заключается в выполнении строго определённой последовательности действий, называемой программой или
задачей. «Запустить программу на выполнение» означает загрузить саму программу (написанную на понятном для ЭВМ языке) и необходимые для неё данные в оперативную память и настроить процессор (значения его внутренних регистров) так, чтобы он стал выполнять инструкции, начиная с соответствующей ячейки оперативной памяти.
В мультизадачных системах, к которым относится и ОС Linux, в оперативную память может быть загружено сразу несколько программ. При этом, чередуя выполнение на одном процессоре инструкций то одной программы, то другой, ЭВМ создаёт «иллюзию» их одновременного выполнения. Правила, по которым чередуются инструкции разных программ, определяются операционной системой (подсистема планирования процессов
или нитей). При этом программы ничего не знают о существовании друг друга39.
В многопроцессорных (многоядерных) системах каждый процесс может выполняться на собственном процессоре (ядре). При этом каждый процессор, в свою очередь, может использоваться для выполнения нескольких (псевдо)параллельных процессов.
Для того чтобы операционная система могла определить, инструкцию какой программы следует выполнить следующей, должны выполняться два условия: во-первых, после выполнения очередной инструкции одной из программ процессор должен переключиться на операционную систему40, и, вовторых, операционная система должна обладать информацией обо всех «выполняющихся» программах (место в оперативной памяти, где располагаются инструкции программы; номер последней выполненной инструкции; значения регистров процессора после выполнения последней инструкции и т.п.). Информация обо всех выполняющихся программах хранится в оперативной памяти вместе с операционной системой.
Совокупность, состоящая из программы, описывающей её информации и дополнительных служебных данных, называется процессом. Информация о программе хранится в операционной системе в виде специальной структуры, называемой дескриптором процесса. Дескриптор процесса и дополнительная информация о программе вместе называются контекстом процесса.
39Следует помнить, что защита программ реализуется как на аппаратурном уровне (защищённый режим процессора), так и на уровне операционной системы.
40Напомним, что для ЭВМ операционная система является обычной программой, также загруженной в оперативную память.
57
5.1. Типы процессов
Все запущенные процессы условно (в зависимости от выполняемой ими функции) можно разделить на три типа: системные, процессы-демоны и прикладные процессы.
Системные процессы являются частью ядра и всегда расположены в оперативной памяти. Они часто не имеют соответствующих им программ в виде исполняемых файлов и всегда запускаются особым образом при загрузке ядра системы. Системными процессами являются, например: keventd (диспетчер системных событий), kswapd (диспетчер страничного замещения – своппинга), bdflush (диспетчер буферного кэша) и т.д.
Ксистемным процессам следует отнести процесс init, являющийся первым создаваемым процессом в системе и «прародителем» всех остальных процессов.
Процессы-демоны – это неинтерактивные (т.е. не взаимодействующие с пользователями) процессы, которые выполняются в фоновом режиме. Обычно они обеспечивают работу различных подсистем Linux, например, системы терминального доступа, системы печати, системы сетевого доступа и сетевых услуг и т.п.
Кприкладным относятся все остальные процессы, выполняющиеся в системе. Как правило, это процессы, порождённые в рамках пользовательского сеанса работы.
Пользовательские процессы могут выполняться как в интерактивном, так и в фоновом режиме, но в любом случае время их жизни (и выполнения) ограничено сеансом работы пользователя. При выходе из системы все
пользовательские процессы будут уничтожены. Интерактивные процессы связаны с определённым терминалом41 и через него взаимодействуют с пользователем. Фоновые процессы выполняются независимо от пользователя и
(псевдо)параллельно. Из фонового процесса можно создать процесс-демон, для чего ему следует отключиться от терминала42.
Запустить процесс на выполнение в фоновом режиме можно одним из следующих способов:
указать в конце командной строки символ амперсанд «&»;
приостановить выполнение интерактивного процесса (нажать комбинацию клавиш Ctrl+Z43), а затем командой bg запустить его на фоновое выполнение.
Чтобы посмотреть список всех фоновых задач, выполняющихся в рамках текущего сеанса пользователя, используется команда jobs, которая также выведет и текущее состояние каждой задачи.
41Напомним, что при запуске любой программы автоматически формируются три потока: ввода, вывода и вывода ошибок (в Cи их принято обозначать как stdin, stdout, stderr). По умолчанию все эти потоки связаны
стерминалом процесса.
42Это только одно из действий, которые необходимо выполнить, чтобы процесс стал полноценным «демоном».
43Следует помнить, что указанная комбинация клавиш для разных терминалов может быть разной. Здесь рассматриваются терминалы класса linux и xterm.
58
Чтобы перевести задачу, выполняющуюся в фоновом режиме, на передний план (в интерактивный режим), надо вызвать команду fg и передать ей в качестве аргумента номер фоновой задачи (из списка, выдаваемого командой jobs).
Любая фоновая задача будет приостановлена, если ей требуется определённый доступ к консоли (например, для ввода информации).
5.2. Состояние процесса
Каждый процесс в операционной системе Linux может находиться в одном из четырёх состояний: работоспособный, спящий (или ожидающий), остановленный и завершившийся.
Работоспособный (англ. runnable) процесс. Если процесс в текущий момент времени выполняет какие-либо действия или стоит в очереди на получение кванта времени на центральном процессоре, он называется работоспособным и обозначается символом R.
Ожидающий (спящий, англ. sleeping) процесс. Это состояние обозначается символом S и возникает после того, как процесс инициирует системную операцию, окончания которой он должен дождаться. К таким операциям относятся ввод-вывод, истечение заданного интервала времени, завершение дочернего процесса и т.д.
Остановленный (англ. stopped) процесс. Остановленный процесс не использует процессор и может быть полностью выгружен из оперативной памяти. Пользователь может остановить процесс, например, чтобы дать возможность другому процессу использовать больший объём оперативной памяти или быстрее завершиться. Обычный пользователь может остановить и продолжить только свой процесс, а суперпользователь – любой процесс в системе. Операционная система автоматически останавливает фоновые процессы в случае, когда они пытаются ввести данные с терминала. Это состояние обозначается символом Т.
Завершившийся («зомби», англ. «zombie») процесс. После завершения процесса информация о нём должна быть удалена операционной системой из таблицы процессов. В Linux такая операция возможна только после того, как родительский процесс выполнит системную операцию «ожидания завершения дочернего процесса» и прочитает статус возврата. До этих пор ОС вынуждена хранить в таблице процессов запись о завершившемся процессе, хотя он реально уже не существует и не потребляет ресурсы ЭВМ. Такое состояние процесса обозначается символом Z.
5.3. Атрибуты процесса
Любой процесс в операционной системе описывается дескриптором, содержащим ряд параметров, включая:
уникальный идентификатор процесса (PID);
идентификатор родительского процесса (PPID);
59
связанный с процессом терминал (TTY);
идентификаторы пользователя (UID, RUID, EUID, FSUID, SUID) и группы (GID, RGID, EGID, FSGID, SGID), от имени которых процесс выполняется и пытается осуществлять действия в рамках операционной системы или файловой системы;
номер группы процессов (GROUP);
идентификатор пользовательского сеанса (SESSION);
и т.д.44
Уникальный идентификатор процесса (PID) – это целое число,
позволяющее ядру системы различать процессы, т.е. своего рода «имя» процесса. По сути, PID – это номер ячейки в таблице дескрипторов процессов, выполняемых под управлением операционной системы. Когда создаётся новый процесс, ядро операционной системы использует следующую свободную запись в таблице дескрипторов. Если достигнут конец таблицы, то производится поиск свободной ячейки, начиная с начала таблицы. Когда процесс завершает свою работу, ядро освобождает занятый им идентификатор и соответствующий ему дескриптор.
Каждый процесс «запоминает» своего родителя в поле PPID. Зная значения поля PID и PPID, можно построить иерархию порождения процессов, начиная с самого первого процесса в системе (он обычно имеет PID = 0). Такая иерархия называется деревом процессов. Значение поля PPID играет особую роль при завершении процесса (см. ниже).
Как известно, каждому интерактивному процессу при создании назначаются потоки для: ввода информации, для её вывода и для вывода ошибок (stdin, stdout, stderr)45. Обычно все эти потоки указывают на один терминал, который называется «связанным» с процессом, и имя этого терминала (имя файла устройства) помещается в параметр TTY.
Все процессы в операционной системе запускаются каким-либо пользователем46. Идентификатор пользователя, запустившего процесс,
помещается в параметр «реальный идентификатор пользователя» (англ. UID
или RUID, Real UID). Часто возникает необходимость, чтобы процесс был запущен одним пользователем, а имел возможность получать доступ к ресурсам, принадлежащим другому пользователю. Контроль доступа к ресурсам системы осуществляется, исходя из значения поля «эффективный идентификатор пользователя» (англ. EUID, Effective UID). Примером ситуации выполнения действий от имени другого пользователя может служить смена пользовательского пароля с помощью команды passwd. Очевидно, что если база паролей (файлы /etc/passwd или /etc/shadow) будет доступна на запись кому угодно, тогда нельзя будет говорить ни о какой безопасности системы. Поэтому passwd настроена таким образом, что независимо от того, какой пользователь её выполняет, действия будут производиться всегда от имени
44На самом деле дескриптор процесса содержит значительно больше полей. Здесь приведены только те, которые используются в данном учебном пособии.
45О переопределении потоков ввода-вывода рассказывалось в п. 4.5.
46Считается, что загрузку операционной системы выполняет суперпользователь (администратор, root).
60