Добавлен: 29.10.2018
Просмотров: 47993
Скачиваний: 190
86
Глава 1. Введение
пока возникнет какое-нибудь событие, а затем вызывает процедуру для его обработки.
Типичные события — это нажатие клавиши, перемещение мыши, нажатие кнопки мыши
или подключение USB-диска. Затем для обслуживания события, обновления экрана
и обновления внутреннего состояния программы вызываются обработчики. В итоге все
это приводит к несколько иному стилю программирования, чем в UNIX, но поскольку
эта книга посвящена функциям и структурам операционных систем, различные модели
программирования не будут вызывать у нас особого интереса.
Разумеется, в Windows также есть системные вызовы. В UNIX имеется практически
однозначная связь между системными вызовами (например, read) и библиотечными
процедурами (с той же read), используемыми для обращения к системным вызовам.
Иными словами, для каждого системного вызова обычно существует одна библиотеч-
ная процедура, чаще всего одноименная, вызываемая для обращения к нему (рис. 1.17).
При этом в стандарте POSIX имеется всего лишь около 100 процедурных вызовов.
В системе Windows ситуация совершенно иная. Начнем с того, что фактические си-
стемные вызовы и используемые для их выполнения библиотечные вызовы намеренно
разделены. Корпорацией Microsoft определен набор процедур, названный Win32 API
(Application Programming Interface — интерфейс прикладного программирования).
Предполагается, что программисты должны использовать его для доступа к службам
операционной системы. Этот интерфейс частично поддерживается всеми версиями
Windows, начиная с Windows 95. Отделяя API-интерфейс от фактических системных
вызовов, Microsoft поддерживает возможность со временем изменять существующие
системные вызовы (даже от одной версии к другой), сохраняя работоспособность уже
существующих программ. Фактически в основу Win32 вносится некоторая неоднознач-
ность, поскольку в самых последних версиях Windows содержится множество новых,
ранее недоступных системных вызовов. В этом разделе под Win32 будет пониматься
интерфейс, поддерживаемый всеми версиями Windows. Win32 обеспечивает совме-
стимость версий Windows.
Количество имеющихся в Win32 API вызовов велико — исчисляется тысячами. Более
того, наряду с тем, что многие из них действительно запускают системные вызовы,
существенная часть целиком выполняется в пространстве пользователя. Как след-
ствие, при работе с Windows становится невозможно понять, что является системным
вызовом (то есть выполняемым ядром), а что — просто вызовом библиотечной про-
цедуры в пространстве пользователя. Фактически то, что было системным вызовом
в одной версии Windows, может быть выполнено в пространстве пользователя в другой,
и наоборот. В этой книге при рассмотрении системных вызовов Windows мы будем
использовать там, где это необходимо, процедуры Win32, поскольку Microsoft гаран-
тирует, что с течением времени они не будут меняться. Но следует помнить, что не все
они действительно являются системными вызовами (то есть обрабатываются ядром).
В Win32 API имеется огромное число вызовов для управления окнами, геометриче-
скими фигурами, текстом, шрифтами, полосами прокрутки, диалоговыми окнами,
меню и другими составляющими графического пользовательского интерфейса. Если
графическая подсистема работает в памяти ядра (что справедливо для некоторых, но
не для всех версий Windows), то их можно отнести к системным вызовам, в противном
случае они являются просто библиотечными вызовами. Следует ли рассматривать
подобные вызовы в этой книге? Поскольку фактически они не относятся к функциям
операционной системы, мы решили, что не следует, даже учитывая то, что они могут
выполняться ядром. Тем, кто заинтересуется Win32 API, следует обратиться к одной
1.6. Системные вызовы
87
из многочисленных книг на эту тему (например, к книгам Hart, 1997; Rector and
Newcomer, 1997; Simon, 1997).
Даже простое перечисление на этих страницах всех вызовов Win32 API выходит за
рамки нашей тематики, поэтому мы ограничимся только теми, которые по своим
функциональным возможностям можно приблизительно сопоставить с системными
вызовами UNIX, перечисленными в табл. 1.1. Их список представлен в табл. 1.2.
Давайте коротко поговорим об этом списке. Вызов CreateProcess создает новый процесс.
В нем совмещается работа UNIX-вызовов fork и execve. Множество параметров этого вы-
зова определяют свойства вновь создаваемого процесса. В Windows отсутствует иерархия
процессов, присущая UNIX, поэтому понятия родительского и дочернего процессов здесь
не используются. После создания процесса процесс-создатель и вновь созданный про-
цесс становятся равноправными. Вызов WaitForSingleObject используется для ожидания
события. Ожидание может касаться множества возможных событий. Если в параметре
указан процесс, то вызывающая программа дожидается окончания конкретного процесса.
Завершение работы процесса происходит при использовании вызова ExitProcess.
Таблица 1.2. Вызовы Win32 API, приблизительно соответствующие вызовам UNIX,
перечисленным в табл. 1.1. Следует заметить, что в Windows имеется очень большое
количество других системных вызовов, большинство из которых не имеют
соответствий в UNIX
UNIX
Win32
Описание
fork
CreateProcess
Создает новый процесс
waitpid
WaitForSingleObject
Ожидает завершения процесса
execve
Нет
CreateProcess=fork+execve
exit
ExitProcess
Завершает выполнение процесса
open
CreateFile
Создает файл или открывает существующий файл
close
CloseHandle
Закрывает файл
read
ReadFile
Читает данные из файла
write
WriteFile
Записывает данные в файл
lseek
SetFilePointer
Перемещает указатель файла
stat
GetFileAttributesEx
Получает различные атрибуты файла
mkdir
CreateDirectory
Создает новый каталог
rmdir
RemoveDirectory
Удаляет пустой каталог
link
Нет
Win32 не поддерживает связи
unlink
DeleteFile
Удаляет существующий файл
mount
Нет
Win32 не поддерживает подключение к файловой системе
umount
Нет
Win32 не поддерживает подключение к файловой системе
chdir
SetCurrentDirectory
Изменяет рабочий каталог
chmod
Нет
Win32 не поддерживает защиту файла (хотя NT поддер-
живает)
kill
Нет
Win32 не поддерживает сигналы
time
GetLocalTime
Получает текущее время
Следующие шесть вызовов работают с файлами и функционально похожи на своих
UNIX-собратьев, хотя и отличаются от них в параметрах и деталях. Тем не менее файлы
могут быть открыты, закрыты, прочитаны и записаны практически так же, как в UNIX.
88
Глава 1. Введение
Вызовы SetFilePointer и GetFileAttributesEx устанавливают позицию указателя файла
и получают некоторые из атрибутов файла.
В Windows также имеются каталоги, которые создаются и удаляются вызовами
CreateDirectory и RemoveDirectory соответственно. Здесь тоже имеется понятие теку-
щего каталога, который устанавливается вызовом SetCurrentDirectory. Для получения
текущего времени используется вызов GetLocalTime.
В интерфейсе Win32 отсутствует поддержка связанных файлов, подключаемых фай-
ловых систем, защиты файлов, сигналов, поэтому отсутствуют и вызовы, соответству-
ющие тем, что есть в UNIX. Разумеется, в Win32 есть огромное количество других вы-
зовов, которых нет в UNIX, особенно относящихся к графическому пользовательскому
интерфейсу. Windows Vista имеет усовершенствованную систему защиты, а также
поддерживает связанные файлы
1
. А в Windows 7 и 8 добавлено еще больше свойств
и системных вызовов.
Пожалуй, о Win32 следует сделать еще одно замечание. Win32 не является полностью
единообразным и последовательным интерфейсом. Основной причиной этого стала
необходимость обеспечения обратной совместимости с предыдущим 16-битным ин-
терфейсом, который использовался в Windows 3.x.
1.7. Структура операционной системы
Теперь, когда мы увидели, как выглядят операционные системы снаружи (имеется
в виду интерфейс, доступный программисту), пришло время взглянуть на их вну-
треннее устройство. В следующих разделах мы рассмотрим шесть различных ис-
пользующихся (или использовавшихся ранее) структур, чтобы получить некоторое
представление о спектре их возможностей. Они ни в коем случае не представляют
собой исчерпывающую картину, но дают представление о некоторых конструкторских
решениях, опробованных на практике. Эти шесть конструкторских решений представ-
лены монолитными системами, многоуровневыми системами, микроядрами, клиент-
серверными системами, виртуальными машинами и экзоядрами.
1.7.1. Монолитные системы
Несомненно, такая организация операционной системы является самой распростра-
ненной. Здесь вся операционная система работает как единая программа в режиме
ядра. Операционная система написана в виде набора процедур, связанных вместе
в одну большую исполняемую программу. При использовании этой технологии каж-
дая процедура может свободно вызвать любую другую процедуру, если та выполняет
какое-нибудь полезное действие, в котором нуждается первая процедура. Возможность
вызвать любую нужную процедуру приводит к весьма высокой эффективности работы
системы, но наличие нескольких тысяч процедур, которые могут вызывать друг друга
сколь угодно часто, нередко делает ее громоздкой и непонятной. Кроме того, отказ
в любой из этих процедур приведет к аварии всей операционной системы.
1
Точнее, продуманная система защиты и поддержка связей файлов является свойством фай-
ловой системы NTFS, используемой в операционных системах ряда Windows NT, включая
Windows 2000, Windows XP, Windows Vista и Windows 7. — Примеч. ред.
1.7. Структура операционной системы
89
Для построения исполняемого файла монолитной системы необходимо сначала ском-
пилировать все отдельные процедуры (или файлы, содержащие процедуры), а затем
связать их вместе, воспользовавшись системным компоновщиком. Здесь, по существу,
полностью отсутствует сокрытие деталей реализации — каждая процедура видна любой
другой процедуре (в отличие от структуры, содержащей модули или пакеты, в которых
основная часть информации скрыта внутри модулей и за пределами модуля его про-
цедуры можно вызвать только через специально определяемые точки входа).
Тем не менее даже такие монолитные системы могут иметь некоторую структуру. Служ-
бы (системные вызовы), предоставляемые операционной системой, запрашиваются
путем помещения параметров в четко определенное место (например, в стек), а затем
выполняется инструкция trap. Эта инструкция переключает машину из пользова-
тельского режима в режим ядра и передает управление операционной системе (шаг 6
на рис. 1.17). Затем операционная система извлекает параметры и определяет, какой
системный вызов должен быть выполнен. После этого она перемещается по индексу
в таблице, которая в строке k содержит указатель на процедуру, выполняющую систем-
ный вызов k (шаг 7 на рис. 1.17).
Такая организация предполагает следующую базовую структуру операционной си-
стемы:
1. Основная программа, которая вызывает требуемую служебную процедуру.
2. Набор служебных процедур, выполняющих системные вызовы.
3. Набор вспомогательных процедур, содействующих работе служебных процедур.
В этой модели для каждого системного вызова имеется одна ответственная за него слу-
жебная процедура, которая его и выполняет. Вспомогательные процедуры выполняют
действия, необходимые нескольким служебным процедурам, в частности извлечение
данных из пользовательских программ. Таким образом, процедуры делятся на три
уровня (рис. 1.21).
Рис. 1.21. Простая структурированная модель монолитной системы
В дополнение к основной операционной системе, загружаемой во время запуска ком-
пьютера, многие операционные системы поддерживают загружаемые расширения,
в числе которых драйверы устройств ввода-вывода и файловые системы. Эти ком-
поненты загружаются по мере надобности. В UNIX они называются библиотеками
общего пользования. В Windows они называются DLL-библиотеками (Dynamic-Link
90
Глава 1. Введение
Libraries — динамически подключаемые библиотеки). Они находятся в файлах с расши-
рениями имен
.dll
, и в каталоге
C:\Windows\system32
на системе Windows их более 1000.
1.7.2. Многоуровневые системы
Обобщением подхода, показанного на рис. 1.21, является организация операционной
системы в виде иерархии уровней, каждый из которых является надстройкой над ниже-
лежащим уровнем. Первой системой, построенной таким образом, была система THE,
созданная в Technische Hogeschool Eindhoven в Голландии Э. Дейкстрой (E. W. Dijkstra)
и его студентами в 1968 году. Система THE была простой пакетной системой для
голландского компьютера Electrologica X8, имевшего память 32 K 27-разрядных слов.
Как показано в табл. 1.3, у системы было шесть уровней. Уровень 0 занимался рас-
пределением ресурса процессора (процессорного времени), переключением между
процессами при возникновении прерываний или истечении времени таймера. Над
уровнем 0 система состояла из последовательных процессов, каждый из которых мог
быть запрограммирован без учета того, что несколько процессов были запущены на
одном процессоре. Иными словами, уровень 0 обеспечивал основу многозадачности
центрального процессора.
Таблица 1.3. Структура операционной системы THE
Уровень
Функция
5
Оператор
4
Программы пользователя
3
Управление вводом-выводом
2
Связь оператора с процессом
1
Управление основной памятью и магнитным барабаном
0
Распределение ресурсов процессора и обеспечение многозадачного режима
Уровень 1 управлял памятью. Он выделял процессам пространство в основной памяти
и на магнитном барабане емкостью 512 К слов, который использовался для хранения
частей процесса (страниц), не умещавшихся в оперативной памяти. На уровнях выше
первого процессы не должны были беспокоиться о том, где именно они находятся,
в памяти или на барабане. Программное обеспечение уровня 1 обеспечивает помещение
страниц в память в то время, когда они необходимы, и удаление их из памяти, когда
они не нужны.
Уровень 2 управлял связью каждого процесса с консолью оператора (то есть с пользо-
вателем). Над этим уровнем каждый процесс фактически имел собственную консоль
оператора. Уровень 3 управлял устройствами ввода-вывода и буферизацией инфор-
мационных потоков в обоих направлениях. Над третьим уровнем каждый процесс
мог работать с абстрактными устройствами ввода-вывода, имеющими определенные
свойства. На уровне 4 работали пользовательские программы, которым не надо было
заботиться о процессах, памяти, консоли или управлении вводом-выводом. Процесс
системного оператора размещался на уровне 5.
Дальнейшее обобщение многоуровневой концепции было сделано в системе MULTICS.
Вместо уровней для описания MULTICS использовались серии концентрических ко-
лец, где внутренние кольца обладали более высокими привилегиями по отношению