Главная страница Межпроцессное взаимодействие (состязание) Таким образом, когда заголовочный файл включается при компиляции table.c, ключевое слово extern перед объявлениями переменных не ставится (так как в файле table.c макрос EXTERN определен как пустая строка), поэтому все глобальные переменные размещаются в одном месте, в объектном файле table.o. Если вы новичок в программировании на С и не совсем понимаете, к чему приводят описанные вьше действия, не пугайтесь - эти детали в действительности не так важны. Суть в том, что у некоторых компоновщиков многократное включение одного файла может вызвать проблему, так как приводит к многократному объявлению одних и тех же переменных. EXTERN используется для того, чтобы сделать систему более переносимой между различными платформами с потенциально проблематичными компоновщиками. Макрос PRIVATE синонимичен ключевому слову static. Этот макрос всегда применяется для объявления переменных и функций, на которые не будут ссылаться другие компоненты системы, чтобы имена этих объектов не были видимы за пределами того файла, где они объявлены. Как правило, переменные и процедуры необходимо по возможности размещать в локальной области видимости. Макрос PUBLIC определен как пустая строка. Так, например, декларация: PUBLIC void free 2one(Dev t dev. 2one t numb) преобразуется препроцессором в следующий код: void free 2one(0ev t dev. 2one t numb) который, в соответствии с синтаксическими правилами языка С, означает, что функция с именем free zone экспортируется и может быть использована в других файлах. Использовать макросы PRIVATE и PUBLIC необязательно, это только попытка исправить проблемы, вносимые соглащениями С (где по умолчанию имена размещаются в глобальной области видимости, а должно быть наоборот). В оставшейся части файла const.h определяются константы, повсеместно используемые в системе. Так, например, везде и всюду в коде фигурирует величина базового блока памяти, зависящая от архитектуры системы. Кроме того, в этом файле определяются удобные макросы МАХ и MIN, позволяющие для вычисления большего из двух значений применять следующую запись: 2 = МАХ(х. у): Еще один файл, косвенно включаемый при каждой компиляции в главных заголовочных файлах, - это type.h. В нем содержится ряд описаний ключевых типов и связанных с ними числовых констант. Самый важный тип здесь - message (сообщение). Его можно было бы задать как массив определенного количества байтов, но ради хорошего стиля программирования он описан как структура, содержащая объединение различных возможных типов сообщений. Всего имеется шесть форматов сообщений, с именами от mess l до mess 6. В самой структуре message есть поле m source с информацией об отправителе сообщения, поле m type, говорящее о том, каков формат сообщения (например, для задачи таймера это может быть GET TIME), и поля с данными сообщения. Структуры шести типов сообщений показаны на рис. 2.15. На этом рисунке первая и вторая структура кажутся одинаковыми, равно как и вторая и четвертая, что действительно так для 32-разрядных реализаций MINIX на платформе Intel. Но для других машин, где типы int, long и указатели могут иметь другой размер, это не факт. Поэтому для упрощения компиляции и определено шесть различных структур. m source m type m1 i1 ml 12 m1 i3 m1 p1 m1 p2 m1 p3 m source m type m2 И m2 12 m2 is m2 11 ml 12 m2 p1 m source m type mS И mS 12 mS cal m source m type m4 11 m4 12 m4 13 m4 14 m4 15 m source m type m5 c2m53l m5 il m5 i2 m5 l1 m5 i2 m5 13 m source m type m6 il m6 i2 m6 iS m6 il m6 fl Рис. 2.15. Структуры шести типов сообщений, используемых в IVIiNIX. Размеры элементов могут меняться, в зависимости от архитектуры целевой машины. Диаграмма соответствует компьютеру с 32-разрядными указателями, например Pentium (Pro) Когда необходимо передать сообщение, содержащее, к примеру, три целочисленных значения и три указателя, задействуется первая структура. Подобным же образом используются и другие форматы. Как же можно присвоить нужное значение первому целочисленному полю в первой структуре? Предположим, что сообщение имеет имя х. Тогда объединение (union), содержащее параметры сообщения, будет иметь имя x.m u. Чтобы обратиться к первой структуре этого объединения, подставляется имя x.m u.m ml. Наконец, чтобы обратиться к первому целочисленному полю в этой структуре, следует применять запись: x.m u.m ml.mlil. Она довольно многословна, поэтому после описания самого типа message описываются несколько макроопределений, слегка укорачивающих запись. Так, x.m u.m ml.mlil становится заменяемой x.mljl. Укороченные имена имеют следующий формат: они начинаются с буквы т , затем следует номер структуры, знак подчеркивания, один или два символа, обозначающие тип значения (целое число, указатель, длинное целое, символ, массив символов, функция), после чего записывается число, позволяющее локализовать нужное поле в структуре. Отступая в сторону, при обсуждении форматов сообщений имеет смысл обратить внимание на то, что операционная система и компилятор зачастую понимают такие вещи, как размещение структур, что может упростить жизнь профаммиста. В MINIX поля с типом int зачастую используются для хранения беззнаковых целых значений. В некоторых случаях это опасно ошибками переполнения, но система написана в расчете на то, что компилятор без потерь может присваивать значения типа unsigned переменным типа int и наоборот без изменения данных или возникновения переполнения. При более строгом подходе нужно было бы заменить каждую такую целочисленную переменную объединением, состоящим из поля int и поля unsigned. То же самое относится и к полям типа long, которые иногда используются для передачи данных типа unsigned long. Кто-то может сказать, что мы поступаем неправильно, но если вы собираетесь перенести MINIX на новую платформу, то вам почти наверняка придется сколько-то поработать над точным форматом сообщений, теперь же вы предупреждены, что поведению компилятора также нужно уделить немало внимания. Есть в каталоге include/minix еще один файл, сквозной по всей системе благодаря тому, что включен в основные заголовочные файлы. Это файл syslib.h, содержащий прототипы библиотечных функций языка С, которые в системе используются для доступа к прочим службам ОС. Библиотеки С не обсуждаются в книге, но больщая часть из них стандартна и поставляется с любым компилятором. Тем не менее сами функции, прототипы которых содержатся в файле syslib.h, специфичны для операционной системы, и при переносе MINIX на новую платформу с другим компилятором должны быть переписаны. К счастью, последнее несложно, так как назначение этих функций в том, чтобы извлечь нужные параметры, заполнить ими структуру сообщения, после чего отправить сообщение и извлечь ожидаемые значения из ответа. Как правило, в каждом таком случае требуется не больше дюжины строк кода. В MINIX, когда процессу нужно сделать системный вызов, он посылает сообщение файловой системе (или, для краткости, FS) или менеджеру памяти (ММ). Каждое такое сообщение должно содержать номер требуемого системного вызова. Соответствующие номера перечислены в файле callnr.h. В файле com.h находятся описания, в основном актуальные при взаимодействии менеджера памяти или файловой системы с задачами ввода/вывода. Кроме того, здесь же указаны номера, соответствующие разным задачам. Задачам присвоены отрицательные номера, чтобы можно было отличать их от процессов. В этом же заголовочном файле описаны типы сообщений (коды функций), которые могут быть посланы каждой из задач. Например, задача таймера воспринимает коды SET ALARM (установка таймера), CLOCK TICK (возникновение прерывания таймера), GET TIME (запрос времени) и SET TIME (установка времени). Ответ на сообщение GET TIME имеет код REAL TIME. Наконец, в каталоге include/minix содержатся несколько более специфических заголовочных файлов. Среди них - boot.h, который необходим ядру и файловой системе для детектирования устройств и доступа к данным, переданным программе boot. Еще один файл - key тар. h, задает структуры, необходимые для реализации различных национальных раскладок клавиатур. Этот файл нужен программам, генерирующим и загружающим таблицы символов. Другие файлы каталога, такие как partition.h, представляют интерес исключительно для ядра и не требуются файловой системе или менеджеру памяти. Кроме того, если в вашей реализации системы имеется поддержка дополнительных устройств ввода/вывода, то в этом каталоге будут находиться еще несколько подобных файлов, поддерживающих взаимодействие с 1/О-устройствами. Структура каталога include/minix требует дополнительного пояснения. Дело в том, что в идеале пользовательские профаммы должны взаимодействовать с устройствами ввода/вывода исключительно через операционную систему, тогда подобные файлы должны были быть размещены в src/kernel. Тем не менее реалии работы с системой требуют, чтобы
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |