Распределение оперативной памяти в MS-DOS

MS-DOS – это однопрограммная ОС, она предназначена для выполнения только одного вычислительного процесса. Поэтому распределение памяти в ней построено по самой простой схеме, рассмотренной выше.

В IBM PC использовался 16-разрядный микропроцессор i18088, который за счет введения сегментного способа адресации позволял адресоваться к памяти объе­мом до 1 Мбайт. В последующих ПК (IBM PC AT, AT386 и др.) было приня­то решение поддерживать совместимость с первыми, поэтому при работе с DOS прежде всего рассматривают первый мегабайт. Вся эта память разделялась на не­сколько областей, что проиллюстрировано на рис. 1.10.

В состав MS-DOS входят следую­щие основные компоненты:

• Базовая подсистема ввода/вывода – BIOS (base input-output system), вклю­чающая в себя помимо программы тестирования ПК (POST) обработчики прерываний (драйверы), расположенные в постоянном запоминающем уст­ройстве. В конечном итоге, почти все остальные модули MS-DOS обращают­ся к BIOS. Если и не напрямую, то через модули более высокого уровня иерархии.

• Модуль расширения BIOS – файл IO.SYS.

• Основной, базовый модуль обработки прерываний DOS – файл MSDOS.SYS. Именно этот модуль в основном реализует работу с файловой системой.

• Командный процессор (интерпретатор команд) – файл COMMAND.СОМ.

• Утилиты и драйверы, расширяющие возможности системы.

• Программа загрузки MS-DOS – загрузочная запись (boot record).

Вся память в соответствии с архитектурой IBM PC условно может быть разбита на три части.

В самых младших адресах памяти (первые 1024 ячейки) размещается таблица векторов прерываний. Это связано с аппаратной реализацией процессора i8088, на котором была реализована ПК. В последующих процессорах (начиная с i80286) адрес таблицы прерываний определяется через содержимое соответст­вующего регистра, но для обеспечения полной совместимости с первым процес­сором при включении или аппаратном сбросе в этот регистр заносятся нули.

Вторая часть памяти отводится для размещения программных модулей самой MS-DOS и для программ пользователя. Эта область памяти называется Conventional Memory (основная, стандартная память).

Третья часть адресного пространства отведена для постоянных запо­минающих устройств и функционирования некоторых устройств ввода/вывода. Эта область памяти получила название UMA (upper memory areas – область верхней памяти).

В младших адресах основной памяти размещается то, что можно назвать ядром этой ОС – системные переменные, основные программные модули, блоки дан­ных для буферирования операций ввода/вывода. Для управления устройствами, драйверы которых не входят в базовую подсистему ввода/вывода, загружают­ся так называемые загружаемые (или инсталлируемые) драйверы. Перечень ин­сталлируемых драйверов определяется специальным конфигурационным файлом CONFIG.SYS.

Память с адресами, большими чем 10FFFFh, может быть использована в DOS-программах при выполнении их на микропроцессорах, имеющих такую возмож­ность. Но для этого с помощью специаль­ных драйверов необходимо переключать процессор в другой режим работы, при котором он сможет использовать адреса выше 10FFFFh. Широкое распростране­ние получили две основные спецификации: XMS (extended memory specification) и EMS (expanded memory specification).

Для того чтобы предоставить больше памяти программам пользователя, в MS-DOS применено то же решение, что и во многих других простейших ОС – командный процессор COMMAND.СОМ сделан состоящим из двух частей. Первая часть явля­ется резидентной, она размещается в области ядра. Вторая часть – транзитная; она размещается в области старших адресов раздела памяти, выделяемой для программ пользователя. И если программа пользователя перекрывает собой об­ласть, в которой была расположена транзитная часть командного процессора, то последний при необходимости восстанавливает в памяти свою транзитную часть, поскольку после выполнения программы она возвращает управление резидент­ной части COMMAND.COM.

Поскольку размер основной памяти (conventional memory) относительно неболь­шой, то очень часто системы программирования реализуют оверлейные структу­ры. Для этого в MS-DOS есть специальные вызовы.

1.7.2. Распределение оперативной памяти
в Microsoft Windows 95/98

С точки зрения базовой архитектуры ОС Windows 95/98 они обе являются 32-разрядными, многопотоковыми ОС с вытесняющей многозадачностью. Основ­ной пользовательский интерфейс этих ОС – графический.

