Системные часы и таймеры в UNIX

Страницы работы

34 страницы (Word-файл)

Содержание работы

МИНИСТЕРСТВО ОБЩЕГО И ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ

РОССИЙСКОЙ ФЕДЕРАЦИИ

САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ МЕХАНИКИ И

ОПТИКИ

Кафедра

Систем Управления и Информатики

Группа

4145

Реферат на тему:

«Системные часы и таймеры в UNIX»

Автор реферата  

Годгильдиев А.М.

(фамилия, и.о.)

Руководитель

Боженкова Н.Ю.

(фамилия, и.о.)

06

мая

20

08

г.                                      Санкт-Петербург, 200

8

г.

Реферат выполнен с оценкой

 

Дата защиты “

20

08

г.

 

Содержание

Введение………………………………………………………………….……………….3

1 Аппаратное обеспечение часов…………………………… ………………………….4

2 Программное обеспечение часов…………..…………………………………………..6

3 Обзор драйвера часов в MINIX……………………………………………………….12

4 Задача синхронного сигнальноготаймера……………………….. ………………16

5 Обработчик прерывания часов…………………………….………………………...…18

6 Миллисекундные задержки …………………………………………………………….19

7 Резюме …………………………………………………………………………..……...20

8 Реализация драйвера часов в MINIX………………………………………………...22

9 Реализация задачи синхронного сигнального таймера……………………………..27

10 Реализация обработчика прерываний часов……………………………………….28

11 Утилиты для работы со временем………………………………………………….30

Заключение…...…...………………………………………………………………....……32

Литература…...…...…………………………………………..…………………………..33

КСУИ.216445.001 РФ

Изм

Лист

№ док

Подпись

Дата

Разработал

Годгильдиев

Системные часы и таймеры в UNIX. Реферат.

Литера

Лист

Листов

Проверил

Боженкова

2

33

Группа 4145. Кафедра систем управления и информатики.

Н.Контроль

Утвердил

К С У И . 216445. 0 0 1   РФ

Введение

Часы (также называемые таймерами) необходимы для нормального функционирования любой системы с разделением времени. В частности, часы нужны для определения текущего времени, а также для того, чтобы предотвратить монополизацию процессора одним процессом. Программное обеспечение часов может иметь форму драйвера, хотя часы не являются ни блочным, ни символьным устройством. Сначала мы сделаем общий обзор аппаратного и программного обеспечения, а затем рассмотрим, как это реализовано в MINIX.

КСУИ.216445.001 РФ

Лист

3

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


1 Аппаратное обеспечение часов

В компьютерах используются таймеры двух типов, и оба типа заметно отличаются от тех, которые используются людьми. Простейший таймер подключается к линии питания на 110 или 220 В и генерирует прерывание в каждый период колебания переменного напряжения, с частотой 50 или 60 Гц.

Второй тип часов  состоит из трёх компонентов: кварцевого резонатора,  счетчика и регистра. Условная схема приведена на рисунке 1. Кварцевый резонатор представляет собой особым образом прикреплённый кусочек кристалла кварца, который может генерировать колебания с очень высокой стабильностью. Обычно частота колебаний резонатора находится в пределах от 5 до 100 МГц, в зависимости от параметров кристалла. В компьютере практически всегда есть как минимум один такой элемент, который генерирует синхросигнал для различных схем компьютера. Сигнал от резонатора передаётся на счетчик, отсчитывающий время в обратном направлении. Когда значение счетчика становится равным нулю, генерируется прерывание.

У программируемых часов обычно есть несколько режимов работы. В режиме одноразового срабатывания при запуске часов в счетчик помещается значение, сохраненное в регистре, которое затем уменьшается с каждым импульсом от резонатора. Когда значение счетчика достигает нуля, вырабатывается прерывание и таймер останавливается до следующего явного запуска. В режиме прямоугольных импульсов, после того как счетчик доходит до нуля и генерируется прерывание, значение из регистра вновь копируется в счетчик, и процесс повторяется до бесконечности. Эти периодическое прерывание иногда называют «тиками».

КСУИ.216445.001 РФ

Лист

4

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Рисунок 1 – Программируемые часы

Преимущество программируемых часов в том, что их частота может быть изменена программно. Если используется 1-мегагерцовый кристалл импульсы от резонатора приходят каждую микросекунду. В случае 16-разрядного счетчика часы можно запрограммировать на генерацию прерываний с периодом от 1 мкс до 65536 мс. Микросхемы программируемых часов обычно содержат две или три независимо программируемые схемы и имеют некоторые дополнительные настройки (например, отсчет вперед, а не назад, блокирование прерываний и пр.).

Чтобы компьютер не «забыл» текущее время при выключении питания, в большинство систем устанавливаются подпитываемые от батарейки запасные часы, на тех же низковольтных схемах, что и в наручных цифровых часах. Значение времени с этих вспомогательных часов может считываться при запуске системы. Если же таких часов нет, текущее время может запрашиваться у пользователя. Кроме того, существует стандартный протокол, который позволяет узнать текущее время с удаленной системы. Так или иначе, в MINIX, UNIX и некоторых Других системах запрошенное время затем преобразуется в число тиков, прошедших с 12 часов дня 1 января 1970 года по всеобщему скоординированному времени (UTC, ранее говорилось - Гринвичское время). С каждым сигналом от часов значение времени увеличивается на единицу.

