Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Куровой.doc
Скачиваний:
13
Добавлен:
05.09.2019
Размер:
1.48 Mб
Скачать

4 Определение состава и общей структуры системы

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

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

4.1 Общее описание ядра и ОС

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

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

При организации сетевой работы операционная система играет роль интерфейса, экранирующего от пользователя все детали низкоуровневых программно-аппаратных средств сети. Например, вместо числовых адресов компьютеров сети, таких как МАС-адрес и IP-адрес, операционная система компьютерной сети позволяет оперировать удобными для запоминания символьными именами. В результате в представлении пользователя сеть с ее множеством сложных и запутанных реальных деталей превращается в достаточно понятный набор разделяемых ресурсов.

Функциональная сложность операционной системы неизбежно приводит к сложности ее архитектуры, под которой понимают структурную организацию ОС на основе различных программных модулей. Обычно в состав ОС входят исполняемые и объектные модули стандартных для данной ОС форматов, библиотеки разных типов, модули исходного текста программ, программные модули специального формата (например, загрузчик ОС, драйверы ввода-вывода), конфигурационные файлы, файлы документации, модули справочной системы и т. д.

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

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

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

Ядро ОС обычно содержит программы для реализации следующих функций:

  1. обработка прерываний:

а) создание и уничтожение процессов;

б) переключение состояний процессов;

в) диспетчеризация;

г) приостановка и активация;

д) синхронизация процессов;

е) организация взаимодействия между процессами;

2) поддержка операций ввода/вывода;

  1. поддержка распределения, иерархирование памяти;

  2. поддержка работы ФС;

  3. поддержка механизма вызова возврата при обращении к процедурам (то есть возвращение в то место, откуда был произведен вызов);

  4. поддержка определения функций по ведению учета машины.

Вход в ядро ОС обычно осуществляется по прерываниям. Когда ядро реагирует на данное прерывание, оно запрещает другие прерывания. После определения причины данного прерывания ядро передает его обработку специальному системному процессу, предназначаемому для работы с прерываниями данного типа. Схема прерываний для разных конфигураций ЭВМ отличается.

Схемы прерываний (типы):

  1. прерывание по вызову супервизора (инициатором является работающий процессор);

  2. прерывание ввода/вывода (инициируется аппаратурой ввода/вывода (когда завершается операция ввода/вывода, или совершается ошибка, или устройство переходит в другое состояние));

  3. внешние прерывания (причиной могут быть различные события: истечение кванта времени, заданного на таймере, нажатие клавиши прерывания(ctrl+break); прием прерывания от другого процессора в мультипроцессорной системе);

  4. прерывание по рестарту (происходит, когда оператор нажимает на пульте управления кнопку рестарта или от другого процессора в мультипроцессорной системе приходит такая команда);

  5. прерывание по ошибке программы при делении на 0, попытка процесса пользователя выполнить привилегированную операцию;

  6. прерывание по ошибке машины (аппаратная ошибка: по питанию, испорченные области на диске).

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

4.2 Ядро и вспомогательные модули ОС

Наиболее общим подходом к структуризации операционной системы является разделение всех ее модулей на две группы:

  • ядро — модули, выполняющие основные функции ОС;

  • модули, выполняющие вспомогательные функции ОС.

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

В состав ядра входят функции, решающие внутрисистемные задачи организации вычислительного процесса, такие как переключение контекстов, загрузка/выгрузка станиц, обработка прерываний. Эти функции недоступны для приложений. Другой класс функций ядра служит для поддержки приложений, создавая для них так называемую прикладную программную среду. Приложения могут обращаться к ядру с запросами — системными вызовами — для выполнения тех или иных действий, например для открытия и чтения файла, вывода графической информации на дисплей, получения системного времени и т. д. Функции ядра, которые могут вызываться приложениями, образуют интерфейс прикладного программирования — API.

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

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

Вспомогательные модули ОС подразделяются на следующие группы:

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

  • системные обрабатывающие программы — текстовые или графические редакторы, компиляторы, компоновщики, отладчики;

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

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

Как и обычные приложения, для выполнения своих задач утилиты, обрабатывающие программы и библиотеки ОС, обращаются к функциям ядра посредством системных вызовов (рис. 1).

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

Рисунок 4.1 – Взаимодействие между ядром и вспомогательными модулями ОС

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

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

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

