<<
>>

Сокрытие аппаратуры

Большое количество аппаратуры весьма неудобно в использовании. Его следует скрывать на ранней стадии реализации системы (если только оно не предоставляет особых возможностей). Некоторые детали самого нижнего уровня могут быть скрыты уровнем вроде HAL.
Однако есть детали, которые таким способом скрыть невозможно.

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

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

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

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

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

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

центрального процессора, длины слова, блока MMU и т. д. Представьте себе операционную систему, которая должна работать на компьютерах с процессорами линейки IA32 микропроцессоров x86 (иногда называемой x86-32) и UltraSPARC, требующих различных программ инициализации. Процедура init может быть написана так, как показано в листинге 12.3, а. В зависимости от значения константы CPU, определяемой в заголовочном файле config.h, будет выполняться либо один тип инициализации, либо другой.

Поскольку в двоичном файле содержится только один вариант программы, потери эффективности не происходит.

Листинг 12.3. Условная компиляция, зависящая: а — от типа центрального процессора; б — от длины слова

#include "config.h" init( )

{

#if (CPU == IA32)

/* Здесь инициализация для IA32 */

#endif

#if (CPU == ULTRASPARC)

/* Здесь инициализация для UltraSPARC */ #endif }

б

В качестве второго примера предположим, что нам требуется тип данных Regis-ter, который должен состоять из 32 бит на компьютере с процессором IA32 и 64 бит на компьютере с процессором UltraSPARC. Этого можно добиться при помощи условного кода, приведенного в листинге 12.3, б (при условии, что компилятор воспринимает тип int как 32-разрядное целое, а тип long — как 64-разрядное). Как только это определение дано (возможно, в заголовочном файле, включаемом во все остальные исходные файлы), программист может просто объявить переменные типа Register и быть уверенным, что эти переменные имеют правильный размер.

Разумеется, заголовочный файл config.h должен быть определен корректно. Для процессора IA32 он может выглядеть примерно так:

#define CPU IA32 #define WORD_LENGTH 32

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

#define CPU ULTRASPARC #define WORD_LENGTH 64

Некоторые читатели могут удивиться, почему переменные CPU и WORD LENGTH управляются различными макросами. В определении константы Register можно сделать ветвление программы, устанавливая ее значение в зависимости от значения константы CPU, то есть устанавливая значение константы Register равной 32 битам для процессора IA32 и 64 битам для процессора UltraSPARC. Однако эта идея не слишком удачна. Что произойдет, если позднее мы соберемся переносить систему на 32-разрядный

процессор ARM? Для этого нам пришлось бы добавить третий условный оператор в листинг 12.3 б для процессора ARM. При том, как это было сделано, нужно только добавить строку

#define WORD_LENGTH 32

в файл config.h для процессора ARM.

Этот пример иллюстрирует обсуждавшийся ранее принцип ортогональности. Участки системы, зависящие от типа центрального процессора, должны компилироваться с использованием условной компиляции в зависимости от значения константы CPU, а для участков системы, зависимых от размера слова, должен использоваться макрос WORD LENGTH. Те же соображения справедливы и для многих других параметров.

<< | >>
Источник: Э. ТАНЕНБАУМ Х. БОС. СОВРЕМЕННЫЕ ОПЕРАЦИОННЫЕ СИСТЕМ Ы 4-е ИЗДАНИЕ. 2015

Еще по теме Сокрытие аппаратуры:

  1. АППАРАТУРА ПСИХОЛОГИЧЕСКАЯ
  2. Статья 220. Сокрытие устойчивой финансовой несостоятельности
  3. Статья 396. Сокрытие преступления
  4. 1. Создание видимости одного преступления для сокрытия другого
  5. Статья 232-2. Сокрытие информации о деятельности эмитента
  6. Статья 256. Содействие участникам преступных организаций и сокрытие их преступной деятельности
  7. Статья 238. Сокрытие или искажение сведений об экологическом состоянии или заболеваемости населения
  8. Статья 298-1. Уничтожение, повреждение или сокрытие документов или уникальных документов Национального архивного фонда
  9. ТЕСТ АППАРАТУРНЫЙ
  10. Правило выявления «индивидуального действия» на основе установления стабильности действия во времени.
  11. 3. Клад
  12. Статья 235. Правовые следствия притворной сделки
  13. Передвижная телевизионная станция
  14. Статья 221. Незаконные действия при банкротстве
  15. § 13. Открытие клада как основание возникновения права собственности (п. 1386, 1387)