КСУИ.216445.001 РФ

Лист

5

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


2 Программное обеспечение часов

Аппаратная часть часов только генерирует прерывания с заданным интервалом. Всё остальное должно делаться программно, в драйвере часов. Функции драйвера часов во многом зависят от операционной системы, но чаще они включают в себя большую часть функций из следующего списка.                   

1. Поддержание текущего значения времени суток.

2. Предотвращение монополизации процессора одним процессом.

3.  Подсчет полезной загрузки процессора.

4.Обработка системного вызова alarm, используемого пользовательскими процессами.

5. Выполнение функции сторожевого таймера для некоторых частей самой системы.

6.  Профилирование, мониторинг и сбор статистики.

Первая из задач, поддержание текущего времени суток (также называемого реальным временем), не сложна. Для этого требуется только увеличивать значение счетчика времени по каждому сигналу от таймера, как говорилось ранее. Единственное, за чем нужно следить, - это число битов в счетчике времени. Если частота сигналов составляет 60 Гц, то 32-разрядный счетчик переполнится примерно за два года. Поэтому понятно, что в 32-битном счетчике нельзя хранить число тиков с 1.01.1970.

У этой проблемы три решения. Первое - использовать 64-битный счетчик, хотя это несколько усложнит поддержание времени, так как изменять его значение требуется много раз в секунду. Второй способ — хранить время в секундах, а не в тиках, задействуя для подсчета тиков в текущей секунде вспомогательный счетчик. Так как 232 секунд составляет примерно 136 лет, этот метод вполне пригоден до XXII века.

КСУИ.216445.001 РФ

Лист

6

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Согласно третьему подходу время считается в тиках, но относительно момента загрузки системы, а не относительно какого-либо фиксированного момента в прошлом. Когда считывается значение вспомогательного таймера или пользователь сам вводит текущее время, вычисляется время загрузки системы и сохраняется в подходящей форме где-либо в памяти. Все три случая демонстрируются на рисунке 2.

Рисунок 2 – Три способа хранения времени:  а – высокоемкий 64-битный счетчик, б – вспомогательный счетчик, в – подсчет от момента загрузки системы.

Второе назначение таймера в том, чтобы не позволять процессу занимать процессор слишком долго. Когда процесс получает управление, планировщик инициализирует счетчик величиной кванта времени, выраженное в тиках. По каждому прерыванию от часов значение счеичика уменьшается на единицу. Когда счетчик достигает нуля, драйвер часов передает планировщику команду запланировать на выполнение следующий процесс.    

КСУИ.216445.001 РФ

Лист

7

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Третья функция часов – это учет утилизации процессора. Самый точный способ - запускать при старте процесса отдельный счетчик. Когда процесс останавливается, значение этого счетчика скажет, сколько времени процесс работал. Чтобы время учитывалось правильно, значение второго счетчика необходимо сохранять в начале прерывания и восстанавливать при выходе из обработчика.

Менее точный, но гораздо более простой способ – использовать указатель на текущий процесс в таблице процессов, хранящийся в глобальной переменной. По каждому сигналу таймера увеличивается значение счетчика в ячейке текущего процесса. Таким образом, каждый такт таймера считается занятым текущим процессом в таблице процессов. Небольшая неувязка такой методики проявляется в той ситуации, когда процесс генерирует множество прерываний. В этом случае все равно будет считаться, что процесс получил полный «тик» времени,  хотя реально он работал гораздо меньше. Но точный учет процессорного времени - слишком дорогостоящая операция, и практически никогда он не делается. В MINIX и во многих других операционных системах процесс может попросить систему передать ему предупредительный сигнал с некоторой заданной задержкой. Обычно в качестве такового используется сигнал ОС, сообщение или что-либо подобное. Примером приложения, которому такое может потребоваться, служит сетевой интерфейс. Здесь необходимо повторно передавать пакет данных, если за некоторое время не поступило подтверждение его получения. Еще один пример — программа-тренажер, где обучаемому дается ограниченное время на ответ.

КСУИ.216445.001 РФ

Лист

8

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Если драйвер часов поддерживает достаточное количество таймеров, он может длякаждого запроса запускать отдельный таймер. Обычно это не так, и драйвер должен имитировать несколько виртуальных таймеров, имея за душой только один физический.

Один из способов опирается на таблицу, в которой хранится время подачи сигнала для всех текущих таймеров, а также на переменную задающую время наступления следующего срабатывания. Каждый раз, когда обновляется текущее время, драйвер проверяет ближайший по времени сигнал. Если его время пришло, сигнал отправляется и драйвер переходит к следующему. Когда ожидается много сигналов, более эффективно имитировать несколько таймеров при помощи единой очереди запросов, отсортированной по времени. Очередьможет быть организована в виде списка, как показано на рисунке 3. Каждая запись в этой очереди хранит число тиков между сигналом в текущей записи и предыдущей. В частности, показанная на рисунке ситуация соответствует сигналам, ожидаемым в моменты времени 4203, 4207, 4213, 4215 и 4216.