Обеспечить привилегии операционной системе невозможно без специальных средств аппаратной поддержки. Аппаратура компьютера должна поддерживать как минимум два режима работы — пользовательский режим (user mode) и привилегированный режим, который также называют режимом ядра (kernel mode), или режимом супервизора (supervisor mode). Подразумевается, что операционная система или некоторые ее части работают в привилегированном режиме, а приложения — в пользовательском режиме.

Так как ядро выполняет все основные функции ОС, то именно ядро становится той частью ОС, которая работает в привилегированном режиме Иногда это свойство — работа в привилегированном режиме — служит основным определением понятия «ядро».

Структуру ОС составляют следующие модули:

  • базовый модуль (ядро ОС) – управляет работой программы и файловой системой, обеспечивает доступ к ней и обмен файлами между периферийными устройствами;

  • командный процессор – расшифровывает и исполняет команды пользователя, поступающие прежде всего через клавиатуру;

  • драйверы периферийных устройств – программно обеспечивают согласованность работы этих устройств с процессором (каждое периферийное устройство обрабатывает информацию по-разному и в различном темпе);

  • дополнительные сервисные программы (утилиты) – делают удобным и многосторонним процесс общения пользователя с компьютером.

4.3 Загрузка и модули ядра ОС

Для выполнения программы и файлы ОС должны находится в оперативной памяти (ОЗУ). Чтобы произвести запись ОС в ОЗУ, необходимо выполнить программу загрузку, которой сразу после включения компьютера в ОЗУ нет. Выход из этой ситуации состоит в последовательной, поэтапной загрузке ОС в оперативную память. Рассмотрим этапы загрузки операционной системы:

  1. первый этап загрузки ОС: в системном блоке компьютера находится постоянное запоминающее устройство (ПЗУ, постоянная память, ROM-Read Only Memory - память с доступом только для чтения), в котором содержатся программы тестирования блоков компьютера и первого этапа загрузки ОС. Они начинают выполнятся с первым импульсом тока при включении компьютера. На этом этапе процессор обращаются к диску и проверяет наличие на определенном месте (в начале диска) очень небольшой программы - загрузчика. Если эта программа обнаружена, то она считывается в ОЗУ и ей передается управление.

  2. второй этап загрузки ОС: программа-загрузчик ищет на диске базовый модуль ОС, переписывает его память и передает ему управление.

  3. третий этап загрузки ОС: в состав базового модуля входит основной загрузчик, который ищет остальные модули ОС и считывает их в ОЗУ. После окончания загрузки ОС управление передается командному процессору и на экране появляется приглашение системы к вводу команды пользователя.

В оперативной памяти во время работы компьютера обязательно должны находится базовый модуль ОС и командный процессор. Следовательно, нет необходимости загружать в оперативную память все файлы ОС одновременно. Драйверы устройств и утилиты могут подгружаться в ОЗУ по мере необходимости, что позволяет уменьшать обязательный объем оперативной памяти, отводимый под системное программное обеспечение.

В состав операционной системы входят следующие файлы:

loadeк.com – загрузчик операционной системы. Выполняет загрузку ядра, всех драйверов и параметров, а также загрузку модулей ОС. Файл загружается при запуске операционной системы.

kernel.sys – ядро операционной системы. После загрузки запускает к выполнению основные системные процессы. К которым относятся планировщик процессов, а также модуль управления памятью и межпроцессным взаимодействием.

Модули ядра операционной системы представлены в таблице 4.1.

Таблица 4.1– Модули ядра

Наименование

Назначение

Обрабатываемые прерывания

procman

является планировщиком процессов, обеспечивает все выполняемые процессы необходимыми ресурсами

обрабатывает все виды прерываний

memman

управляет оперативной и виртуальной памятью

обрабатывает программные прерывания

interproc

передача данных между различными процессами

обрабатывает программные и аппаратные прерывания

command_proc.com

обработка команд пользователя

обрабатывает аппаратные прерывания

filesys.com

работа с файловой системой

обрабатывает программные и аппаратные прерывания

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

Модуль управления памятью обеспечивает выделение оперативной памяти для прикладных программ; реализует доступ к виртуальной памяти; управляет виртуальной памятью процессов.

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

command_proc.com – командный процессор. Необходим для обработки команд пользователя. Запускается после ядра системы.

filesys.com – файловый процессор. Главной задачей файлового процессора является работа с файловой системой (выполнения различных команд пользователя, например, таких как удаление, копирование, переименование файлов).