Для своей загрузки они используют операционную систему MS‑DOS 7.0 (MS-DOS 98). Распределение памяти в MS-DOS 7.0 такое же, как и в предыдущих версиях DOS. Однако при загрузке GUI-интерфейса перед загрузкой ядра Win­dows 95/98 процессор переключается в защищенный режим работы и начинает распределять память уже с помощью страничного механизма.

Младшие адреса виртуального адресного пространства совместно используются всеми процессами. Это сделано для обеспечения совместимости с драйверами устройств реального режима, резидентными программами и некоторыми 16-раз­рядными программами Windows. Безусловно, это плохое решение с точки зре­ния надежности, поскольку оно приводит к тому, что любой процесс может непреднамеренно (или же, наоборот, специально) испортить компоненты, нахо­дящиеся в этих адресах.

В Windows 95/98 каждая 32-разрядная прикладная программа выполняется в сво­ем собственном адресном пространстве, но все они используют совместно один и тот же 32-разрядный системный код. Доступ к чужим адресным пространствам в принципе возможен. Другими словами, виртуальные адресные пространства не используют всех аппаратных средств защиты, заложенных в микропроцессор.

Системный код Windows 95 размещается выше границы 2 Гбайт. В пространстве с отметками 2 и 3 Гбайт находятся системные библиотеки DLL (dynamic link library, динамически загружаемый библиотечный модуль), используемые несколькими программами. В 32-битовых микропроцессорах семейства i80х86 имеются четыре уровня защиты, именуемые кольцами с номерами от 0 до 3. Кольцо с номером 0 является наиболее привилегированным, то есть максимально защищенным. Компоненты системы Windows 95, относящиеся к кольцу 0, отображаются на виртуальное адресное пространство между 3 и 4 Гбайт. К этим компонентам относятся собственно ядро Windows, подсистема управле­ния виртуальными машинами, модули файловой системы и виртуальные драй­веры (VxD).

Область памяти между 2 и 4 Гбайт адресного пространства каждой 32-разрядной прикладной программы совместно используется всеми 32-разрядными приклад­ными программами.

В области между 2 и 3 Гбайт также находятся все запускаемые 16‑разрядные прикладные программы Windows. С целью обеспечения совместимости эти про­граммы выполняются в совместно используемом адресном пространстве, где они могут испортить друг друга так же, как и в Windows 3.х.

Адреса памяти ниже 4 Мбайт также отображаются в адресное пространство каж­дой прикладной программы и совместно используются всеми процессами. Бла­годаря этому становится возможной совместимость с существующими драйвера­ми реального режима, которым необходим доступ к этим адресам. Это делает еще одну область памяти незащищенной от случайной записи.

Модель распределения памяти можно проиллюстрировать с помощью рис. 1.11.

Рис. 1.11. Модель памяти ОС Windows 95/98

Минимально допустимый объем оперативной памяти, начиная с которого ОС Windows 95 может функционировать, равен 4 Мбайт, однако при таком объеме пробуксовка столь велика, что практически работать нельзя.

1.7.3. Распределение оперативной памяти
в Microsoft Windows NT

Схема распределения возможного виртуального адресного пространства в системах Windows NT отличается от модели памяти Windows 95/98. Прежде всего, в отличие от Windows 95/98 в гораздо большей степени используется ряд серьезных аппарат­ных средств защиты, имеющихся в микропроцессорах, а также применено прин­ципиально другое логическое распределение адресного пространства.

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

Во-вторых, остальные программные модули самой операционной системы, ко­торые выступают как серверные процессы по отношению к прикладным про­граммам (клиентам), функционируют также в своем собственном системном виртуальном адресном пространстве, невидимом для прикладных процессов.

Ло­гическое распределение адресных пространств приведено на рис. 1.12.

Прикладным программам выделяется 2 Гбайт локального (собственного) линей­ного (неструктурированного) адресного пространства от границы 64 Кбайт до 2 Гбайт (первые 64 Кбайт полностью недоступны). Прикладные программы изо­лированы друг от друга, хотя могут общаться через буфер обмена (clipboard), ме­ханизмы DDE (Dynamic Data Exchange, механизм динамического обмена данными) и OLE (Object Linking and Embedding, механизм связи и внедрения объектов).