КСУИ.216445.001 РФ

Лист

9

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Здесь первое прерывание произойдет через 3 такта таймера. С каждым тиком таймера значение переменной «следующий сигнал» уменьшается на единицу. Когда оно достигает нуля, генерируетсяпервый сигнал из очереди и первая запись исключается, после чего в переменную помещается время из следующей записи в очереди (в данном случае это время равно 4).

Рисунок 3 –Имитация нескольких таймеров на одних часах

Обратите внимание, что при возникновении каждого прерывания часов драйвер должен выполнить несколько действий: увеличить значение реального времени, уменьшить счетчик времени кванта и проверить, равен ли он 0, учесть время работы процессора и уменьшить значение времени сигнального таймера. Все эти действия должны производиться много раз в секунду, поэтому они тщательно программируются в расчете на максимальное быстродействие. [1, Таненбаум, 2005, 250-255].

КСУИ.216445.001 РФ

Лист

10

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Некоторым частям операционной системы также необходимо устанавливать таймеры. Это так называемые сторожевые таймеры. Изучая драйвер жесткого диска, мы видели, что каждый раз, когда контроллеру отдается команда, запускается таймер как средство выполнения некоторых действий, если команда не будет выполнена. Кроме того, мы упоминали, что драйвер флоппи-дисковода должен дождаться, пока раскрутится двигатель, а также должен выключить его, если в течение некоторого времени не было сделано ни одного обращения. Существуют принтеры, которые умеют печатать 120 символов/с (8,3 мс/символ), но даже они не в силах выполнить возврат каретки за 8,3 мс, поэтому драйвер принтера должен приостановиться после передачи символа возврата каретки. Для создания сторожевых таймеров драйвером часов используется тот же механизм, что и для работы с пользовательскими сигналами. Единственное различие в том, что вместо подачи сигнала драйвер часов вызывает подпрограмму обратной связи, адрес которой ему передается при вызове. Эта процедура является частью кода, сделавшего вызов, но благодаря тому, что все драйверы разделяют общее адресное пространство, драйвер часов все равно может обратиться к указанной подпрограмме. Вызываемая подпрограмма затем может выполнить любые необходимые действия, в том числе и возбудить прерывание, хотя на уровне ядра работа с прерываниями неудобна, а сигналы не существуют. Именно поэтому и реализован отдельный механизм сторожевых таймеров. Последний пункт в списке функций драйвера часов – это профилирование. Некоторые операционные системы предоставляют  механизм, благодаря которому пользовательские программы могут получить от системы гистограмму, показывающую, где процессор провел больше времени. Если профилирование поддерживается, то по каждому сигналу таймера проверяется, является ли текущий процесс профилируемым. Если это так, определяется, в каком из диапазонов адресов находится счетчик команд, значение времени для этого диапазона увеличивается на единицу. Этот же механизм пригоден и для профилирования самой системы. [2, Гордеев, 2003, 145]

КСУИ.216445.001 РФ

Лист

11

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


3 Обзор драйвера часов в MINIX

Код драйвера часов в MINIX находится в файле clock.с.  Задача часов может получать шесть типов сообщений с указанными параметрами        

1.  HARD_INT

2.  GET_UPTIME

3.  GET_TIME

4.  SET_TIME (новое значение времени в секундах)

5.  SEL_ALARM (номер процесса, вызываемая подпрограмма, величина задержки)

6.  SET_SYN_AL (номер процесса, величина задержки)

Сообщение HARD_INT отправляется драйверу тогда, когда возбуждается аппаратное прерывание и необходимо выполнить некоторую работу, например нужно послать предупредительный сигнал процессу или процесс работает чересчур долго.

Сообщение GET_UPTIME используется для определения времени, прошедшего с момента загрузки системы. GET_TIME возвращает количество секунд, отсчитанных с 12 часов дня 1.01.1970, a SET_TIME устанавливает текущее время. Последнее сообщение вправе отправлять только суперпользователь.

Когда задается текущее время, драйвер вычисляет, когда была загружена система. Это вычисление возможно благодаря тому, что драйвер знает текущее реальное время, а также знает продолжительность работы системы (в тиках). Реальное время загрузки системы сохраняется в отдельной переменной. Позже, при вызове GET_TIME, текущее время работы системы переводится из тиков в секунды и суммируется со значением времени, сохраненным в переменной при загрузке.

КСУИ.216445.001 РФ

Лист

12

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Вызов SET_ALARM позволяет процессу запустить таймер, который сработает через указанное время (в тиках). Когда пользовательский процесс делает системный вызов alarm, то системный вызов отправляет сообщение менеджеру памяти, который, в свою очередь, отправляет сообщение с информацией о запросе драйверу часов. По исчерпании указанного промежутка времени драйвер часов посылает сообщение обратно менеджеру памяти, который уже заботится о том, чтобы передать сигнал процессу.      

Сообщение SET_ALARM используется также теми задачами, которым необходимо установить сторожевой таймер. В этом случае, когда истекает   указанное время, просто вызывается заранее указанная процедура. Сам драйвер часов не имеет представления о том, что делает эта процедура.

