netlib.narod.ru | < Назад | Оглавление | Далее > |
В этом разделе в ходе рассмотрения работы примера прерывания (прерывания таймера) связывается воедино все, что читателям уже известно о прерываниях и нижних половинах.
Функция прерывания таймера timer_interrupt связывается с IRQ 0 в строке 6086. Используемая здесь переменная irq0 определяется в строке 5937. Посредством использования функции init_bh (строка 12484) в строке 27972 функция timer_bh регистрируется в качестве нижней половины обработчика прерывания таймера.
Когда IRQ 0 запускается, timer_interrupt считывает некоторые значения из счетчика отметок времени центрального процессора, если таковой имеется (этот счетчик используется некоторыми кодами, не рассматриваемыми в этой книге), а затем вызывает функцию do_timer_interrupt (строка 5758). Кроме выполнения некоторых других задач, эта функция вызывает функцию do_timer, которая является интересной частью прерывания таймера.
27446: Эта верхняя половина таймера представляет для нас интерес.
27448: Обновляет глобальную переменную jiffies, которая отслеживает количество тиков системных часов, произошедших с момента начальной загрузки. (Очевидно, что в действительности выполняется подсчет тиков таймера, произошедших с момента установки прерывания таймера, который не совпадает с моментом начальной загрузки системы.)
27449: Увеличивает число «потерянных» тиков таймера — тиков, которые не были обработаны нижней половиной. Вскоре будет показано, как нижняя половина таймера использует эту переменную.
27450: Верхняя половина выполняется, поэтому ее нижняя половина помечается для скорейшего выполнения.
27451: Кроме отслеживания общего количества тиков таймера, произошедших с момента последнего выполнения нижней половины таймера, необходимо знать, сколько из этих тиков произошло в режиме системы. Повторим снова, вскоре будет показано, зачем это значение нужно нижней половине; а пока, отметим, что значение lost_ticks_system увеличивается, если процесс выполняется в режиме системы (ядра), а не в режиме пользователя.
27453: Если какие-либо задачи ожидают в очереди таймера, нижняя половина очереди таймера помечается как готовая к выполнению (нижняя половина очереди таймера описана несколько ниже). Вот и все, что касается прерывания таймера. Код кажется простым, но в значительной степени это обусловлено тем, что основная часть работы была оправданно передана нижней половине.
27439: Это нижняя половина таймера. Она вызывает функции, предназначенные для обновления связанных со временем статистических данных процесса и самого ядра и для обслуживания таймеров ядра, как в старом, так и в новом формате.
27412: В основном, эта функция обновляет статистические данные: она вычисляет среднюю загрузку системы, обновляет глобальную переменную, которая отслеживает текущее время, и обновляет вычисленный ядром объем времени центрального процессора, который потребуется текущему процессу.
27422: Получает количество тиков таймера, произошедших с момента последнего выполнения нижней половины, и сбрасывает счетчик.
27427: Если данное количество не равно 0 (нормальная ситуация), update_times определяет, сколько из этих тиков произошло в системном режиме.
27429: Обращение к calc_load (строка 27135) для обновления приближения показателя загрузки системы, необходимого ядру.
27430: Обращение к update_wall_time (строка 27311) для обновления xtime, которая отслеживает граничное время.
27433: Обращение к update_process_times (строка 27382), которая вместе со вспомогательной функцией update_one_process (строка 27371) обеспечивает обновление общего времени выполнения текущего процесса. Подобного рода статистика выдается такими общеиспользуемыми программами, как time, top и ps. Несложно заметить, что выдаваемая программами статистика не настоль точна, как этого хотелось бы: если процесс запланирован как такой, который никогда не выполняется в течение прерывания от таймера, он может потреблять циклы ЦП безо всякого отражения в статистических данных. Однако, очень трудно понять, почему и как таким «злостным» процессам удается это делать; для процессов «с хорошими намерениями» статистика естественным образом усредняется.
27313: Вызов update_wall_time_one_tick (строка 27271) для каждого обрабатываемого тика. Это приводит к обновлению глобальной переменной xtime, по возможности синхронизируя ее с реальным временем с целью соответствия с протоколом Network Time Protocol.
27318: Преобразование xtime в микросекунды, лежащие в диапазоне от 0 до 999999. Для исключительно нежелательных событий, отымающих у таймера более секунды, компонент tv_usec, принадлежащий xtime, может содержать значения более 2000000, поэтому данный код не сможет выполнить нормализацию xtime. Однако, xtime будет окончательно нормализована в последующих вызовах.
27135: calc_load вызывается из верхней половины таймера и обновляет приближенное время загрузки системы. Функция, в основном, заинтересует тех, кто желает разобраться, как вычисляется это постоянно присутствующее в памяти число. Рассмотрим кратко данную функцию.
27138: Статическая переменная count запоминает, сколько прошло с момента последнего вычисления среднего времени загрузки. Переменная инициализируется значением LOAD_FREQ, которое определяется в строке 16164 и означает число тиков таймера за пять секунд. Каждое обращение к этой функции приводит к увеличению количества тиков таймера, которые остаются до следующего вычисления загрузки.
27142: Когда количество оставшихся тиков становится меньше 0, наступает время пересчета. (Я ожидал, что в данном случае должно было быть сравнение «меньше либо равно», однако на самом деле используется сравнение «строго меньше». Причина заключается в том, что на практике это различие оказывается весьма незначительным.)
27143: После повторной инициализации count, которая «заведет» его на следующий пятисекундный интервал, функция count_active_tasks (строка 27119) выясняет количество задач, присутствующих в системе. Несмотря на то что реализация count_active_tasks особой сложностью не отличается, все же существует несколько вопросов, которые будут рассматриваться в главе 7.
27144: Макрос CALC_LOAD, определенный в строке 16169, применяется для обновления трех элементов массива avenrun (строка 27116), которые отслеживают загрузку системы за последние 5, 10 и 15 секунд. Как утверждалось в предыдущей главе, арифметика с плавающей запятой изгнана из ядра, поэтому вычисления производятся с фиксированной запятой.
27077: Ядро обладает устарелой возможностью, подобной нижним половинам, которая заключается в следующем: функции ядра могут регистрироваться в специальной таблице, связываться с определенным временем и вызываться при достижении этого времени. Это обеспечивает функция, вызывающая другие функции в случае возникновения необходимости. Поскольку все предназначение функции связано с поддержкой старого кода, она детально рассматриваться не будет. Все что она делает, так это проходит по списку элементов массива timer_table (строка 27109) и обращается к функциям, время вызова которых наступило.
netlib.narod.ru | < Назад | Оглавление | Далее > |