В верхней части каждой 2-гигабайтной области прикладной прог­раммы разме­щен код системных DLL кольца 3, который выполняет перенаправление вызовов в совершенно изолированное адресное пространство, где содержится уже собст­венно системный код. Этот системный код, выступающий как сервер-процесс (server process), проверяет значения параметров, исполняет запрошенную функ­цию и пересылает результаты назад в адресное пространство прикладной про­граммы. Хотя сервер-процесс сам по себе остается процессом прикладного уровня, он полностью защищен от вызывающей его прикладной программы и изолиро­ван от нее.

Между отметками 2 и 4 Гбайт расположены низкоуровневые системные компо­ненты Windows NT кольца 0, в том числе ядро, планировщик потоков и диспетчер виртуальной памяти.

Процессами выделения памяти, ее резервирования, освобождения и подкачки управляет диспетчер виртуальной памяти Windows NT (Windows NT virtual memory manager, VMM). В своей работе этот компонент реализует сложную стратегию учета требований к коду и данным процесса для минимизации досту­па к диску, поскольку реализация виртуальной памяти часто приводит к боль­шому количеству дисковых операций.

Каждая виртуальная страница памяти, отображаемая на физическую страницу, переносится в так называемый страничный фрейм (page frame). Прежде чем код или данные можно будет переместить с диска в память, диспетчер виртуальной памяти (модуль VMM) должен найти или создать свободный страничный фрейм или фрейм, заполненный нулями. Заполнение страниц нулями пред­ставляет собой одно из требований стандарта на системы безопасности уровня С2, принятого правительством США. Страничные фреймы должны заполняться нулями для того, чтобы исключить возможность использования их предыдущего содержимого другими процессами. Чтобы фрейм можно было освободить, необ­ходимо скопировать на диск изменения в его странице данных, и только после этого фрейм можно будет повторно использовать. Программы, как правило, не меняют страницы кода. Страницы кода, в которые программы не внесли измене­ний, можно удалить.

Диспетчер виртуальной памяти может быстро и относительно легко удовлетво­рить программные прерывания типа «ошибка страницы» (page fault). Что каса­ется аппаратных прерываний типа «ошибка страницы», то они приводят к подкачке (paging), которая снижает производительность системы.

Когда процесс использует код или данные, находящиеся в физической памяти, система резервирует место для этой страницы в файле подкачки Pagefile.sys на диске. Это делается с расчетом на тот случай, что данные потребуется выгрузить на диск. Файл Pagefile.sys представляет собой зарезервированный блок дисково­го пространства, который используется для выгрузки страниц, помеченных как «грязные», при необходимости освобождения физической памяти. Этот файл может быть как непрерывным, так и фрагментированным; он может быть расположен на системном диске либо на любом другом и даже на несколь­ких дисках. Размер этого страничного файла ограничивает объем данных, кото­рые могут храниться во внешней памяти при использовании механизмов вирту­альной памяти. По умолчанию размер файла подкачки устанавливается равным объему физической памяти плюс 12 Мбайт, однако пользователь имеет возмож­ность изменить его размер по своему усмотрению. Проблема нехватки виртуаль­ной памяти часто может быть решена за счет увеличения размера файла подкачки.

В системах Windows NT 4.0 объекты, создаваемые и используемые приложения­ми и операционной системой, хранятся в так называемых пулах памяти (memory pools). Доступ к этим пулам может быть получен только в привилегированном режиме работы процессора, в котором работают компоненты операционной сис­темы. Поэтому для того чтобы объекты, хранящиеся в пулах, стали видимы задачам приложений, эти задачи должны переключиться в привилегированный режим.

Перемещаемый или нерезидентный пул (paged pool) содержит объекты, которые могут быть при необходимости выгружены на диск. Неперемещаемый или рези­дентный пул (nonpaged pool) содержит объекты, которые должны постоянно на­ходиться в памяти. В частности, к такого рода объектам относятся структуры данных, используемые процедурами обработки прерываний, а также структуры, используемые для предотвращения конфликтов в мультипроцессорных системах.

Исходный размер пулов определяется объемом физической памяти, доступной Windows NT. Впоследствии размер пула устанавливается динамически, и в зави­симости от работающих в системе приложений и сервисов будет изменяться в широком диапазоне.

Вся виртуальная память в Windows NT подразделяется на классы: зарезервиро­ванную (reserved), выделенную (committed) и доступную (available),

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