Вызов SET.SYN.AL подобен вызову SET_ALARM, за исключением того, что он устанавливает синхронный сигнальный таймер. Этот вариант отличается тем, что процессу отправляется сообщение вместо передачи ему сигнала или вызова подпрограммы. Задача синхронного сигнального таймера отвечает за диспетчеризацию сообщений процессам-потребителям.

В задаче часов нет никаких значительных структур данных, но она поддерживает несколько локальных переменных, помогающих отслеживать время. Только одна из этих переменных, lost_ticks, - глобальная, она объявлена в файле gloth. Сейчас она не используется. Возможно, в будущем, если в систему будет добавлен драйвер, который может надолго заблокировать прерывания и потерять несколько тактов таймера, она и появится. Если такой драйвер действительно будет написан, программист может увеличивать значение  lost_ticks, чтобы компенсировать время, в течение которого прерывания были запрещены.

КСУИ.216445.001 РФ

Лист

13

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Очевидно, прерывания часов происходят очень часто и необходимо обрабатывать их как можно быстрее. Поэтому в MINIX обработчик прерываний по большей части выполняет минимальное количество действий. Получив управление, обработчик помещает в локальную переменную ticks значение lost_ticks -  после чего опирается на полученное значение при подсчете времени занятости процессора, обновляет значение переменной pending_ticks, а затем сбрасывает переменную lost_ticks в 0. Переменная pending_ticks объявлена как PRIVATE, ее объявление не лежит внутри какой-либо функции, но она видима только в пределах файла clock.c. Еще одна переменная, sched_ticks, также объявлена как PRIVATE. Значение этой переменной уменьшается на единицу с каждый сигналом часов, с целью отслеживать время выполнения процесса. Обработчик отправляет сообщение менеджеру памяти только тогда, когда сработал таймер или истек отведенный процессу квант времени. Благодаря такой схеме в большинстве случаев обработчик прерываний практически сразу завершается.

Когда задача часов получает какое-либо сообщение, она прибавляет значение pending_ticks к переменной realtime, после чего обнуляет pending_ticks. Переменная realtime, вместе с boot_time, позволяет вычислить текущее системное время. Обе эти переменные объявлены как PRIVATE, поэтому остальные части системы в состоянии определить время только отправляя сообщения задаче часов. Несмотря на то что в любой отдельный момент значение переменной realtime может быть неточным, механизм вычисления времени обеспечивает, что при каждом обращении вычисляется точное значение. Другими словами, каждый раз, когда вы их не видите, время может быть неточным.

.

КСУИ.216445.001 РФ

Лист

14

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Для поддержки таймеров в переменную next_alarm записывается время, когда должен сработать ближайший обычный или сторожевой таймер. Обслуживая таймеры, необходимо соблюдать осторожность, так как в момент срабатывания запросивший услугу процесс может быть уже завершен. Поэтому, когда наступает пора отправить сигнал, сначала делается проверка, действительно ли сигнал все еще нужен. Если нужда в нем отпала, никаких действий не выполняется.

Каждому пользовательскому процессу устанавливать только один сигнальный таймер. Если процесс делает системный вызов alarm уже после запуска им другого таймера, предыдущий таймер отменяется. Таким образом, информацию о таймере удобно хранить в таблице процессов, выделяя под нее одно слово в каждой из записей. Для задач при срабатывании таймера должна вызываться некоторая функция, адрес которой должен где-то храниться. Для этой цели предназначен массив watch_dog. Аналогичный массив, syn_table, хранит флаги, отмечающие, установлен ли для процесса синхронный сигнальный таймер.

Общая логика драйвера часов следует той же модели, что и для драйвера диска. Главная программа драйвера представляет собой бесконечный цикл, в котором сообщения принимаются, обрабатываются и отправляются ответные сообщения (кроме случая CLOCK_TICK). Для обработки каждого типа сообщения предусмотрена отдельная процедура. Все эти процедуры, в cooтветствие со стандартным соглашением об именовании, имеют названия вида do_xxx, где вместо xxx подставлется название действия. К сожалению, некоторые компоновщики усекают имена подпрограмм до семи или восьми символов, поэтому имена do_set_alarm и do_set_time потенциально конфликтны. В силу чего выбрано название do_set_alarm. Подобная проблема иногда встречается в MINIX и решается обычно путем корректирования одного из имен.

КСУИ.216445.001 РФ

Лист

15

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


4 Задача синхронного сигнального таймера

В этом разделе мы будем изучать еще одну задачу - задачу синхронного сигнального таймера. Такой таймер аналогичен обычному, за исключением того, что он в заданное время отправляет процессу сообщение, а не вызывает сигнал или выполняет указанную подпрограмму, как это делает обычный таймер. Сигнал или вызов подпрограммы от обычного таймера могут произойти в любой момент работы процесса-инициатора вызова, в то время как сообщение может быть получено только тогда, когда процесс сделает вызов receive. Именно поэтому таймер, работающий с сообщениями, назван синхронным.

Синхронный таймер был добавлен в MINIX для поддержки сетевого сервера, который, как и менеджер памяти или файловая система, работает как отдельный процесс. Часто возникает потребность ограничить время, в течение которого процесс может находиться в заблокированном состоянии, ожидая ввода. Например, при работе с сетью отсутствие подтверждения получения пакета в течение определенного отрезка времени означает сбой при передаче данных. Перед тем как пытаться получить сообщение (это блокирует процесс), сетевой сервер устанавливает синхронный таймер. Так как при срабатывании таймер отправляет процессу сообщение, процесс в некоторый момент обязательно будет разблокирован. Если процесс получает сообщение, то он прежде всего сбрасывает таймер. После этого проанализировав тип или отправителя полученного сообщения, сервер может определить, прибыл ли пакет или же истекло время ожидания. В последнем случае сервер может сделать попытку исправить ошибку, обычно - повторно отправив пакет.                             

КСУИ.216445.001 РФ

Лист

16

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Отправка сообщения синхронным таймером обходится дешевле, чем подача сигнала обычным, так как последнему требуется передавать несколько сообщений и производится значительное количество дополнительных действий. Вызов функции сторожевым таймером происходит быстро, но пригоден только для задач, которые находятся в общем адресном пространстве с ядром. Когда процесс

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

КСУИ.216445.001 РФ

Лист

17

Изм.

К С У И. 2 6 0 3 4 6. 0 0 1  РФК С У И . 2 6 0 3 4 6 . 0 0 1   РФЛист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


5 Обработчик прерывания часов

Как уже описывалось ранее, значение переменной realtime обновляется  не сразу после возбуждения прерывания часов. Подпрограмма, обслуживающая прерывание, обновляет значение переменной pending_ticks, а также выполняет  некоторые дополнительные простые действия, такие как учет  процессорного времени или же уменьшение значения счетчика кванта времени. Сообщение отправляется задаче таймера только в том случае, если требуются более сложные операции. Такое поведение является компромиссом между идеей о том, что задачи MINIX  должны взаимодействовать исключительно при помощи сообщений, и пониманием того, что на практике обработка каждого сигнала таймера потребляет процессорное время. Практика показала, что на медленных машинах переход от реализации, где сообщение отправляется задаче таймера по каждому прерыванию, к описанной выше реализации может привести к повышению производительности до 15 %.

КСУИ.216445.001 РФ

Лист

18

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


6 Миллисекундные задержки

Как еще одна уступка реальности, в файле clock.c имеется несколько подпрограмм, которые позволяют задавать задержки с миллисекундным разрешением. Такие небольшие задержки необходимы для работы с некоторыми устройствами ввода/вывода. Реализовать их при помощи таймеров и механизма передачи сигналов практически невозможно. Находящиеся в этом файле функции должны вызываться задачей напрямую. В их основе старейший и простейший механизм: непрерывный опрос. Непрерывно, с максимально возможной скоростью считывается значение счетчика, используемого для генерации прерываний, и считанное значение преобразуется в миллисекунды. Это делается до тех пор, пока не истечет требуемое время.

КСУИ.216445.001 РФ

Лист

19

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


7 Резюме

Таблица 1 резюмирует различные сервисы, предоставляемые кодом в файле clock.c. Существует несколько путей доступа к таймеру и несколько вариантов выполнения запроса. Некоторые из сервисов доступны для любого процесса, эти сервисы возвращают результат выполнения запроса при помощи сообщения.

Код ядра может запросить текущее время работы системы посредством вызова функции, избегая тем самым лишних затрат на передачу сообщения. Пользовательский процесс может установить таймер, в результате срабатывания которого процесс получит сигнал. Задача также может запросить сторожевой таймер, который вызовет некоторую функцию. Ни один из этих механизмов не может быть использован сервером, но сервер может запросить синхронный сигнальный таймер. Кроме того, код задач или ядра может запросить задержку миллисекундной длительности при помощи функции milli_delay или же встроить в код процедуры ожидания вызовы milli_elapsed, например, во время ожидания при считывании данных из порта.

КСУИ.216445.001 РФ

Лист

20

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Сервис

Способ доступа

Ответ

Клиенты

Gettime

Системный вызов

Сообщение

Любой процесс

Uptime

Системный вызов

Сообщение

Любой процесс

Uptime

Вызов функции

Значение, возвращенное функцией

Ядро и задача

Alarm

Системный вызов

Сигнал

Любой процесс

Alarm

Системный вызов

Активизация сторожевой функции

Задача

Synchronous alarm

Системный вызов

Сообщение

Сервер

Milli_delay

Вызов функции

Активное ожидание

Ядро и задача

Milli_elapsed

Вызов функции

Значение, возвращенное функцией

Ядро и задача

Таблица 1 – Сервисы, предоставляемые программным обеспечением таймера

КСУИ.224345.001 РФ

Лист

21

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


8 Реализация драйвера часов в MINIX

При запуске MINIX вызываются все имеющиеся в системе драйверы. Большинство из них просто делают попытку получить сообщение и блокируются. Драйвер часов, dock_task, также делает такой вызов, но перед этим он вызывает подпрограмму init_clock, настраивая программируемый таймер на работу с частотой 60 Гц. Когда драйвер получает какое бы то ни было сообщение, он прежде всего добавляет значение pending_ticks к переменной realtime и сбрасывает переменную pending_ticks. Это действие потенциально конфликтно с прерыванием таймера, поэтому оно обрамлено вызовами lock и unlock, предотвращающими возможную ситуацию состязания. Главный цикл у драйвера часов точно тот же, что и остальных драйверов: принимается сообщение, вызывается обслуживающая его функция и генерируется ответное сообщение.

КСУИ.216445.001 РФ

Лист

22

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Функция do_clocktick в действительности не вызывается при каждом сигнале таймера, как можно было бы подумать, глядя на ее название. Она вызывается тогда, когда обработчик прерываний определил, что необходимо выполнить некоторые важные действия. Сначала эта функция проверяет, не сработал ли таймер (сигнальный или сторожевой). Если это так, в таблице процессов просматриваются поля с информацией о запущенном таймере. За один проход по таблице может потребоваться обслужить несколько таймеров. Когда обнаруживается процесс, время срабатывания таймера у которого меньше текущего времени или равно ему, но не равно нулю, проверяется соответствующий этому процессу элемент массива watch_dog. Если эта ячейка содержит адрес функции, значит процесс затребовал сторожевой таймер, и функция вызывается. Для проверки значения указателя привлекается тот факт, что в языке С числовое значение одновременно может интерпретироваться и как логическое. Если в таблице обнаружен пустой указатель (в С ему соответствует нулевое значение, интерпретируемое в логическом контексте как ложь), значит, процесс затребовал  обычный таймер, поэтому вызывается функция cause_sig, передающая процессу сигнал SIGALARM.. Запись в массиве watch_dog  используется и тогда, когда сработал синхронный сигнальный таймер. В этом случае в массив вместо адреса сторожевой функции помещается адрес функции cause_alarm. Такой же подход неплох и для обычного таймера, только уже с адресом функции cause_sig, но тогда нам бы пришлось переписать функцию cause_sig так, чтобы она принимала аргументы, а номер процесса определяла бы из глобальной переменной. Или же переписать остальные функции так, чтобы они получали ненужные им аргументы.

КСУИ.216445.001 РФ

Лист

23

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Назначение функции cause_sig – посылать сообщение менеджеру памяти. Здесь сначала нужно определить, ожидает ли менеджер памяти сообщение. Если да, то сообщение о срабатывании таймера отправляется, в противном случае делается отметка передать при первой оказии.

При переборе записей в таблице процессов обновляется значение переменной next_alarm. Перед началом цикла в эту переменную помещается очень большое значение, после чего для каждого процесса, у которого время срабатывания таймера (поле p_alarm) не равно нулю, сравнивается значение p_alarm и next_alarm. При этом в next_alarm помещается меньшее из двух значений.

Закончив облуживание таймеров, do_clocktick приступает к проверке, не подошло ли время запланировать на выполнение следующий процесс. Время кванта выполнения хранится в переменой sched_time, объявленной как PRIVATE. Обычно значение этой переменной декрементируется с каждым тиком таймера. В тех случаях, когда активизируется do_clocktick, обработчик прерывания сам не уменьшает значение переменной, позволяя сделать это функции do_clocktick, которая также проверяет, стало ли значение равно нулю. Значение sched_ticks не сбрасывается при запуске нового процесса (поскольку менеджер памяти и файловая система должны продолжать работать), вместо этого значение сбрасывается через каждые SCHED_NATE тиков. Перед тем как отобрать у текущего процесса процессор, проверяется, что он выполнялся в течение хотя бы одного полного такта планировщика.

КСУИ.216445.001 РФ

Лист

24

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Следующая подпрограмма, do_getuptime, занимает всего одну строчку. Она копирует текущее значение переменной realtime (количество тактов таймера с момента загрузки системы) в соответствующее поле сообщения. Этот метод позволяет любому процессу получить информацию о времени работы системы, но для задач издержки на передачу сообщения чересчур велики, поэтому имеется соответствующая функция, get_uptime, к которой задачи могут обращаться напрямую. Так как эта функция вызывается не через сообщение для задачи часов, ей приходится самостоятельно добавлять к значению realtime количество отложенных тиков. Чтобы в то время, когда делается обращение к переменной pending_ticks, не произошло прерываний таймера, оно обрамлено вызовами lock и unlock.

Функция do_get_time вычисляет текущее значение времени исходя из значения realtime и boot_time (момент загрузки системы в секундах). Функция do_set_time имеет обратное назначение. Она вычисляет новое значение boot_time, основываясь на переданном ей значении реального времени и времени работы системы.

Следующие две подпрограммы, do_setalarm и do_setsvnalarm, настолько похожи, чтомы будем рассматривать их вместе. Обе они сначала извлекают из сообщения информацию о процессе, которому будет передан сигнал, а также время задержки. Затем do_setalarm извлекает адрес функции, которую необходимо вызвать, а несколькими строками далее этот адрес заменяется нулевым указателем, если целевой процесс является пользовательским процессом, а не задачей. Как мы уже видели ранее, подпрограмма do_clocktick сравнивает значение данного указателя с нулем и тем самым определяет, нужно ли послать целевому процессу сигнал или вызвать сторожевую функцию у задачи. Далее обе функции вычисляют оставшееся до срабатывания таймера время (в секундах) и записывают его в ответное сообщение. В завершение обе функции вызывают common_setalarm. При этом do_setsyn_alarm всегда передает common_setalarm значение cause_alarm.

КСУИ.216445.001 РФ

Лист

25

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Функция common_setalarm завершает работу, начатую одной из двух только что описанных функций. Затем она записывает время срабатывания таймера в таблицу процессов, а в массив watch_dog заносит адрес сторожевой функции (этот адрес также может быть равен нулю или быть ссылкой на функцию cause_alarm). Далее функция сверяет все записи в таблице процессов, чтобы определить, какой таймер сработает следующим, точно так же, как это делается в do_clocktick. Код cause_alarm несложен. В элемент массива syn_table, соответствующий целевому процессу, помещается значение TRUE. Кроме того, если задача синхронного сигнального таймера не активна, ей отправляется сообщение, чтобы она «проснулась».

КСУИ.216445.001 РФ

Лист

26

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


9 Реализация задачи синхронного сигнального таймера

Структура задачи синхронного сигнального таймера, syn_alarm_task, следует общей структуре всех задач. После инициализации она переходит в бесконечный цикл, принимающий и отправляющий сообщения. Инициализация сводится к тому, что задача заявляет о своей активности, записывая в переменную syn_al_alive значение TRUE, а после сообщает о том, что ей нечем заняться, обнуляя (FALSE) все элементы массива syn_table. В этой таблице имеются ячейки для всех процессов.

Внешний цикл программы начинается с того, что функция декларирует, что ее работа завершена, после чего управление передается во внутренний цикл. В этом цикле проверяются все записи в массиве syn_tabte. Если обнаруживается процесс, ожидающий сигнала синхронного таймера, соответствующая ему запись сбрасывается, соответствующему процессу отправляется сигнал CLOCK_INT и объявляется, что еще есть поле деятельности. Завершив внутренний цикл, программа не останавливается, ожидая новых сообщений, если не установлен флаг work_done (работа завершена). Если для задачи имеется работа, передавать ей сообщения не нужно, так как cause_alarm обращается к таблице syn_alarm напрямую. В результате, пока имеются сигналы, ожидающие доставки, внешний цикл программы очень быстро проворачивается несколько раз.                                                                              

Фактически эта задача не используется в обычном установочном пакете mINIX. Она будет использоваться сетевым сервером только в том случае, если перекомпилировать ядро, включив поддержку сети. Сетевой сервер нуждается именно в этом механизме потому, чтобы выжидать небольшое время, если ожидаемый пакет не принимается. Кроме того, серверу нельзя послать сигнал, так как сервер должен работать все время, а большинство сигналов по умолчанию «убивают» процесс.

КСУИ.216445.001 РФ

Лист

27

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


10 Реализация обработчика прерываний часов

Код обработчика прерываний часов – пример компромисса  между потребностью делать как можно меньше (ради минимизации времени обработки) и необходимостью изредка выполнять достаточно сложные действия. Обработчик изменяет значения небольшого количества переменных и проверяет значения некоторых других. Код clock_handler начинается с того, что делается учет процессорного времени. В MINIX отслеживается как процессорное время пользовательских процессов, так и время системы. Текущее время отдается пользовательскому процессу, если он исполнялся во время возникновения прерывания. Системное время соответствует случаям, когда исполнялась файловая система или менеджер памяти. Ссылка на последний запланированный пользовательский процесс (два сервера не учитываются) всегда хранится в переменной  bill_ptr. После того как завершены действия по учету процессорного времени, увеличивается значение одной из основных переменных, pending_ticks. Чтобы узнать, нужно ли пробудить терминал пли послать сообщение задаче часов, необходимо знать реальное время, но каждый раз обновлять значение переменной realtime - дорогостоящая операция так как обращение к этой переменной производится через блокировки. Чтобы избежать накладных расходов, обработчик вычисляет собственную версию реального времени в локальной переменной now. Существует небольшая вероятность погрешности в значении этой переменной, но у подобной ошибки не будет серьезных последствий.

КСУИ.216445.001 РФ

Лист

28

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Оставшаяся часть кода обработчика зависит от проверок различных условий. Как терминал, так и принтер нуждаются в том, чтобы время от времени получать управление. Для терминала предусмотрена глобальная переменная tty_timeout, поддерживаемая задачей терминала. Она хранит время, соответствующее моменту получения управления задачей терминала в следующий раз. Для принтера нужно проверить значения нескольких переменных, объявленных в коде модуля принтера как PRIVATE, для этого служит функция pr_restart, которая быстро завершается даже в худшем случае, если принтер не отвечает. Далее делается проверка не имеется ли сработавших таймеров и не завершился ли квант времени, при выполнении этого условия активизируется задача часов. Последнее условие сложное, оно является логической конъюнкцией трех более простых  условий!

Следующий далее код

interrupt(CLOCK);

приводит к тому, что задаче часов отправляется сообщение HARD_INT.

Обсуждая работу do_clocktick, упоминалось, что функция уменьшает вычение переменной sched_ticks и проверяет, не обнулилась ли она, то есть истек ли квант времени. В упомянутом выше сложном составном условии проверяется равенство sched_ticks единице. Если задача часов еще не активизирована, необходимо уменьшить на единицу значение sched_ticks, и если оно стало нулевым, завершить квант. Если это произошло, следует сохранить информацию о том, что текущий процесс был активен в прошедшем кванте. Для чего и переменную prev_ptr копируется текущее значение bill_ptr. [1, Таненбаум, 2005, 255-263]

КСУИ.216445.001 РФ

Лист

29

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


11 Утилиты для работы со временем

Помимо прочего, в файле clock.c есть несколько вспомогательных функций. Многие из этих функций аппаратно-зависимые, и при переносе системы на  другую аппаратную платформу их необходимо переписать. Мы рассмотрим только назначение этих функции, не вдаваясь в детали их работы.      

Функция init_clock вызывается в начале работы задачи часов clock_task. Она устанавливает режим работы и период программируемых часов так, чтобы они «тикали» 60 раз в секунду. Несмотря на то что «скорость процессора* увеличилась с 4,77 МГц у оригинальных IBM PC до сотен мегагерц на современных системах, для программирования таймера используется одно и то же значение константы TIMER_COUNT, вне зависимости от модели компьютера, на котором работает MINIX. У каждого IBM-совместимого компьютера, каким бы быстрым ни был его процессор, для управления различными устройствами, оперирующими временем, имеется сигнал с частотой 14,3 МГц. Примерами устройств, которым необходим таймер, являются последовательный интерфейс и экран.

Функция clock_stop дополняет init_clock. Эта функция не очень нужна, она используется потому, что пользователям MINIX иногда может потребоваться запускать другие операционные системы. Эта функция просто сбрасывает параметр микросхемы таймера, переводя ее в режим работы по умолчанию, как этого могут ожидать MS-DOS и некоторые другие операционные системы.

КСУИ.216445.001 РФ

Лист

30

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Функция milli_delay необходима для задач, которым требуются задержки миллисекундной величины. Она написана на языке С и не содержит аппаратно-специфичного кода, но в ее коде вы увидите технику, которую могли бы ожидать только в низкоуровневых ассемблерных процедурах. Функция инициализирует переменную-счетчик нулем, после чего быстро, в непрерывном цикле, проверяет эту переменную до тех пор, пока она не достигнет нужного значения. Во второй главе мы говорили о том, что такая методика, называемая активным ожиданием, по возможности должна избегаться, но правила не бывают без исключений, это жизнь. За инициализацию счетчика отвечает следующая функция, milli_start, которая просто обнуляет значения двух переменных. Опрос значения счетчика производится при помощи последней функции в файле, milli_elapsed. Она обращается к аппаратному обеспечению часов. Проверяется значение того же самого счетчика, который используется для обратного отсчета тиков таймера, то есть тот, что может дойти до нуля или принять максимальное значение до того, как закончите требуемый временной интервал. Функция milli_elapsed корректирует это поведение. [3, Партыка, 2007, 220-221]

КСУИ.216445.001 РФ

Лист

31

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Заключение

В системе разделения времени ядро предоставляет процессу ресурсы центрального процессора (ЦП) на интервал времени, называемый квантом, по истечении которого выгружает этот процесс и запускает другой, периодически переупорядочивая очередь процессов. Алгоритм планирования процессов в системе UNIX использует время выполнения в качестве параметра. Каждый активный процесс имеет приоритет планирования; ядро переключает контекст на процесс с наивысшим приоритетом. При переходе выполняющегося процесса из режима ядра в режим задачи ядро пересчитывает его приоритет, периодически и в режиме задачи переустанавливая приоритет каждого процесса, готового к выполнению.

Информация о времени, связанном с выполнением, нужна также и некоторым из пользовательских процессов: используемая ими, например, команда time позволяет узнать, сколько времени занимает выполнение другой команды, команда date выводит текущую дату и время суток. С помощью различных системных функций процессы могут устанавливать или получать временные характеристики выполнения в режиме ядра, а также степень загруженности центрального процессора. Время в системе поддерживается с помощью аппаратных часов, которые посылают ЦП прерывания с фиксированной, аппаратно-зависимой частотой, обычно 50-100 раз в секунду. Каждое поступление прерывания по таймеру (часам) именуется таймерным тиком. В настоящем реферате были рассмотрены особенности реализации процессов во времени, включая планирование процессов в системе MINIX, описание связанных со временем системных функций, а также функций, выполняемых программой обработки прерываний по таймеру.

КСУИ.216445.001 РФ

Лист

32

Изм.

Лист

№ докум.

Подп.

Дата

К С У И . 216445. 0 0 1   РФ


Литература

1. Таненбаум Э., Вудхалл А. и др. Операционные системы. Разработка и реализация. – СПб.: «Питер», 2005. – 576с.

2. Гордеев А.В., Молчанов А.Ю.и др. Системное программное обеспечение. – СПб.: Питер, 2003. – 736с.

3. Партыка Т. Л., Попов И. И. и др. Операционные системы, среды и оболочки. – М.: «Форум», 2007. – 399с.

КСУИ.216445.001 РФ

Лист

33

Изм.

Лист

№ докум.

Подп.

Дата

Похожие материалы

Информация о работе