Оброблювач переривань таймера

Тепер, коли ми розібралися, що таке jiffie s і HZ, а також яка роль системного таймера, розглянемо реалізацію обробника переривань системного таймера розбитий на дві частини: частина, залежну від апаратної платформи, і незалежну частину

Підпрограма, яка залежить від апаратної платформи, реєструється як обробника переривань системного таймера і виконується, коли спрацьовує системний таймер Конкретна робота, звичайно, залежить від апаратної платформи, але більшість обробників виконують такі дії

• Захоплюється блокування xtime_lock, яка захищає доступ до змінної jiffies_6 4 та значенням поточного часу-змінної xtirne

• Зчитується або скидається стан системного таймера, якщо це необхідно

• Періодично записується нове значення абсолютного часу в години реального часу

• Викликається апаратно-незалежна підпрограма таймера do_timer () Апаратно-незалежна функція do_time r () виконує значно більше

дій

• Збільшується значення змінної jiffies_6 4 на одиницю (це безпечна операція навіть для 32-розрядних апаратних платформ, оскільки блокування xtime_lock була захоплена раніше)

• Оновлюється статистка використання системних ресурсів, таких як витрачений процесорний час в режимі користувача і в режимі ядра, для процесу, який в даний момент виконується

• Виконуються обробники динамічних таймерів, для яких закінчився період часу очікування (це буде розглянуто в наступному розділі)

• Викликається функція scheduler_tic k (), як було розглянуто в розділі 4

• Оновлюється значення абсолютного часу, який зберігається у змінній xtime

• Обчислюються значення сумнозвісної середній завантаженості системи

(load  average)

Сама по собі підпрограма дуже проста, так як більшість розглянутих дій виконуються іншими функціями

void do_timer(struct pt_regs *regs)

{

jiffies_64++ update_process_times(user_mode(regs)) update_times()

}

Макрос user_mod e () переглядає стан регістрів процесора, regs, і повертає значення 1, якщо переривання таймера виникло в просторі користувача, і значення 0 – якщо в просторі ядра Це дозволяє функції update _ process_time s Про врахувати, що за час між попереднім і даними імпульсами системного таймера процес виконувався в режимі завдання або в режимі ядра

void update_process_times(int user_tick)

{

struct task_struct *p = current

int cpu = smp_processor_id()

int system = user_tick ^ 1

update_one_process(p,user_tick,system,cpu)

run_local_timers()

scheduler_tick(user_tick, system)

}

Функція update_proces s () власне оновлює значення параметрів часу виконання процесу Ця функція ретельно продумана Слід звернути увагу, яким чином за допомогою операції виключає АБО (XOR) досягається, що одна з змінних user_tic k і syste m має значення, рівне нулю, а інша-одиниці Тому у функції update_one_proces s () можна просто додати необхідне значення до відповідних лічильників без використання оператора розгалуження

/*

* Збільшуємо значення відповідного лічильника імпульсів таймера на одиницю

*/

p-&gtutime += user

p-&gtstime += system

Необхідне значення збільшується на 1, а інше залишається без змін Легко помітити, що в такому випадку передбачається, що за час імпульсу системного таймера процес виконувався  в тому ж режимі, в якому він виконується під час приходу переривання Насправді процес міг кілька разів переходити в режим завдання і в режим ядра за останній період системного таймера Крім того, поточний процес може виявитися не єдиним процесом, який виконувався за останній період системного таймера На жаль, без застосування більш складної системи обліку, такий спосіб є найкращим з усіх тих, які надає ядро Це також одна з причин збільшення частоти системного таймера

Далі функція run_local_timer s () позначає відкладені переривання, як готові до виконання (див главу 7, Обробка нижніх половин і відкладені дей-

ствия ), для виконання всіх таймерів, для яких закінчився період часу очікування Таймери будуть розглянуті нижче, в розділі Таймери.

Нарешті, функція schedule_tic k () зменшує значення кванта часу для поточного виконуваних процесів і встановлює прапор need_resched при необхідності Для SMP-машин в цій функції також при необхідності виконується балансування черг виконання Все це обговорювалося в розділі 4

Після повернення з функції update_process_time s () викликається функція update_time s (), яка оновлює значення абсолютного часу

void update_times(void)

{

unsigned long ticks

ticks = jiffies wall_jiffies

if (ticks) {

wall_jiffies += ticks

update_wall_time(ticks)

}

last_time_offset = 0

calc_load(ticks)

}

Значення змінної tick s обчислюється як зміна кількості імпульсів системного таймера з моменту останнього оновлення абсолютного часу У нормальній ситуації це значення, звичайно, дорівнює 1 У рідкісних випадках переривання таймера може бути пропущено, і в такому випадку говорять, що імпульси таймера втрачені Це може статися, якщо переривання заборонені протягом тривалого часу Така ситуація не є нормальною і часто вказує на помилку програмного коду Значення змінної wall_jiffie s збільшується на значення ticks, тому вона дорівнює значенню змінної jiffie s в момент самого останнього оновлення абсолютного часу Далі викликається функція update _ wall_tim e () для того, щоб оновити значення змінної xtime, яка містить значення абсолютного часу Нарешті викликається функція calc_loa d () для того, щоб оновити значення середньої завантаженості системи, після чого функція update_times () повертає управління

Функція do_time r () повертається в аппаратао-залежний обробник переривання, який виконує всі необхідні завершальні операції, звільняє блокування xtirae_lock і зрештою повертає управління

Все це відбувається кожні 1/HZ секунд, тобто 1000 разів на секунду на машині типу

PC

Джерело: Лав, Роберт Розробка ядра Linux, 2-е видання : Пер з англ – М: ТОВ «ІД Вільямс »2006 – 448 с : Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*