
- •Операционные системы для программиста
- •Введение
- •1. Основные понятия
- •1.1. Понятие операционной системы
- •1.2. Системные соглашения для доступа к функциям ос
- •1.3. Особенности разработки программ в базовых ос
- •1.4. Командный интерфейс пользователя в ос
- •1.5. Информация об ошибках системной функции
- •2. Программный доступ к файловой системе
- •2.1. Понятия дескрипторов, идентификаторов и хэндлов
- •2.2. Ввод и вывод в стандартные файлы.
- •2.3. Базовые средства использования файлов
- •2.4. Многопользовательская блокировка файлов
- •2.5. Установка произвольной позиции в файле
- •3. Принципы построения ос
- •3.1. Модульная структура построения ос
- •3.2. Использование прерываний в ос
- •3.3. Управление системными ресурсами
- •3.4 Строение ядра операционной системы
- •3.5. Структура операционной системы типа Windows nt
- •4. Многофункциональный консольный вывод
- •4.1. Функции управления курсором
- •4.2. Многократный вывод символов и атрибутов
- •4.3. Вывод в произвольную позицию экрана
- •4.4. Ввод данных, размещенных предварительно на экране
- •5. Системные функции ввода для консольных устройств
- •5.1. Системные функции ввода текстовых строк
- •5.2. Событийно-управляемый ввод
- •5.3. Системные функции ввода с клавиатуры
- •5.4. Опрос ввода с клавиатуры в программе
- •5.5. Системные функции мыши для текстового режима
- •6. Файловые системы
- •6.1. Структуры файловых систем для пользователя
- •6.2. Методы распределения внешней памяти
- •6.3. Принципы построения файловых систем типа fat
- •6.4. Современные модификации файловой системы fat
- •6.5. Особенности построения файловой системы hpfs
- •6.6. Принципы построения файловой системы ntfs
- •6.7. Особенности строения файловых систем для Unix
- •6.8. Программный опрос файловой системы
- •7. Обеспечение множественности процессов
- •7.1. Основные понятия теории вычислительных процессов
- •7.2. Программное порождение процессов
- •7.3. Уничтожение процессов
- •7.4. Ожидание завершения процессов
- •8. Многопоточное функционирование ос
- •8.1. Понятие нити и связь Хе с процессом
- •8.2. Создание нитей (thread) в программе
- •8.3. Уничтожение нитей
- •8.4. Приостановка и повторный запуск нити
- •8.5. Ожидание завершения нити
- •9. Средства взаимодействия программных единиц
- •9.1. Абстрактные критические секции
- •9.2. Абстрактные семафоры
- •9.3. Семафоры взаимоисключения
- •9.4. Семафоры событий
- •9.5. Средства группового ожидания
- •9.6. Программные критические секции
- •9.7. Программные семафоры с внутренним счетчиком
- •10. Управление памятью
- •10.1. Виртуальная память
- •10.2. ЏодкРчка страниц для реализациШ виртуальной памяти
- •10.3. Системные функции распределения памяти
- •10.4. Совместное использование памяти
- •10.5. Отображение файлов в оперативную память
- •10.6. Динамически распределяемая память
- •11. Средства коммуникации процессов
- •11.1. Неименованные коммуникационные каналы Unix
- •11.2. Переназначение хэндлов для доступа к каналу
- •11.3. Неименованные каналы в Windows
- •11.4. Именованные каналы в Windows nt
- •11.5. Именованные каналы в Unix
- •12. Взаимодействие пользователя с ос
- •12.1. Интерфейсы операционных систем
- •12.2. Командные и операционные оболочки (shells)
- •12.3. Основные команды базовых операционных систем
- •12.4. Групповое выполнение и фоновый запуск команд
- •12.5. Стандартный ввод-вывод и конвейеры командной строки
- •12.6. Командные файлы и сценарии
- •Библиографический список
6.7. Особенности строения файловых систем для Unix
Принципиальной особенностью файловых систем для Unix является хранение минимальной информации в записях оглавления. Так, в современной расширенной файловой системе для Linux, называемой в сокращении ext2, структура записи каталога описывается структурой
struct dir
{unsigned long inode_num;
unsigned short rec_len;
unsigned short name_len;
char name[256]; /* between 0 and 256 chars */
};
В самой старой файловой системе для Unix, созданной еще в 70-х годах XX века, запись каталога занимала всего 16 байтов, из которых 14 байтов предназначались под имя файла (или каталога), а два оставшихся хранили значение индексного узла (inode).
В современном решении запись каталога имеет переменную длину, определяемую для каждой записи полем rec_len и содержит имя длинной до 255 символов, причем поле name_len задает действительное значение этого имени. Такое решение связано со стремлением, как допускать очень длинные имена и в то же время не делать очень большими записи каталога. По существу, поля rec_len, name_len – вспомогательные, и запись каталога несет все ту же содержательную информацию.
Вся информация о файле (каталоге), за исключением его имени в текущем каталоге, хранится в специализированной структуре файловой системы, называемой индексным узлом (inode). Именно в нем хранится время создания файла (каталога), время последней модификации, время последнего доступа, число ссылок на файл, размер файла. Более подробная информация представлена в описании структуры inode:
typedef struct
{ unsigneg short i_mode; /* File mode */
unsigneg short i_uid; /* Owner Uid */
unsigneg long i_size; /* Size in bytes */
unsigneg long i_atime; /* Access time */
unsigneg long i_ctime; /* Creation time */
unsigneg long i_mtime; /* Modification time */
unsigneg long i_dtime; /* Deletion Time */
unsigneg short i_gid; /* Group Id */
unsigneg short i_links_count; /* Links count */
unsigneg long i_blocks; /* Blocks count */
unsigneg long i_flags; /* File flags */
unsigneg long i_reserved1; /* Reserved 1 */
unsigneg long i_block[15]; /* Pointers to blocks */
unsigneg long i_version; /* File version (for NFS) */
unsigneg long i_file_acl; /* File ACL */
unsigneg long i_dir_acl; /* Directory ACL */
unsigneg long i_faddr; /* Fragment address */
unsigneg char i_frag; /* Fragment number */
unsigneg char i_fsize; /* Fragment size */
unsigneg long i_reserved2[2]; /* Reserved 2 */
} inode;
6.8. Программный опрос файловой системы
Операции по получению данных из файлов и запись в файлы составляют одну из основ программирования и в применении к отдельным ОС уже рассматривались в гл. 2. Кроме этих общеупотребительных функций нередко возникает проблема нахождения в некотором каталоге файлов, удовлетворяющих определенным условиям. В частности, иногда требуется получение информации, какие файлы находятся в некотором каталоге. Для решения подобных задач в операционные системы включены системные функции просмотра содержимого каталогов.
В ОС Unix операции с каталогом строятся подобно операциям с типизированными файлами, используемыми в Паскале, а именно, вводится указатель на структуру данных, описывающую каталог. Эта структура описана в заголовочном файле dirent.h и имеет имя DIR. Указатель на эту структуру данных используется для получения значения от функции opendir, имеющей прототип
DIR* opendir(char *dirname),
где единственный аргумент задает имя того каталога, из которого требуется получить информацию. При невозможности открыть указанный аргументом каталог функция возвращает значение NULL.
Дальнейшие действия выполняются системной функцией с прототипом
struct dirent *readdir(DIR* dirptr),
с аргументом, полученном от предыдущей функции. Каждое выполнение вызова readdir() возвращает указатель на содержимое структуры типа dirent, содержащей информацию об очередном элементе каталога. Эта структура данных описана также в заголовочном файле dirent.h. В последней структуре два основных поля, которые заданы в ней как
ino_t d_ino; /* Номер индексного дескриптора */
char d_name[ ]; /* Имя файла, заканчивающегося нулевым байтом*/
При использовании этих полей каталога следует иметь в виду, что нулевое значение поля d_ino вполне возможно у используемого каталога и обозначает неиспользуемую запись в каталоге (обычно по причине удаления информации о фРйле из данного каталога).
После окончРния использования указателя нР каталог, полученный от функции opendir(), следует выполнить закрытие доступа к каталогу и освобождение ресурсов вызовом функции с прототипом
int closedir(DIR* dirptr),
Вспомогательной функцией работы с каталогами служит описываемая прототипом
void rewinddir(DIR* dirptr),
которая позволяет вернуться к началу каталога с целью чтения его опять с самого начала.
Применение описанных функций демонстрирует программа примера, приведенного в листинге 6.8.1.
#include <unistd.h>
#include <dirent.h>
#include <string.h>
int main()
{DIR *dp;
struct dirent *de;
int len, rc;
dp=opendir(".");
if (dp= =NULL)
{printf("No those files\n"); exit(1);}
while (de=readdir(dp)) {
if (de->d_ino != 0)
{len=strlen(de->d_name);
if (!strcmp(".c",(de->d_name)+len-2))
printf("%s\n",de->d_name);
}
}
closedir(dp);
return 0;
}
Листинг 6.8.1. Программный доступ к информации каталога в Unix
Эта программа последовательно читает все записи текущего каталога (обозначаемого символом '.'), и если запись не пуста, то проверяет, не оканчивается ли имя файла, заданного в этой записи на цепочку символов ".c". При совпадении выполняется вывод имени файла на экран.
В операционных системах типа Windows и OS/2 разработчики включили проверку условия для имени файла в действия соответствующей системной функции. В этих ОС основных функций, работающих с содержимым каталогов, – две: функция поиска первого файла по задаваемому условию и функция поиска следующего файла по тому же условию. Само условие задается как метанотация, т.е. записью совокупности файлов с помощью метасимволов * и ? в соответствующем аргументе имени файла. Использование этих метасимволов полностью совпадает с традиционным их применением в командах операционной системы, восходящим к правилам командного интерпретатора Unix.
В Windows для поиска первого файла в каталоге служит функция с прототипом
HANDLE FindFirstFile(char *metaname, WIN32_FIND_DATA *FindFileData),
где аргумент metaname задает метанотацию файла в текущем каталоге или в явно заданном в аргументе каталоге, а второй аргумент задается адресом (указателем на) экземпляра структуры данных, куда должна быть помещена служебная информация о файле. Поля этой структуры данных, описывающей кроме имени файла еще и вспомогательную информацию, дают среди прочего время последней коррекции и последнего доступа (а также ряд других параметров). Наиболее значимым является поле с именем cFileName, описывающее имя файла массивом символов. При неудаче функция возвращает значение INVALID_HANDLE_VALUE (равное -1), в противном случае она возвращает специальный хэндл, предназначенный для использования только в функции продолжения поиска и закрытия этого хэндла. По существу, упомянутый хэндл соответствует хэндлу каталога, который получается от функции открытия каталога в Unix.
Для поиска следующих файлов, удовлетворяющих той же метанотации, что была задана при выполнении функции FindFirstFile, в Windows служит функция с прототипом
BOOL FindNextFile(HANDLE hFindFile, WIN32_FIND_DATA *FindFileData),
где аргумент hFindFile должен быть получен от функции FindFirstFile, а второй аргумент задает экземпляр структуры для размещения служебной информации о файле и уже рассматривался для предыдущей функции. Последняя функция возвращает значение TRUE, если находит очередной файл в текущем каталоге, удовлетворяющий метанотации, в противном случае она возвращает значение FALSE.
В завершение работы с каталогом должна вызываться функция с прототипом
BOOL FindClose(HANDLE hFindFile),
которая закрывает хэндл, ранее полученный от функции FindFirstFile.
Следующая программа для Windows, приведеная в листинге 6.8.2, демонстрирует поиск в текущем каталоге файлов, которые имеют расширение ".c", с выводом их имен на экран. По существу эта программа полностью соответствует программе в листинге 6.8.1.
#include <stdio.h>
#include <windows.h>
int main()
{HANDLE fdirsearch;
WIN32_FIND_DATA dan;
BOOL rc;
fdirsearch=FindFirstFile("*.c", &dan);
if (fdirsearch= =INVALID_HANDLE_VALUE)
{printf("No those files\n"); exit(1);}
do {
printf("%s\n",dan.cFileName);
rc=FindNextFile(fdirsearch, &dan);
} while(rc!=FALSE);
FindClose(fdirsearch);
return 0;
}
Листинг 6.8.2. Программный доступ к информации каталога в Windows
Для вспомогательных действий по переустановке текущего каталога предназначена в Windows функция с прототипом
BOOL SetCurrentDirectory(char *PathName)),
а также функция с прототипом
DWORD GetCurrentDirectory(DWORD BufferSize, char *Buffer),
которая позволяет запомнить в символьном массиве полное имя текущего каталога.