• Память выделена, если диспетчер VMM резервирует для нее место в файле Pagefile.sys на тот случай, когда потребуется выгрузить содержимое памяти на диск. Объем выделенной памяти процесса характеризует фактически по­требляемый им объем памяти. Выделенная память ограничивается размером файла подкачки. Предельный объем выделенной памяти в системе (commit limit) определяется тем, какой объем памяти можно выделить процессам без увеличения размеров файла подкачки. Если в системе имеется достаточный объем дискового пространства, то файл подкачки может быть увеличен и тем самым будет расширен предельный объем выделенной памяти.

Вся память, которая не является ни выделенной, ни зарезервированной, явля­ется доступной. К доступной относится свободная память, обнуленная память (освобожденная и заполненная нулями), а также память, находящаяся в списке ожидания (standby list), которая была удалена из рабочего набора процесса, но может быть затребована вновь.

2. Управление Вводом/выводом

2.1. Основные понятия и концепции организации
ввода/вывода в ОС

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

Поэтому самым главным является следующий принцип: любые операции по управлению вводом/выводом объявляются привилегированными и могут вы­полняться только кодом самой ОС. Для обеспечения этого принципа в большин­стве процессоров даже вводятся режимы пользователя и супервизора. Как пра­вило, в режиме супервизора выполнение команд ввода/вывода разрешено, а в пользовательском режиме – запрещено. Использование команд ввода/вывода в пользовательском режиме вызывает исключение (вид внутреннего прерывания), и управление через механизм прерываний передается коду ОС. Хотя возможны и более сложные системы, в которых в ряде случаев пользовательским программам разрешено непосредст­венное выполнение команд ввода/вывода.

В мультипрограммных ОС одним из основных видов ресурсов являются устройства ввода/вывода и соответствующее программное обеспечение, с помощью которого осуществляется управление обменом данными между внешними устройствами и оперативной памятью. Помимо разделяемых устройств ввода/вывода (эти устройства допускают разделение посредством ме­ханизма доступа) существуют неразделяемые устройства. Примерами разделяе­мого устройства могут служить накопитель на магнитных дисках, устройство для чтения компакт-дисков. Это устройства с прямым доступом. Примеры не­разделяемых устройств – принтер, накопитель на магнитных лентах. Это уст­ройства с последовательным доступом. Операционные системы должны управ­лять и теми и другими устройствами, предоставляя возможность параллельно выполняющимся задачам использовать различные устройства ввода/вывода.

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

1. Необходимость разрешать возможные конфликты доступа к устройствам ввода/вывода. Например, две параллельно выполняющиеся программы пыта­ются вывести на печать результаты своей работы. Если не предусмотреть внешнее управление устройством печати, то в результате мы можем получить абсолютно нечитаемый текст, так как каждая программа будет время от вре­мени выводить свои данные, которые будут перемежаться данными другой программы. Другой пример: ситуация, когда одной программе необходимо прочитать данные с некоторого сектора магнитного диска, а другой – запи­сать результаты в другой сектор того же накопителя. Если операции вво­да/вывода не будут отслеживаться каким-то третьим (внешним) процессом-арбитром, то после позиционирования магнитной головки для первого запро­са может тут же появиться команда позиционирования головки для второй задачи, и обе операции ввода/вывода не смогут быть выполнены корректно.

2. Желание увеличить эффективность использования этих ресурсов. Например, у накопителя на магнитных дисках время подвода головки чтения/записи к необходимой дорожке и обращение к определенному сектору может значи­тельно (до тысячи раз) превышать время пересылки данных. В результате, если задачи по очереди обращаются к цилиндрам, далеко отстоящим друг от друга, то полезная работа, выполняемая накопителем, может быть существен­но снижена.

3. Ошибки в программах ввода/вывода могут привести к краху всех вычисли­тельных процессов, ибо таких часть операций осуществляется для самой операционной системы. В ряде ОС системный ввод/вывод имеет существен­но более высокие привилегии, чем ввод/вывод задач пользователя. Поэтому системный код, управляющий операциями ввода/вывода, очень тщательно отлаживается и оптимизируется для повышения надежности вычислений и эффективности использования оборудования.

Итак, управление вводом/выводом осуществляется операционной системой, компонентом, который чаще всего называют супервизором ввода/вывода. В пере­чень основных задач, возлагаемых на супервизор, входят следующие:

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

• супервизор ввода/вывода вызывает соответствующие распределители каналов и контроллеров, планирует ввод/вывод (определяет очередность предостав­ления устройств ввода/вывода задачам, затребовавшим их). Запрос на ввод/вывод либо тут же выполняется, либо ставится в очередь на выполнение;

