Главная страница Межпроцессное взаимодействие (состязание) Наконец, функция main выполнила свое предназначение. Во многих профаммах на С функция main представляет собой цикл, но в данном случае ее задача офаничивается инициализацией. Вызов функции restart запускает первую задачу. После чего управление уже никогда не возвращается в main. Функция .restart представляет собой ассемблерную подпрофамму, код которой находится в mpx386.s. Фактически restart не является самостоятельной функцией. Это промежуточная точка входа в более сложную процедуру. Подробно мы рассмотрим ее в следующем разделе, а пока скажем лишь, что .restart вызывает переключение контекста и управление получает процесс, на который указывает переменная proc ptr. В первый раз restart запускает процесс. Затем эта функция вызывается снова и снова, по мере того как пользовательские процессы, задачи и серверы по очереди получают и теряют управление, либо приостанавливаясь в ожидании ввода, либо по истечении кванта времени. Первой в очереди задач (то есть задачей с индексом О, которому соответствует наименьший из отрицательных номеров) всегда стоит задача консоли, чтобы другие задачи могли использовать консоль для вывода сообщений. Эта задача работает до тех пор, пока не блокируется в ожидании сообщения. Затем управление получает следующая задача, также до момента, пока не попадет в состояние блокировки и т. д. В конечном счете, настанет момент, когда все задачи будут приостановлены, и управление смогут получить менеджер памяти и файловая система. Проработав некоторое время, обе эти составные части системы инициализируются и также переходят в состояние блокировки. Далее управление может получить уже процесс init, который запустит несколько дочерних процессов getty, по одному на каждый терминал. Эти процессы также будут заблокированы до ввода какой-либо информации на терминал. Вот теперь пользователь может войти в систему. Мы рассмотрели процесс запуска MINIX, управляемый кодом из трех файлов, два из которых написаны на С, а один - на ассемблере. В ассемблерном файле, mpx386.s, есть дополнительный код, связанный с обработкой прерываний, обсуждение которого мы отложим до следующего раздела. А пока давайте завершим рассмотрение кратким описанием оставшихся функций из файлов на С. В start.c это процедура k.atoi, преобразующая строку в целое число, и k getenv, необходимая для получения значений переменных окружения ядра, являющихся копией параметров загрузки. Обе эти функции представляют собой упрощенные версии аналогичных функций из стандартной библиотеки, переписанных с целью упрощения ядра. В файле main.с осталась нерассмотренной процедура panic, вызываемая в том случае, когда возникает ситуация, делающая невозможной дальнейшую работу системы. Типичными примерами таких ситуаций являются сбои при чтении критических секторов диска, обнаружение недопустимого состояния или внутрисистемный вызов с неправильными данными. Вызовы printf в этой процедуре в действительности вызывают процедуру printk, чтобы ядро могло выводить сообщения даже в случае, когда нарушен нормальный механизм взаимодействия процессов. 2.6.7. Обработка прерываний в MINIX Особенности обработки прерываний во многом зависят от аппаратной платформы, но у любой системы должны быть элементы с подобной функциональностью. В 32-битных процессорах Intel прерывания генерируются аппаратным обеспечением и в виде электрических сигналов передаются сначала на контроллер прерываний. Это интегральная схема, которая умеет различать несколько подобных сигналов и для каждого из них генерировать уникальный идентификатор на шине данных процессора. У компьютеров с 32-битными процессорами Intel обычно имеется два таких контроллера, каждый из которых обслуживает 8 устройств. Но один контроллер подчинен другому (slave), то есть сигналы с его выхода передаются на вход основного контроллера (master). Таким образом, эта комбинация контроллеров способна обслуживать 15 различных устройств, как показано на рис. 2.17. Прерывание INTA Подтвер)кдение прерывания Главный контроллер прерываний Подчиненный контроллер прерываний IRQ О (часы) - IRQ 1 (клавиатура) - IRQ 3 (tty 2) IRQ4(tty 1) - IRQ 5 (винчестер XT) - IRQ 6 (дисковод) - IRQ 7 (принтер) - IRQ 6 (часы реального времени) - IRQ 9 (перенаправление IRQ2) -IRQ 10 -IRQ 11 -IRQ 12 - IRQ 13 (исключение FPU) - IRQ 14 (винчестер AT) -IRQ 15 Рис. 2.17. Обработка прерываний в 32-битных процессорах Intel Здесь прерывания приходят по одной из линий IRQ п, нарисованных в правой части схемы. Процессор получает сигнал о том, что произошло прерывание, по контакту INT. В ответ на это сообшение процессор посылает по контакту INTA (INTerrupt Acknowledge, подтверждение прерывания) сигнал, по которому контроллер помещает в шину данных информацию, говорящую системе о том, какой из обработчиков вызывать. Программируются контроллеры прерываний при инициализации системы в момент, когда функция main вызывает intrjnit. При профаммировании определяется, какие данные контроллер сформирует на шине данных процессора при поступлении сигнала по каждой из входных линий контроллера, а также устанавливается ряд других параметров контроллера. Передаваемые на шину данные представляют собой 8-разрядное число, используемое далее как индекс в массиве максимум из 256 элементов. В MINIX этот массив содержит 56 элементов, из которых реально задействуются 35. Остальные зарезервированы для будущих версий процессоров Intel или изменений в MINIX. В 32-битной версии системы в записях таблицы содержатся дескрипторы щлю-зов прерываний (interrupt gate descriptor). Каждый дескриптор является 8-байтовой структурой с несколькими полями. Есть несколько режимов обработки прерываний. В том, который принят в MINIX, из нескольких полей дескриптора наибольшее значение для нас будут иметь адрес сегмента памяти, где размещена функция-обработчик, и адрес этой функции внутри сегмента. Получив сигнал прерывания, процессор выполняет код, на который ссылается запись в таблице. Результат полностью эквивалентен ассемблерному вызову int <nnn> Разница только в том, что при аппаратном прерывании адрес процедуры берется не из памяти, а из регистра контроллера. Механизм переключения задач в 32-битных процессорах Intel, как ответ на прерывание, довольно сложен, и изменение значения счетчика команд - только часть этого процесса. Когда процессор, уже обрабатывающий некоторый процесс, получает прерывание, он сначала выделяет новый стек, который будет использоваться для выполнения обработчика. Положение стека определяется значением записи в сегменте состояния задачи (Task State Segment, TSS). Эта структура едина для всей системы и инициализируется при вызове protjnit. Положение стека обновляется при запуске каждого нового процесса так, чтобы новый стек всегда начинался от конца структуры stackframe s в записи в таблице процессов того процесса, который был прерван. Затем процессор автоматически помещает в новый стек значения нескольких регистров, включая нужные для восстановления стека и счетчика команд прерванного процесса. Обработчик прерывания заносит в стек значения дополнительных регистров, заполняя кадр стека, после чего переключается на другой стек, предоставляемый ядром. Этот стек и используется для всех действий по обработке прерывания. Завершив свою работу, обработчик прерывания переключается обратно на кадр стека в таблице процессов (не обязательно на тот, который использовался для предыдущего прерывания), затем самостоятельно извлекает из стека значения дополнительных регистров и выполняет инструкцию iretd (возврат из прерывания). Эта инструкция восстанавливает значения регистров, помещенные в стек процессором, и переключается на исходный стек (до прерывания). Таким образом, генерация прерывания останавливает текущий процесс, а по завершении обработчика запускает процесс, причем не обязательно тот, что был приостановлен. Данная схема отличается от более простых алгоритмов, часто встречающихся во многих ассемблерных программах, тем, что в стеке прерванного процесса не сохраняется никаких данных. Более того, так как стек пересоздается в заранее заданном месте (которое определяется записью в TSS), упрощается управление несколькими параллельно работающими процессами. Все, что нужно для запуска нового процесса, - поместить в указатель стека адрес нового кадра стека, извлечь из стека значения регистров, помещаемые туда программно, и выполнить инструкцию iretd.
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |