Главная страница Межпроцессное взаимодействие (состязание) Следующая функция, check mem, используется во время запуска, для того чтобы определить величину блока памяти. Она просто побитово тестирует каждый 16-й байт при помощи контрольных двоичных значений. Хотя функция cp mess (см. ниже) могла бы использоваться для копирования сообщений, есть более быстрая специализированная функция, cp mess. Она вызывается следующим образом: cp mess(source. src clicks. src dest. dest clicks. dest offset): Здесь source - это номер процесса отправителя, который копируется в поле m source буфера адресата. Адреса буферов приемника и отправителя представлены в виде комбинации количества кликов, обычно это базовый адрес сегмента, содержащего буфер, и смещения. Это более эффективная форма представления адресов, чем 32-разрядные целые числа, как в phys copy. Функции exit, exit и exit необходимы потому, что некоторые из библиотечных процедур, которые могут использоваться при компиляции MINIX, способны делать вызовы стандартной функции языка С exit. Она вызывается, когда необходимо выйти из программы, но выход из ядра не имеет смысла, здесь просто некуда выходить. Эта проблема решена так: функция разрешает прерывания и входит в бесконечный цикл. В определенный момент возникает прерывание таймера или от операции ввода/вывода, и система возвращается к нормальной работе. Точка входа с именем main - еще один пример борьбы с поведением компилятора, которое имеет смысл при компиляции пользовательской программы, но бесполезно для ядра. Эта точка входа указывает на ассемблерную инструкцию ret. Функции in byte, Jn word, out byte и out word предоставляют доступ к портам ввода/вывода, которые в архитектуре процессоров Intel занимают отдельное адресное пространство, поэтому для работы с ними требуются инструкции, отличные от обычных инструкций работы с памятью. Передачей блоков данных между портами и памятью заведуют функции port read, port read byte, port write и port write byte. Они используются в основном при взаимодействии с диском, которое должно происходить быстрее, чем это позволяют обычные функции ввода/вывода. Байтовые версии этих функций читают по 8 бит, а не по 16, чтобы соответствовать старым 8-битным периферийным устройствам. Изредка задачам необходима функция, которая временно блокировала бы все прерывания процессора. Это делается путем вызова 1оск. Когда прерывания можно вновь разрешить, вызывается unlock. Каждый из обоих вызовов сводится к одной машинной инструкции. В противоположность этому, функции enable irq и disable irq более сложно устроены. Они работают на уровне контроллера прерываний и разрешают или запрещают отдельные аппаратные прерывания. Функция phys copy вызывается из программы на С следующим образом: phys copy(source address. destination address. bytes): Она копирует блок данных из одной области физической памяти в любое другое место. Оба передаваемых этой функции адреса абсолютные, то есть О означает первый байт адресного пространства. Все три аргумента функции являются по типу беззнаковыми длинными целыми. Две следующие короткие функции очень специфичны для процессоров Intel. Функция mem rdw возвращает 16-битное слово из произвольного места памяти. Результат дополняется нулями и помещается в регистр еах. Функция reset сбрасывает процессор. Для этого в дескриптор прерываний процессора загружается нулевой указатель, после чего вызывается программное прерывание. Результирующий эффект равносилен аппаратному сбросу. Далее идут две функции, поддерживающие работу видеодисплея и вызываемые задачей консоли. Подпрограмма mem vid copy копирует строку, содержащую различные символы и управляющие коды, из области ядра в видеопамять. Функция vid vid copy копирует блок в пределах видеопамяти. Эта функция несколько сложнее, так как возможно перекрывание блоков, поэтому важно учитывать направление копирования. Последняя функция в файле klib386.s - levelO. Она позволяет задачам при необходимости получать более высокий уровень привилегий - нулевой. На данном уровне разрешены такие действия, как сброс процессора или обращение к подпрограммам BIOS. Вспомогательные функции на языке С в файле misc.c специализированы. Функция memjnit вызывается только из main при запуске MINIX. У компьютера IBM PC область памяти может быть не непрерывной, а состоять из нескольких блоков. Размеры нижнего диапазона, который известен пользователям PC как обычная память, и верхнего, который расположен после области ПЗУ, передаются ядру монитором загрузки через параметры, которые затем интерпретируются функцией cstart и помещаются в переменные low memsize и ext memsize. Третья область памяти - это теневая память, в которую может копироваться содержимое BIOS из ПЗУ для увеличения производительности, так как ПЗУ обычно медленнее, чем обычная память произвольного доступа. Поскольку MINIX при своей обычной работе не пользуется BIOS, функция memjnit старается обнаружить такую память и сделать ее доступной. Для этого вызывается функция check mem, проверяющую пул памяти, где ожидаемо присутствие высокопроизводительных участков. Следующая подпрограмма, env parse, также используется в процессе запуска системы. Монитор загрузки передает ядру отдельные параметры через строки подобного вида: DPETH0=300:10 . Функция пытается найти строку, начало которой совпадает с первым переданным ей аргументом, и извлекает значение параметра. Использование этой функции поясняют комментарии в коде. Прежде всего она предназначена для помощи тем, кто хочет разработать новый драйвер, которому могут потребоваться параметры. Показанный пример с параметром DPETH характерен для передачи параметров адаптеру Ethernet, если в ядре включена поддержка сети. Последние две подпрограммы, bad assertion и bad compare, компилируются только в том случае, если макрос DEBUG определен как TRUE. Эти функции поддерживают макросы в assert.h. Хотя на них нет ни одной ссылки в тексте книги, они могут быть полезны при отладке, если читатель захочет создать собственную версию MINIX. Резюме Чтобы скрыть эффект прерываний, операционная система предоставляет концептуальную модель, в которой параллельно выполняются логически упорядоченные процессы. Процессы могут взаимодействовать друг с другом при помощи примитивов межпроцессного взаимодействия, таких как семафоры, мониторы и сообщения. Назначение примитивов в том, чтобы гарантировать, что никакие два процесса не окажутся в критической секции единовременно. Процессы могут находиться в состоянии выполнения, готовности и в приостановленном состоянии и могут переходить из одного состояния в другое, когда тот или иной процесс исполняет один из примитивов взаимодействия между процессами. Примитивы необходимы для решения таких задач, как потребитель-поставщик, задача обедающих философов , задача одновременного чтения и записи и спящего брадобрея . Но даже при использовании примитивов необходимо быть осторожным, во избежание ошибок и взаимных блокировок. Известно много различных алгоритмов планирования, таких как круговой (round-robin), планирование с приоритетами, планирование с многоуровневыми очередями и управление политиками планирования. ОС MINIX поддерживает концепцию процесса и предоставляет примитивы для реализации взаимодействия между процессами. Сообщения не буферизуются, поэтому вызов send завершается успехом только после того, как адресат получит сообщение. Аналогично, вызов receive завершается лишь тогда, когда сообщение уже отправлено. В противном случае сделавший вызов процесс переходит в состояние ожидания. Когда возникает прерывание, на нижнем уровне ядра создается и отправляется сообщение для задачи, ассоциированной с устройством, вызвавшим прерывание. Пусть, например, задача диска делает вызов receive и, передав контроллеру диска команду на чтение блока данных, блокируется. Когда контролер, наконец, считывает запрошенные данные, он вызывает аппаратное прерывание. Код нижнего уровня системы обрабатывает это прерывание и посылает сообщение задаче диска, переводя ее в состояние готовности. Кроме того, обработчик прерывания может напрямую выполнять некоторые действия, например, обработчик прерывания таймера вправе обновлять системное время. За прерыванием может следовать переключение задачи. Когда возникает прерывание, создается новый стек внутри ячейки таблицы процессов, принадлежащей текущему процессу. В этот стек помещается вся информация, необходимая для восстановления его работы. Для того чтобы вновь запустить любой приостановленный процесс, необходимо установить указатель стека на кадр стека в таблице процессов и запустить последовательность инструкций, восстанавливающих регистры процессора. В завершение нужно выполнить возврат по инструкции iretd. Какой из процессов запускать, решает планировщик. Прерывания могут возникать и тогда, когда выполняется код ядра. Эта ситуация обнаруживается процессором, и вместо стека в таблице процессов используется стек самого ядра. Такое вложенное прерывание будет обрабатываться после
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |