6
Данная тема, озаглавленная как «Подсистема управления вводом-выводом», содержит учебный материал, который конкретизирует знания, полученные студентом при изучении темы 4 «Управление файловыми системами ОС», что предполагает изучение функций, обеспечивающих написание программ на языке С.
Указанный подход к изложению учебного материала имеет свои особенности связанные с архитектурой используемой ОС. Чтобы уменьшить неоднозначность понимания ученого материала, мы будем придерживаться общей архитектуры взаимодействия приложений с ядром ОС, показанной на рисунке 1.1.
Рисунок 1.1 - Общая архитектура подсистем ОС
7
Здесь хорошо видно, что ядро ОС имеет две основные подсистемы, которые в свою очередь тесно связаны между собой:
•подсистему управления файлами, которая является предметом изучения данной темы;
•подсистему управления процессами, которая изучается в последующих темах.
Непосредственно, подсистема управления файлами осуществляет доступ к устройствам компьютера через два типа интерфейсов:
•блок-ориентированный интерфейс, предназначенный для взаимодействия с файловыси системами ОС;
•байт-ориентированный интерфейс, предназначенный для работы со всеми остальными устройствами.
Поскольку рисунок 1.1 не раскрывает многие аспекты взаимодействия ПО подсистемы ввода-вывода, а также не учитывает особенности устройств с которыми осуществляется взаимодействие, то часто применяются иерархические представления, например, как показано на рисунке 1.2.
Рисунок 1.2 - Иерархическая структура подсистемы ввода-вывода
8
Замечание
Можно оспорить утверждение, что модули всех ОС связаны показанным на рисунке 1.2 способом, но основная идея подсистемы ввода-вывода показана правильно.
В целом, при изучении данной темы, мы будем придерживаться концепции «Все есть файл». Такая парадигма позволит нам рассмотреть функциональные возможности современных ОС.
С практической точки зрения, мы будем рассматривать примеры программ, написанных для блок-ориентированных интерфейсов, рассматривая байт-ориенти- рованные интерфейсы как дополнение к ним. Это связано с тем, что в основе разработки прикладных программ лежит работа с файловыми системами, а работа с символьными устройствами обычно требует специальных знаний, выходящих за рамки нашего курса.
Замечание
Как правило, для работы с символьными устройствами требуются специальные драйвера, которые уже и обеспечивают необходимый прикладной интерфейс, например, - потоковый, позволяющий читать байты с устройства как из файла.
Блочные устройства можно рассматривать как символьные — все дело в драйвере.
Поскольку конкретизация учебного материала данной части курса, на уровень языка программирования С, предполагает множество ограничений, то первым вопросом нашей темы, как и всей части курса, будет обсуждение этих ограничений.
Изучение данного вопроса предполагает, что студент освоил и повторил учебный материал темы 2 «Архитектура x86» [4, подраздел 2.1]. Это, в свою очередь, предполагает знание сути понятий:
•архитектуры процессора х86;
•различие 16, 32 и 64-битных процессоров и программного обеспечения;
•суть трех способов выполнения операций ввода-вывода: программируемый,
управляемый прерываниями, прямой доступ к памяти (direct memory access - DMA).
Замечание
Хотя 32-битное ПО может работать на процессорах х86-64, 64-битное ПО не может работать на процессорах х86.
Общеизвестно, что язык С рассматривается в двух контекстах:
•как высокоуровневый инструмент для написания самих ОС;
•как низкоуровневый инструмент для написания прикладных программ, взаимодействующих с ядром ОС.
9
Такое положение языка С делает его особенным, среди других языков программирования, вкладывающим в него не только функциональные возможности по реализации алгоритмов работы арифметики с целыми и вещественными числами, но и набор средств, которые рассматриваются как функции самой ОС. И хотя синтаксис языка не содержит даже собственных конструкций ввода-вывода, функциональное окружение его, реализованное прежде всего в виде библиотеки libc, является неотъемлемой частью ОС и изменяется после перекомпиляции ее ядра.
Как следствие указанных особенностей языка С, его реализация для целей программирования сильно привязана как к аппаратной платформе ЭВМ, так и к архитектуре ПО ОС. Это, в свою очередь, порождает проблемы переносимости уже разработанного ПО на разные архитектуры, а также разработку инструментальных средств для этого языка.
Стремление повысить мобильность ПО, которое пришется на языке С, привело к разработе стандарта POSIX (Portable Operating System Interface), призванного стабилизировать описание интерфейсов различных операционных систем. Основные особенности этого стандарта и изложены в данном подразделе.
Чтобы продемонстрировать проблематику, обозначенную выше, рассмотрим программу, представленную на листинге 1.1, которая наглядно демонстрирует свойства языка С связанные с различной размерностью разных типов переменных.
Листинг 1.1 - Демонстрация определения типов и вывод их размерностей
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <limits.h>
int main(void) {
//Введем обозначение типов данных: char buf[255];
typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64;
struct { |
//Структура MBR |
u8 |
code[446]; |
u8 |
pt1[16]; |
u8 |
pt2[16]; |
u8 |
pt3[16]; |
u8 |
pt4[16]; |
u16 msignature; |
|
} mbr; |
|
char msg1[] = "Hello!"; |
|
char msg2[] = "Привет"; |
|
// Вывод размерности типов данных puts("Длины типов в битах:");
printf("__WORDSIZE =%6i\n", __WORDSIZE); printf("__SYSCALL_WORDSIZE =%6i\n", __SYSCALL_WORDSIZE); printf("u8 =%6lu\nu16 =%6lu\nu32 =%6lu\nu64 =%6lu\n",
sizeof(u8 ), sizeof(u16), sizeof(u32), sizeof(u64)); printf("buf =%6lu\nmbr =%6lu\nmsg1 =%6lu\nmsg1 =%6lu\n",
sizeof(buf), sizeof(mbr), sizeof(msg1), sizeof(msg2));
return EXIT_SUCCESS;
}
10
Результаты вывода данной программы представлены на рисунке 1.3, а ее исследование выполняется в лабораторной работе по данной теме.
Рисунок 1.3 — Вывод программы листинга 1.1
Само название POSIX было предложено известным специалистом, являющимся основателем «Фонда свободного программного обеспечения», - Ричардом Столмэном. Наиболее современная версия стандарта POSIX, в редакции 2003 г., основана на Техническом стандарте Open Group IEEE Std 1003.1 и на международном стандарте ISO/IEC 9945.
По состоянию на 2001 год, стандарт содержал следующие четыре части:
1.основные определения (термины, концепции и интерфейсы, общие для всех частей);
2.описание прикладного программного C-интерфейса к системным сервисам;
3.описание интерфейса к системным сервисам на уровне командного языка и служебных программ;
4.детальное разъяснение положений стандарта, обоснование принятых решений;
5.в дальнейшем, многие мелкие исправления накапливались и были внесены в
редакцию 2003 года.
Основные идеи этого стандарта описываются множеством базовых, системных сервисов, необходимых для функционирования прикладных программ. Доступ к этим сервисам предоставляется посредством интерфейса, который был специфицирован для языка C, командного языка и других общеупотребительных служебных программ. Здесь следует подчеркнуть, что у каждого интерфейса есть две стороны: вызывающая и вызываемая.
Стандарт POSIX ориентирован в первую очередь на вызывающую сторону, что делает его полезным как для системных, так и прикладных программистов.
Цель стандарта POSIX - сделать приложения мобильными на уровне исходного