• супервизор ввода/вывода инициирует операции ввода/вывода (передает управ­ление соответствующим драйверам) и в случае управления вводом/выводом с использованием прерываний предоставляет процессор диспетчеру задач, с тем чтобы передать его первой задаче, стоящей в очереди на выполнение;

• при получении сигналов прерываний от устройств ввода/вывода супервизор идентифицирует их и передает управление соответствующей про­грамме обработки прерывания;

• супервизор ввода/вывода осуществляет передачу сообщений об ошибках, если таковые происходят в процессе управления операциями ввода/вывода;

• супервизор ввода/вывода посылает сообщения о завершении операции вво­да/вывода запросившему эту операцию процессу и снимает его с состояния ожидания ввода/вывода, если процесс ожидал завершения операции.

Таким образом, прикладные программы (а в общем случае – все обрабатываю­щие программы) не могут непосредственно связываться с устройствами ввода/вывода независимо от использования устройств (монопольно или совместно). Установив соответствующие значения параметров в запросе на ввод/вывод, опре­деляющих требуемую операцию и количество потребляемых ресурсов, они могут передать управление супервизору ввода/вывода, который и запускает необходи­мые логические и физические операции.

2.2. Режимы управления вводом/выводом

Как известно, имеются два основных режима ввода/вывода: режим обмена с опро­сом готовности устройства ввода/вывода и режим обмена с прерываниями. Рас­смотрим рис. 2.1.

Пусть для простоты управление вводом/выводом осуществляет центральный процессор (в этом случае часто говорят о наличии программного канала обмена данными между внешними устройством и оперативной памятью, в отличие от канала прямого доступа к памяти, при котором управление вводом/выводом осуществляет специальное дополнительное оборудование). Центральный процессор посылает устройству управле­ния команду выполнить некоторое действие устройству ввода/вывода. Последнее исполняет команду, транслируя сигналы, понятные центральному устройству и устройству управления в сигналы, понятные устройству ввода/вывода. Но быст­родействие устройства ввода/вывода намного меньше быстродействия централь­ного процессора (порой на несколько порядков). Поэтому сигнал готовности (транслируемый или генерируемый устройством управления и сигнализирующий процессору о том, что команда ввода/вывода выполнена и можно выдать новую команду для продолжения обмена данными) приходится очень долго ожидать, постоянно опрашивая соответствующую линию интерфейса на наличие или от­сутствие нужного сигнала. Посылать новую команду, не дождавшись сигнала готовности, сообщающего об исполнении предыдущей команды, бессмысленно, В режиме опроса готовности драйвер, управляющий процессом обмена данными с внешним устройством, как раз и выполняет в цикле команду «проверить нали­чие сигнала готовности». До тех пор пока сигнал готовности не появится, драй­вер ничего другого не делает. При этом, естественно, нерационально использу­ется время центрального процессора. Гораздо выгоднее, выдав команду ввода/вывода, на время забыть об устройстве ввода/вывода и перейти на выполнение другой программы. А появление сигнала готовности трактовать как запрос на прерывание от устройства ввода/вывода. Именно эти сигналы готовности и яв­ляются сигналами запроса на прерывание.

Режим обмена с прерываниями, по своей сути, является режимом асинхронного управления. Для того чтобы не потерять связь с устройством (после того как процессор выдал очередную команду по управлению обменом данными и пере­ключился на выполнение других программ), может быть запущен отсчет времени, в течение которого устройство обязательно должно выполнить команду и выдать сигнал запроса на прерывание. Максимальный интервал времени, в течение которого устройство ввода/вывода или его контроллер должны выдать сигнал запроса на прерывание, часто называют установкой тайм-аута. Если это время истекло после выдачи устройству очередной команды, а устройство так и не от­ветило, то делается вывод о том, что связь с устройством потеряна и управлять им больше нет возможности. Пользователь и/или задача получают соответст­вующее диагностическое сообщение.

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

Секция запуска инициирует операцию ввода/вывода. Эта секция запускается для включения устройства ввода/вывода либо просто для инициации очередной операции ввода/вывода.

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

Секция завершения обычно выключает устройство ввода/вывода либо просто за­вершает операцию.

Управление операциями ввода/вывода в режиме прерываний требует больших усилий со стороны системных программистов – такие программы создавать слож­нее, чем те, что работают в режиме опроса готовности. Примером тому может служить ситуация с драйверами, обеспечивающими печать. Так, в ОС Windows (и Windows 9x, и Windows NT) драйвер печати через параллельный порт работа­ет не в режиме с прерываниями, как это сделано в других ОС, а в режиме опроса готовности, что приводит к 100%-й загрузке центрального процессора на все вре­мя печати. При этом, естественно, выполняются и другие задачи, запущенные на исполнение, но исключительно за счет того, что ОС Windows реализует вытес­няющую мультизадачность и время от времени прерывает процесс управления печатью и передает центральный процессор остальным задачам.

Многие устройства не допускают совместного использования. Пре­жде всего, это устройства с последовательным доступом. Такие устройства могут стать закрепленными, то есть быть предоставленными некоторому вычислитель­ному процессу на все время жизни этого процесса. Однако это приводит к тому, что вычислительные процессы часто не могут выполняться параллельно – они ожидают освобождения устройств ввода/вывода.

Для организации использова­ния многими параллельно выполняющимися задачами устройств ввода/вывода, которые не могут быть разделяемыми, вводится понятие виртуальных устройств. Использование принципа виртуализации позволяет повысить эффективность вы­числительной системы. Например, несколько приложений должны выводить на печать результаты своей работы, можно каждому вычислительному процессу предоставлять не реальный, а виртуальный принтер и поток выводимых симво­лов (или управляющих кодов для их печати) сначала направлять в специальный файл на магнитном диске, называемый спул-файлом. Затем, по окончании виртуальной печати, в соответствии с принятой дисциплиной обслуживания и приоритетами приложений вы­водить содержимое спул-файла на принтер. Системный процесс, который управ­ляет спул-файлом, называется спулером (spool-reader или spool-writer).

2.3. Основные системные таблицы ввода/вывода

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

Исходя из принципа управления вводом/выводом через супервизор ОС и учи­тывая, что драйверы устройств ввода/вывода используют механизм прерываний для установления обратной связи центральной части с внешними устройствами, можно сделать вывод о необходимости создания по крайней мере трех систем­ных таблиц.

Первая таблица (или список) содержит информацию обо всех устройствах вво­да/вывода, подключенных к вычислительной системе. Назовем ее условно таб­лицей оборудования (equipment table), а каждый элемент этой таблицы пусть на­зывается UCB (unit control block, блок управления устройством ввода/вывода). Каждый элемент UCB таблицы оборудования, как правило, содержит следую­щую информацию об устройстве:

• тип устройства, его конкретная модель, символическое имя и характеристики устройства;

• как это устройство подключено (через какой интерфейс, к какому разъему, какие порты и линия запроса прерывания используются и т. д.);

• номер и адрес канала (и подканала), если такие используются для управле­ния устройством;

• указание на драйвер, который должен управлять этим устройством, адрес секции запуска и секции продолжения драйвера;

• информация о том, используется или нет буферирование при обмене данны­ми с этим устройством, «имя» (или просто адрес) буфера, если такой выделя­ется из системной области памяти;

• уставка тайм-аута и ячейки для счетчика тайм-аута;

• состояние устройства;

• поле указателя для связи задач, ожидающих устройство, и, возможно, еще много других сведений.

Вторая таблица предназначена для реализации еще одного принципа виртуа­лизации устройств ввода/вывода – независимости от устройства. Желательно, чтобы программист не был озабочен учетом конкретных параметров (и/или воз­можностей) того или иного устройства ввода/вывода, которое установлено (или не установлено) в компьютер. Для него должны быть важны только самые об­щие возможности, характерные для данного класса устройств ввода/вывода, ко­торыми он желает воспользоваться. Например, принтер должен уметь выводить (печатать) символы или графическое изображение. А накопитель на магнитных дисках – считывать или записывать по указанному адресу порцию данных. При этом для программиста так­же не должно иметь значения, каким образом то или иное устройство подключе­но к вычислительной системе, а не только какая конкретная модель устройства используется. Поэтому в запросе на ввод/вывод программист указывает именно логическое имя устройства. Действительное устройство, которое сопоставляется виртуальному (логическому), выбирается супервизором с помощью таблицы, которую условно можно назвать таблицей описания виртуальных логических устройств (DRT, device reference table). Назначение этой второй таблицы – установление связи между виртуальными (логическими) устройствами и реальными устройст­вами, описанными посредством первой таблицы оборудования. Во мно­гих многопользовательских системах такая таблица не одна, а несколько: одна общая и по одной – на каждого пользователя, что позволяет строить необходи­мые связи между логическими (символьными) именами устройств и реальными физическими устройствами, которые имеются в системе.

