Роберт Лав - Разработка ядра Linux
- Название:Разработка ядра Linux
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2006
- Город:Москва
- ISBN:5-8459-1085-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роберт Лав - Разработка ядра Linux краткое содержание
В книге детально рассмотрены основные подсистемы и функции ядер Linux серии 2.6, включая особенности построения, реализации и соответствующие программны интерфейсы. Рассмотренные вопросы включают: планирование выполнения процессов, управление временем и таймеры ядра, интерфейс системных вызовов, особенности адресации и управления памятью, страничный кэш, подсистему VFS, механизмы синхронизации, проблемы переносимости и особенности отладки. Автор книги является разработчиком основных подсистем ядра Linux. Ядро рассматривается как с теоретической, так и с прикладной точек зрения, что может привлечь читателей различными интересами и потребностями.
Книга может быть рекомендована как начинающим, так и опытным разработчикам программного обеспечения, а также в качестве дополнительных учебных материалов.
Разработка ядра Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Контекст прерывания
При выполнении обработчика прерывания или обработчика нижней половины, ядро находится в контексте прерывания . Вспомним, что контекст процесса — это режим, в котором работает ядро, выполняя работу от имени процесса, например выполнение системного вызова или потока пространства ядра. В контексте процесса макрос current
возвращает указатель на соответствующее задание. Более того, поскольку в контексте процесса процесс связан с ядром, то контекст процесса может переходить в состояние ожидания или использовать функции планировщика каким- либо другим способом..
В противоположность только что рассмотренному, контекст прерывания не связан ни с одним процессом. Макрос current
в контексте прерывания является незаконным (хотя он и указывает на процесс, выполнение которого было прервано). Так как нет процесса, то контекст прерывания не может переходить в состояние ожидания (sleep) — действительно, каким образом можно перепланировать его выполнение? Поэтому некоторые функции ядра не могут быть вызваны из контекста прерывания. Если функция может переводить процесс в состояние ожидания, то ее нельзя вызывать в обработчике прерывания, что ограничивает набор функций, которые можно использовать в обработчиках прерываний.
Контекст прерывания является критичным ко времени исполнения, так как обработчик прерывания прерывает выполнение некоторого программного кода. Код же самого обработчика должен быть простой и быстрый. Использование циклов проверки состояния чего-либо (busy loop) крайне нежелательно. Это очень важный момент. Всегда следует помнить, что обработчик прерывания прерывает работу некоторого кода (возможно, даже обработчика другой линии запроса на прерывание!). В связи со своей асинхронной природой обработчики прерываний должны быть как можно более быстрыми и простыми. Максимально возможную часть работы необходимо изъять из обработчика прерывания и переложить на обработчик нижней половины, который выполняется в более подходящее время.
Возможность установить стек контекста прерывания является конфигурируемой. Исторически, обработчик прерывания не имеет своего стека. Вместо этого он должен был использовать стек ядра прерванного процесса [31] Какой-нибудь процесс выполняется всегда. Если не выполняется никакой процесс, то выполняется холостая задача (idle task).
. Стек ядра имеет размер две страницы памяти, что обычно соответствует 8 Кбайт для 32-разрядных аппаратных платформ и 16 Кбайт для 64-разрядных платформ. Так как в таком случае обработчики прерываний совместно используют стек, то они должны быть очень экономными в отношении того, что они в этом стеке выделяют. Конечно, стек ядра изначально является ограниченным, поэтому любой код ядра должен принимать это во внимание.
В ранних версиях ядер серии 2.6 была введена возможность ограничить размер стека ядра от двух до одной страницы памяти, что равно 4 Кбайт на 32-разрядных аппаратных платформах. Это уменьшает затраты памяти, потому что раньше каждый процесс требовал две страницы памяти ядра, которая не может быть вытеснена на диск. Чтобы иметь возможность работать со стеком уменьшенного размера, каждому обработчику прерывания выделяется свой стек, отдельный для каждого процессора. Этот стек называется стеком прерывания . Хотя общий размер стека прерывания и равен половине от первоначально размера совместно используемого стека, тем не менее в результате выходит, что суммарный размер стека получается большим, потому что на каждый стек прерывания выделяется целая страница памяти.
Обработчик прерывания не должен зависеть от того, какие настройки стека используются и чему равен размер стека ядра. Всегда необходимо использовать минимально возможное количество памяти в стеке.
Реализация системы обработки прерываний
Возможно, не вызовет удивления, что реализация системы обработки прерываний в операционной системе Linux очень сильно зависит от аппаратной платформы. Она зависит от типа процессора, типа контроллера прерываний, особенностей аппаратной платформы и устройства самой вычислительной машины.
На рис. 6.1 показана диаграмма пути, который проходит запрос на прерывание в аппаратном обеспечении и в ядре.

Рис. 6.1. Прохождение запроса на прерывание в аппаратном обеспечении и в ядре
Устройство инициирует прерывание путем отправки электрического сигнала контроллеру прерывания по аппаратной шине. Если соответствующая линия запроса на прерывание не запрещена (линия может быть в данный момент времени замаскирована), то контроллер прерываний отправляет прерывание процессору. Для большинства аппаратных платформ это осуществляется путем подачи сигнала на специальный вывод процессора. Если прерывания не запрещены в процессоре (может случиться, что они запрещены), то процессор немедленно прекращает ту работу, которую он выполнял, запрещает систему прерываний, осуществляет переход на специальный предопределенный адрес памяти и начинает выполнять программный код, который находится по этому адресу. Этот предопределенный адрес памяти устанавливается ядром и является точкой входа в обработчики прерываний.
Прохождение прерывания в ядре начинается из жестко определенной точки входа, так же как и в случае системных вызовов. Для каждой линии прерывания существует своя уникальная точка, куда переходит процессор. Именно этим способом ядро получает информацию о номере IRQ приходящего прерывания. В точке входа сначала в стеке ядра сохраняется значение номера прерывания и значения всех регистров процессора (которые соответствуют прерванному заданию). После этого ядро вызывает функцию do_IRQ()
. Далее, начиная с этого момента, почти весь код обработки прерываний написан на языке программирования С, хотя несмотря на это код все же остается зависимым от аппаратной платформы.
Функция do_IRQ()
определена следующим образом.
unsigned int do_IRQ(struct pt_regs regs);
Так как соглашение о вызовах функций в языке С предусматривает сохранение аргументов функций в вершине стека, то структура pt_regs
содержит первоначальные значения всех регистров процессора, которые были сохранены ассемблерной подпрограммой в точке входа. Так как значение номера прерывания также сохраняется, то функция do_IRQ()
может это значение восстановить. Для аппаратной платформы x86 код будет следующим.
int irq = regs.orig_eax & 0xff;
После вычисления значения номера линии прерывания, функция do_IRQ()
отправляет уведомление о получении прерывания и запрещает доставку прерываний с данной линии. Для обычных машин платформы PC, эти действия выполняются с помощью функции mask_and_ack_8295A()
, которую вызывает функция do_IRQ()
. Далее функция do_IRQ()
выполняет проверку, что для данной линии прерывания зарегистрирован правильный обработчик прерывания, что этот обработчик разрешен и что он не выполняется в данный момент. Если все эти условия выполнены, то вызывается функция handle_IRQ_event()
, которая выполняет установленные для данной линии обработчики прерывания. Для аппаратной платформы x86 функция handle_IRQ_event()
имеет следующий вид.
Интервал:
Закладка: