В функции программы обработки прерываний по таймеру входит:
• перезапуск часов,
• вызов на исполнение функций ядра, использующих встроенные часы,
• поддержка возможности профилирования выполнения процессов в режимах ядра и задачи;
• сбор статистики о системе и протекающих в ней процессах,
• слежение за временем,
• посылка процессам сигналов 'будильника' по запросу,
• периодическое возобновление процесса подкачки (см. следующую главу),
• управление диспетчеризацией процессов.
Некоторые из функций реализуются при каждом прерывании по таймеру, другие — по прошествии нескольких таймерных тиков. Программа обработки прерываний по таймеру запускается с высоким приоритетом обращения к процессору, не допуская во время работы возникновения других внешних событий (таких как прерывания от периферийных устройств). Поэтому программа обработки прерываний по таймеру работает очень быстро, за максимально-короткое время пробегая свои критические отрезки, которые должны выполняться без прерываний со стороны других процессов. Алгоритм обработки прерываний по таймеру приведен на Рисунке 8.9.
#include ‹sys/types.h›
#include ‹sys/stat.h›
#include ‹sys/signal.h›
main(argc, argv)
int argc;
char *argv[];
{
extern unsigned alarm();
extern wakeup();
struct stat statbuf;
time_t axtime;
if (argc != 2) {
printf('только 1 аргумент
');
exit();
}
axtime = (time_t) 0;
for (;;) {
/* получение значения времени доступа к файлу */
if (stat(argv[1], &statbuf) == -1) {
printf('файла с именем %s нет
', argv[1]);
exit();
}
if (axtime != statbuf.st_atime) {
printf('к файлу %s было обращение
', argv[1]);
axtime = statbuf.st_atime;
}
signal(SIGALRM, wakeup); /* подготовка к приему сигнала */
alarm(60);
pause(); /* приостанов до получения сигнала */
}
}
wakeup() {}
Рисунок 8.8. Программа, использующая системную функцию alarm
алгоритм clock
входная информация: отсутствует
выходная информация: отсутствует
{
перезапустить часы; /* чтобы они снова посылали прерывания */
if (таблица ответных сигналов не пуста)
{
установить время для ответных сигналов;
запустить функцию callout, если время истекло;
}
if (профилируется выполнение в режиме ядра)
запомнить значение счетчика команд в момент прерывания;
if (профилируется выполнение в режиме задачи)
запомнить значение счетчика команд в момент прерывания;
собрать статистику о самой системе;
собрать статистику о протекающих в системе процессах;
выверить значение продолжительности ИЦП процессом;
if (прошла 1 секунда или более и исполняется отрезок, не являющийся критическим)
{
for (всех процессов в системе)
{
установить 'будильник', если он активен;
выверить значение продолжительности ИЦП;
if (процесс будет исполняться в режиме задачи) выверить приоритет процесса;
}
возобновить в случае необходимости выполнение процесса подкачки;
}
}
Рисунок 8.9. Алгоритм обработки прерываний по таймеру
8.3.1 Перезапуск часов
В большинстве машин после получения прерывания по таймеру требуется программными средствами произвести перезапуск часов, чтобы они по прошествии интервала времени могли вновь прерывать работу процессора. Такие средства являются машинно-зависимыми и мы их рассматривать не будем.
8.3.2 Внутренние системные тайм-ауты
Некоторым из процедур ядра, в частности драйверам устройств и сетевым протоколам, требуется вызов функций ядра в режиме реального времени. Например, процесс может перевести терминал в режим ввода без обработки символов, при котором ядро выполняет запросы пользователя на чтение с терминала через фиксированные промежутки времени, не дожидаясь, когда пользователь нажмет клавишу 'возврата каретки' (см.раздел 10.3.3). Ядро хранит всю необходимую информацию в таблице ответных сигналов (Рисунок 8.9), в том числе имя функции, запускаемой по истечении интервала времени, параметр, передаваемый этой функции, а также продолжительность интервала (в таймерных тиках) до момента запуска функции.
Пользователь не имеет возможности напрямую контролировать записи в таблице ответных сигналов; для работы с ними существуют различные системные алгоритмы. Ядро сортирует записи в этой таблице в соответствии с величиной интервала до момента запуска функций. В связи с этим для каждой записи таблицы запоминается не общая продолжительность интервала, а только промежуток времени между моментами запуска данной и предыдущей функций. Общая продолжительность интервала до момента запуска функции складывается из промежутков времени между моментами запуска всех функций, начиная с первой и вплоть до текущей.