Третья таблица необходима для организации обратной связи между центральной частью и устройствами ввода/вывода. Это таблица прерываний, ко­торая указывает для каждого сигнала запроса на прерывание тот элемент UCB, который сопоставлен данному устройству, подключенному так, что оно исполь­зует настоящую линию (сигнал) прерывания.

В современных сложных ОС имеется гораздо больше системных таблиц или списков, используемых для организации процессами управления операциями ввода/вывода.

Взаимосвязи между описанными таблицами изображены на рис. 2.2.

Рис. 2.2. Взаимосвязь системных таблиц ввода/вывода

Рассмотрим процесс управления вводом/выводом (рис. 2.3).

Запрос на операцию ввода/вывода от выполняющейся программы поступает на супервизор (действие 1). Тот проверяет системный вызов на соответствие при­нятым спецификациям и в случае ошибки возвращает задаче соответствующее сообщение (действие 1-1). Если же запрос корректен, то он перенаправляется в супервизор ввода/вывода (действие 2). Последний по логическому (виртуаль­ному) имени с помощью таблицы DRT находит соответствующий элемент UCB в таблице оборудования (действие 2’). Если устройство уже занято, то описатель задачи, за­прос которой сейчас обрабатывается супервизором ввода/вывода, помещается в список задач, ожидающих настоящее устройство. Если же устройство свобод­но, то супервизор ввода/вывода определяет из UCB тип устройства и при необ­ходимости запускает препроцессор, позволяющий получить последовательность управляющих кодов и данных, которую сможет правильно понять и отработать устройство (действие 3). Когда «программа» управления операцией ввода/вывода будет готова, супервизор ввода/вывода передаст управление соответствующему драйверу на секцию запуска (действие 4). Драйвер инициализирует операцию управления, обнуляет счетчик тайм-аута и возвращает управление супервизору (диспетчеру задач) с тем, чтобы он поставил на процессор готовую к исполне­нию задачу (действие 5). Система работает своим чередом, но когда устройство ввода/вывода отработает посланную ему команду, оно выставляет сигнал запро­са на прерывания, по которому через таблицу прерываний управление передает­ся на секцию продолжения (действие 6). Получив новую команду, устройство вновь начинает ее обрабатывать, а управление процессором опять передается диспетчеру задач, и процессор продолжает полезную работу. Таким образом, по­лучается параллельная обработка задач, на фоне которой процессор осуществля­ет управление операциями ввода/вывода.

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

2.4. Синхронный и асинхронный ввод/вывод

Задача, выдавшая запрос на операцию ввода/вывода, переводится супервизором в состояние ожидания завершения заказанной операции. Когда супервизор по­лучает от секции завершения сообщение о том, что операция завершилась, он переводит задачу в состояние готовности к выполнению, и она продолжает свою работу. Эта ситуация соответствует синхронному вводу/выводу. Синхронный ввод/вывод является стандартным для большинства ОС. Чтобы увеличить ско­рость выполнения приложений, было предложено при необходимости использо­вать асинхронный ввод/вывод.

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

Можно организовать и асинхронный ввод данных. Однако для этого необходи­мо не только выделить область памяти для временного хранения считываемых с устройства данных и связать выделенный буфер с задачей, заказавшей опера­цию, но и сам запрос на операцию ввода/вывода разбить на две части (на два за­проса). В первом запросе указывается операция на считывание данных, подобно тому, как это делается при синхронном вводе/выводе. Однако тип (код) запроса используется другой, и в запросе указывается еще по крайней мере один допол­нительный параметр – имя (код) того системного объекта, которое получает за­дача в ответ на запрос и которое идентифицирует выделенный буфер. Получив имя буфера, задача продолжает свою работу. Здесь очень важно подчерк­нуть, что в результате запроса на асинхронный ввод данных задача не переводится супервизором ввода/вывода в состояние ожидания завершения операции ввода/вывода, а остается в состоянии выполнения или в состоянии готовности к вы­полнению. Через некоторое время, выполнив необходимый код, который был оп­ределен программистом, задача выдает второй запрос на завершение операции ввода/вывода. В этом втором запросе к тому же устройству, который, естествен­но, имеет другой код (или имя запроса), задача указывает имя системного объек­та (буфера для асинхронного ввода данных) и в случае успешного завершения операции считывания данных тут же получает их из системного буфера. Если же данные еще не успели до конца переписаться с внешнего устройства в систем­ный буфер, супервизор ввода/вывода переводит задачу в состояние ожидания завершения операции ввода/вывода, и далее все напоминает обычный синхрон­ный ввод данных. Обычно асинхронный ввод/вывод предоставляется в большинстве мультипрограммных ОС.