Ядро ОС имеет интерфейс системных вызовов. Именно через него процесс производит запрос необходимых ресурсов, а ядро операционной системы либо отвергает запрос, либо обеспечивает процесс запрашиваемыми ресурсами.

При запуске операционной системы в первую очередь запускается файл «loader.com». Который запускает ядро ОС, подгружает все необходимые драйвера и пользовательские настройки системы. Все вышеописанные модули на протяжении всего времени работы операционной системы находятся в памяти и обеспечивают корректную работу ОС.

4.4 Структура ядра ОС

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

Следует заметить, что удобство и эффективность современных вариантов ОС не означает, что вся система, включая ядро, спроектирована и структуризована наилучшим образом.

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

  • Файловая подсистема. Доступ к структурам ядра осуществляется через файловый интерфейс.

  • Управление процессами. Сюда входит управление параллельным выполнением процессов (планирование и диспетчеризация), виртуальной памятью процесса и взаимодействием между процессами (сигналы, очереди сообщений и т. п.).

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

Благодаря тому, что в UNIX аппаратно-независимая часть отделена явно, операционные системы этого семейства могут быть с минимальными затратами перенесены на новые аппаратные платформы.

Рисунок 4.2 — Ядро ОС

4.5 Системные вызовы

Системные вызовы (system calls) интерфейс между операционной системой и пользовательской программой. Они создают, удаляют и используют различные объекты, главные из которых процессы и файлы. Пользовательская программа запрашивает сервис у операционной системы, осуществляя системный вызов. Имеются библиотеки процедур, которые загружают машинные регистры определенными параметрами и осуществляют прерывание процессора, после чего управление передается обработчику данного вызова, входящему в ядро операционной системы. Цель таких библиотек сделать системный вызов похожим на обычный вызов подпрограммы.

Основное отличие состоит в том, что при системном вызове задача переходит в привилегированный режим или режим ядра (kernel mode). Поэтому системные вызовы иногда еще называют программными прерываниями в отличие от аппаратных прерываний, которые чаще называют просто прерываниями.

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

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

  • Обеспечивать переключение в привилегированный режим (выполняет механизм прерываний)

  • выполняться быстро;

  • иметь одинаковый вид в разных аппаратных платформах;

  • допускать легкое расширение набора системных вызовов;

  • Выполняться под контролем ОС.

Диспетчер системных вызовов контролирует запрос и передает вызов процедуре ОС, адрес которой определяется номером запроса. Процедура, если надо, выбирает из стека данные для своей работы, возможно, обращается к некоторым подсистемам ядра ОС, а после завершения работы возвращает управление диспетчеру системных вызовов.

Для приложения, системный вызов внешне ничем не отличается от вызова функции из библиотеки функций языка С.

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

При обращении к системным вызовам, поддерживаемым ОС, параметры помещаются в строго определенные места, такие, как регистры или стек, а затем выполняется специальная команда прерывания, известная как вызов ядра или вызов супервизора. Эта команда переключает машину из режима пользователя в режим ядра, называемый также режимом супервизора, и передает управление ОС. Затем ОС проверяет параметры вызова для того, чтобы определить, какой системный вызов должен быть выполнен. После этого ОС индексирует таблицу, содержащую ссылки на процедуры, и вызывает соответствующую процедуру. Такая организация ОС предполагает следующую структуру:

1. Главная программа, которая вызывает требуемые сервисные процедуры.

2. Набор сервисных процедур, реализующих системные вызовы.

3. Набор утилит, обслуживающих сервисные процедуры.

В этой модели для каждого системного вызова имеется одна сервисная процедура. Утилиты выполняют функции, которые нужны нескольким сервисным процедурам.

Для обеспечения передачи параметров диспетчеру системных вызовов и процедурам ОС могут использоваться различные механизмы: 

  • передача параметров через регистры (самый быстрый механизм, но сильное ограничение по количеству передаваемой информации);

  • передача параметров через область памяти, адрес которой заносится в регистр (позволяет передать максимально возможное количество параметров);

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

Реализация системных вызовов должна:

– обеспечивать переключение в режим ядра;

– обладать высокой скоростью вызовов процедур ОС;

– обеспечивать единообразное обращение к системным вызовам для всех

аппаратных платформ, на которых работает ОС;

– обладать свойством расширяемости;

– обеспечивать контроль со стороны ОС за корректностью использованных системных вызовов.

4.5.1 Процессы

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

Для образования нового процесса и запуска в нем программы используются два системных вызова (примитива ядра ОС) - fork() и exec (имя-выполняемого-файла). Системный вызов fork приводит к созданию нового адресного пространства, состояние которого абсолютно идентично состоянию адресного пространства основного процесса (т.е. в нем содержатся те же программы и данные).

Сразу после выполнения системного вызова fork основной и порожденный процессы являются абсолютными близнецами; управление и в том, и в другом находится в точке, непосредственно следующей за вызовом fork. Чтобы программа могла разобраться, в каком процессе она теперь работает - в основном или порожденном, функция fork возвращает разные значения: 0 в порожденном процессе и целое положительное число (идентификатор порожденного процесса) в основном процессе.

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

В следующем примере пользовательская программа, вызываемая как команда shell, выполняет в отдельном процессе стандартную команду shell ls, которая выдает на экран содержимое текущего каталога файлов.

main()

{if(fork()==0) wait(0); /* родительский процесс */

else execl("ls", "ls", 0); /* порожденный процесс */

}

4.5.2 Перенаправление ввода/вывода

Механизм перенаправления ввода/вывода является одним из наиболее элегантных, мощных и одновременно простых механизмов ОС.

Реализация механизма основывается на следующих свойствах ОС. Во-первых, любой ввод/вывод трактуется как ввод из некоторого файла и вывод в некоторый файл.

Клавиатура и экран терминала тоже интерпретируются как файлы (первый можно только читать, а во второй можно только писать).

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

Фиксируются три значения дескрипторов файлов. Файл с дескриптором 1 называется файлом стандартного ввода (stdin), файл с дескриптором 2 - файлом стандартного вывода (stdout), и файл с дескриптором 3 - файлом стандартного вывода диагностических сообщений (stderr). В-третьих, программа, запущенная в некотором процессе, "наследует" от породившего процесса все дескрипторы открытых файлов.

В наиболее распространенных функциях библиотеки ввода/вывода printf, scanf и error вообще не требуется указывать дескриптор файла.

Функция printf неявно использует stdout, функция scanf - stdin, а функция error - stderr.

4.5.3 Монтируемые файловые системы

Файлы любой файловой системы становятся доступными только после "монтирования" этой файловой системы. Файлы "не смонтированной" файловой системы не являются видимыми операционной системой.

Для монтирования файловой системы используется системный вызов mount. Монтирование файловой системы означает следующее. В имеющемся к моменту монтирования дереве каталогов и файлов должен иметься листовой узел - пустой каталог (в терминологии UNIX такой каталог, используемый для монтирования файловой системы, называется directory mount point - точка монтирования).

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

Смонтированная файловая система впоследствии может быть отсоединена от общей иерархии с использованием системного вызова umount. Для успешного выполнения этого системного вызова требуется, чтобы отсоединяемая файловая система к этому моменту не находилась в использовании (т.е. ни один файл из этой файловой системы не был открыт). Корневая файловая система всегда является смонтированной, и к ней не применим системный вызов umount.

4.5.4 Интерфейс с файловой системой

Ядро ОС поддерживает для работы с файлами несколько системных вызовов. Среди них наиболее важными являются open, creat, read, write, lseek и close.

Файл в системных вызовах, обеспечивающих реальный доступ к данным, идентифицируется своим дескриптором (целым значением). Дескриптор файла выдается системными вызовами open (открыть файл) и creat (создать файл). Основным параметром операций открытия и создания файла является полное или относительное имя файла. Кроме того, при открытии файла указывается также режим открытия (только чтение, только запись, запись и чтение и т.д.) и характеристика, определяющая возможности доступа к файлу:

open(pathname, oflag [,mode])

Одним из признаков, которые могут участвовать в параметре oflag, является признак O_CREAT, наличие которого указывает на необходимость создания файла, если при выполнении системного вызова open файл с указанным именем не существует (параметр mode имеет смысл только при наличии этого признака

Открытый файл может использоваться для чтения и записи последовательностей байтов. Для этого поддерживаются два системных вызова:

read(fd, buffer, count) и write(fd, buffer, count)

Здесь fd - дескриптор файла (полученный при ранее выполненном системном вызове open или creat), buffer - указатель символьного массива и count - число байтов, которые должны быть прочитаны из файла или в него записаны. Значение функции read или write - целое число, которое совпадает со значением count, если операция заканчивается успешно, равно нулю при достижении конца файла и отрицательно при возникновении ошибок.

В каждом открытом файле существует текущая позиция. Сразу после открытия файл позиционируется на первый байт. Другими словами, если сразу после открытия файла выполняется системный вызов read (или write), то будут прочитаны (или записаны) первые count байтов содержимого файла (конечно, они будут успешно прочитаны только в том случае, если файл реально содержит по крайней мере count байтов). После выполнения системного вызова read (или write) указатель чтения/записи файла будет установлен в позицию count+1 и т.д.

Такой, чисто последовательный стиль работы, оказывается во многих случаях достаточным, но часто бывает необходимо читать или изменять файл с произвольной позиции (например, как без такой возможности хранить в файле прямо индексируемые массивы данных?). Для явного позиционирования файла служит системный вызов

lseek(fd, offset, origin)

Как и раньше, здесь fd - дескриптор ранее открытого файла. Параметр offset задает значение относительного смещения указателя чтения/записи, а параметр origin указывает, относительно какой позиции должно применяться смещение. Возможны три значения параметра origin. Значение 0 указывает, что значение offset должно рассматриваться как смещение относительно начала файла. Значение 1 означает, что значение offset является смещением относительно текущей позиции файла. Наконец, значение 2 говорит о том, что задается смещение относительно конца файла. Заметим, что типом данных параметра offset является long int. Это значит, что, во-первых, могут задаваться достаточно длинные смещения и, во-вторых, смещения могут быть положительными и отрицательными.

Например, после выполнения системного вызова

lseek(fd, 0, 0)

указатель чтения/записи соответствующего файла будет установлен на начало (на первый байт) файла. Системный вызов

lseek(fd, 0, 2)

установит указатель на конец файла. Наконец, выполнение системного вызова

lseek(fd, 10, 1)

приведет к увеличению текущего значения указателя на 10.

Естественно, системный вызов успешно завершается только в том случае, когда заново сформированное значение указателя не выходит за пределы существующих размеров файла.

4.5.5 Файлы-каталоги

Наличие обычных файлов недостаточно для организации иерархических файловых систем. Требуется наличие каталогов, которые сопоставляют имена файлов или каталогов с их физическим описанием. Каталоги представляют собой особый вид файлов, которые хранятся во внешней памяти подобно обычным файлам, но структура которых поддерживается самой файловой системой.

Структура файла-каталога очень проста. Фактически, каталог - это таблица, каждый элемент которой состоит из двух полей: номера i-узла данного файла в его файловой системе и имени файла, которое связано с этим номером (конечно, этот файл может быть и каталогом).

Файлам-каталогам соответствует особый тип файла (обозначенный в их i-узлах), по отношению к которому возможно выполнение только специального набора системных вызовов:

  • mkdir, производящего новый каталог,

  • rmdir, удаляющий пустой (незаполненный) каталог,

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

Отсутствует системный вызов, позволяющий прямо писать в файл-каталог.

4.5.6 Специальные файлы

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

4.5.7 Связывание файлов с разными именами

Файловая система ОС обеспечивает возможность связывания одного и того же файла с разными именами.

Для работы с символьными связями поддерживаются три специальных системных вызова:

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

  • lstat - аналогичен системному вызову stat (получить информацию о файле), но относится к символической ссылке;

  • lchowm - аналогичен системному вызову chown, но используется для смены пользователя и группы самой символической ссылки.

4.5.8 Файлы, отображаемые в виртуальную память

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

Несколько процессов могут одновременно открыть один и тот же файл и подключить его к своей виртуальной памяти системным вызовом mmap. Тогда любые изменения, производимые путем записи в соответствующий сегмент разделяемой памяти, будут сразу видны другим процессам.

4.5.9 Синхронизация при параллельном доступе к файлам

Ядро ОС поддерживает дополнительный системный вызов fcntl, обеспечивающий такие вспомогательные функции, относящиеся к файловой системе, как получение информации о текущем режиме открытия файла, изменение текущего режима открытия и т.д.

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

Установленные блокировки относятся только к тому процессу, который их установил, и не наследуются процессами-потомками этого процесса. Более того, даже если некоторый процесс пользуется синхронизационными возможностями системного вызова fcntl, другие процессы по-прежнему могут работать с тем файлом без всякой синхронизации. Другими словами, это дело группы процессов, совместно использующих файл, - договориться о способе синхронизации параллельного доступа.