Переменная nextCommand
указывает на исходное (не разобранное) строковое представление следующей команды, которая должна быть выполнена, либо NULL
, если команда должна быть прочитана из входного файла, коим обычно является stdin
. Когда никакое задание не выполняется на переднем плане, ladsh
вызывает checkJobs()
для проверки выполняющихся фоновых заданий, читает следующую команду из входного файла, если nextCommand
равно NULL
, затем разбирает и выполняет следующую команду.
Когда выполняется задание переднего плана, ladsh1.с
ожидает завершения одного из процессов задания переднего плана. Когда все процессы задания переднего плана завершены, задание исключается из списка запущенных заданий и ladsh1.с
читает следующую команду, как описано выше.
10.8. Создание клонов
Хотя fork()
является традиционным способом создания новых процессов в Unix, Linux также предлагает системный вызов call()
, позволяющий процессам дублироваться с указанием ресурсов, которые родительский процесс должен разделять со своими потомками.
int clone(int flags);
Это ненамного отличается от fork()
. Единственная разница в наличии параметра flags
. Он должен быть установлен равным сигналу, который посылается родительскому процессу, когда потомок завершает работу (обычно это SIGCHLD
), объединенному логическим "или" с любым сочетанием перечисленных ниже флагов, определенных в <sched.h>
.
CLONE_VM |
Два процесса разделяют пространство виртуальной памяти (включая стек). |
CLONE_FS |
Разделяется информация файловой системы (такая как текущий каталог). |
CLONE_FILES |
Разделяются открытые файлы. |
CLONE_SIGHAND |
Обработчики сигналов разделяются двумя процессами. |
Когда ресурсы разделяется двумя процессами, оба они видят эти ресурсы идентично. Если указан CLONE_SIGHAND
, то когда один процесс заменяет обработчик определенного сигнала, оба начинают использовать новый обработчик (подробности об обработчиках сигналов представлены в главе 12). Когда используется CLONE_FILES
, разделяются не только наборы открытых файлов, но также текущие позиции в каждом файле. Значения возврата для clone()
те же самые, что и у fork()
.
Если для доставки родительскому процессу специфицирован сигнал, отличный от SIGCHLD
, то семейство функций wait()
по умолчанию не будет возвращать информацию об этих процессах. Если вы хотите получать информацию об этих процессах, как и в случае процессов, использующих нормальный механизм SIGCHLD
, то флаг __WCLONE
должен быть объединен с помощью логического "или" с параметром flags
вызова wait()
. Хотя такое поведение может показаться странным, оно обеспечивает большую гибкость. Если бы функция wait()
возвращала информацию о клонированных процессах, было бы сложнее построить стандартные библиотеки потоков вокруг clone()
, потому что wait()
должна возвращать информацию о других потоках, а также о дочерних процессах.
Хотя и не рекомендуется, чтобы приложения непосредственно использовали clone()
, доступно множество библиотек пространства пользователя, которые применяют clone()
и предоставляют полностью POSIX-совместимую реализацию потоков. Библиотека glibc
включает libthread
— наиболее популярную реализацию потоков. Теме программирования потоков POSIX посвящено несколько хороших книг, среди которых [4] и [23].
Глава 11
Простое управление файлами
Файлы — это наиболее распространенная абстракция ресурсов, используемая в мире Unix. Такие ресурсы, как память, дисковое пространство, устройства и каналы межпроцессного взаимодействия (IPC), могут быть представлены в виде файлов. Поддерживая унифицированную абстракцию для этих ресурсов, Unix уменьшает количество программных интерфейсов, которые обязан знать программист. Ниже перечислены ресурсы, доступные через файловые операции.
• Обычные файлы. Это то, о чем большинство пользователей компьютеров думают как о файлах. Они служат репозиториями данных, которые могут расти до необходимых размеров, и обеспечивают произвольный доступ. Файлы Unix являются байт-ориентированными — любое другое логическое представление является результатом программных преобразований; ядро ничего не знает о них.
• Каналы (pipes). Простейший механизм IPC в Unix. Обычно один процесс пишет информацию в канал в то время как другой читает из него. Каналы — это то, что командные оболочки используют для перенаправления ввода-вывода (например, ls -LR | grep notes
или ls | more
), и многие программы применяют каналы для того, чтобы передавать свой ввод программам, запущенным в виде их подпроцессов. Существуют два типа каналов: именованные и неименованные. Неименованные каналы создаются по мере необходимости и исчезают, как только читатель и писатель на концах канала закрывают его. Неименованные каналы называются так, потому что они не существуют в файловой системе и потому не имеют файловых имен[36]. Именованные каналы обладают именами файлов, и имя файла используется для того, чтобы позволить двум независимым процессам общаться через канал (подобно тому, как работают сокеты доменов Unix (см. главу 17)). Каналы также известны как FIFO (first-in-first-out), потому что данные упорядочены в манере "первым вошел — первым вышел".
• Каталоги. Специальные файлы, которые содержат списки файлов, хранящихся внутри них. Старые реализации Unix позволяли программам читать и писать их в той же манере, что и обычные файлы. Чтобы обеспечить большую степень абстракции, добавлен специальный набор системных вызовов для обеспечения манипуляций каталогами, хотя каталоги по-прежнему открываются и закрываются подобно обычным файлам. Эти функции рассматриваются в главе 14.
• Файлы устройств. Большинство физических устройств представлены в виде файлов. Есть два типа файлов устройств: блочные устройства и символьные устройства. Файлы блочных устройств представляют аппаратные устройства[37], которые не могут быть прочитаны побайтно; они должны читаться блоками определенного размера. В Linux блочные устройства принимают специальное управление от ядра[38]и могут содержать файловые системы[39]. Дисковые приводы, включая CD-ROM и RAM-диски, являются наиболее часто используемыми блочными устройствами. Символьные устройства могут быть прочитаны по одному символу за раз, и ядро не представляет для них никаких средств кэширования или упорядочивания. Модемы, терминалы, принтеры, звуковые карты и мыши — все это символьные устройства. Традиционно к каждому из них привязана некая сущность в каталоге /dev
, что позволяет пользовательским процессам получать доступ к ресурсам устройств как к файлам.
• Символические ссылки. Специальный тип файла, который содержит путь к другому файлу. Когда открывается символическая ссылка, система распознает ее как ссылку, читает ее значение и открывает файл, на который она ссылается, вместо самой ссылки. Когда используется значение, сохраняемое в символической ссылке, говорят, что система следует по ссылке. Если не указано другое, предполагается, что системные вызовы следуют по ссылкам, которые переданы им.
36
В среде Linux файловая система /proc
включает информацию о каждом файле, открытом в системе в данный момент. Хотя это значит, что неименованные каналы могут быть найдены в файловой системе, все же они не имеют постоянных имен, потому что исчезают при завершении процесса, использующего их.
37
Не все блочные устройства представляют реальное оборудование. Более правильное описание блочных устройств — это нечто, на чем может располагаться файловая система; блочное устройство обратной связи (loopback block device) отображает на обычный файл логическое блочное устройство, что позволяет файлам содержать в себе целые файловые системы.
39
Это отличается от ряда систем, которые способны монтировать файловые системы как на символьных устройствах, так и на блочных.