2.5. Кэширование операций ввода/вывода при работе с накопителями на магнитных дисках

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

Буфер – память для промежуточного хранения данных.

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

Под кэшем можно понимать буферную память, предназначенную для промежуточного хранения наиболее часто используемых процессором данных. Если мы считываем какое-то множество секторов, содержащих записи того или иного файла, то эти данные, пройдя через кэш, там остаются (до тех пор, пока другие секторы не заменят эти буферы). Если впоследствии потребуется повторное чтение, то данные могут быть извлечены непосредственно из опера­тивной памяти без фактического обращения к диску. Ускорить можно и опера­ции записи: данные помещаются в кэш, и для запросившей эту операцию задачи можно считать, что они уже фактически записаны. Задача может продолжить свое выполнение, а системные внешние процессы через некоторое время запи­шут данные на диск. Это называется операцией отложенной записи (lazy write, «ленивая запись»). Если отложенная запись отключена, только одна задача мо­жет записывать на диск свои данные. Остальные приложения должны ждать своей очереди. Это ожидание подвергает информацию риску не меньшему (если не большему), чем отложенная запись, которая к тому же и более эффективна по скорости работы с диском.

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

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

В мультипрограммных ОС при выполнении многих задач запросы на чтение и запись данных могут идти таким потоком, что при их обслуживании образуется очередь. Если выполнять эти запросы в поряд­ке поступления их в очередь, то вследствие случайного характера обращений к тому или иному сектору магнитного диска мы можем иметь значительные поте­ри времени на поиск данных. ОС может переупорядочивать запросы с целью минимизации затрат времени на поиск данных. Перечислим известные дисциплины, в соответствии с которыми можно пере­страивать очередь запросов на операции чтения/записи данных:

1. SSTF (shortest seek time – first) – с наименьшим временем поиска – первым. В соответствии с этой дисциплиной при позиционировании магнитных голо­вок следующим выбирается запрос, для которого необходимо минимальное перемещение с цилиндра на цилиндр, даже если этот запрос не был первым в очереди на ввод/вывод. Однако для этой дисциплины характерна резкая дис­криминация определенных запросов, а ведь они могут идти от высокоприори­тетных задач. Обращения к диску проявляют тенденцию концентрироваться, в результате чего запросы на обращение к самым внешним и самым внутрен­ним дорожкам могут обслуживаться существенно дольше и нет никакой гаран­тии обслуживания. Достоинством такой дисциплины является максимально возможная пропускная способность дисковой подсистемы.

2. Scan (сканирование). По этой дисциплине головки перемещаются то в одном, то в другом «привилегированном» направлении, обслуживая «по пути» под­ходящие запросы. Если при перемещении головок чтения/записи более нет попутных запросов, то движение начинается в обратном направлении.

3. Next-Step Scan – отличается от предыдущей дисциплины тем, что на каждом проходе обслуживаются только запросы, которые уже существовали на мо­мент начала прохода. Новые запросы, появляющиеся в процессе перемеще­ния головок чтения/записи, формируют новую очередь запросов, причем та­ким образом, чтобы их можно было оптимально обслужить на обратном ходу.

4. C-Scan (циклическое сканирование). По этой дисциплине головки перемеща­ются циклически с самой наружной дорожки к внутренним, по пути обслу­живая имеющиеся запросы, после чего вновь переносятся к наружным ци­линдрам. Эту дисциплину иногда реализуют таким образом, чтобы запросы, поступающие во время текущего прямого хода головок, обслуживались не по­путно, а при следующем ходе, что позволяет исключить дискриминацию за­просов к самым крайним цилиндрам; она характеризуется очень малой дис­персией времени ожидания обслуживания. Эту дисциплину обслуживания часто называют «элеваторной».

Управление файлами

Наши рекомендации