Главная страница  Межпроцессное взаимодействие (состязание) 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 [ 80 ] 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

пись исключается, после чего в переменную помещается время из следующей записи в очереди (в данном случае это время равно 4).

Текущее время Следующий ситал

Заголовок таймера

4200

> 3

-> 4

-> 6

> 2

> 1 X

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

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

Некоторым частям операционной системы также необходимо устанавливать таймеры. Это так называемые сторожевые таймеры. Изучая драйвер жесткого диска, мы видели, что каждый раз, когда контроллеру отдается команда, запускается таймер как средство выполнения некоторых действий, если команда не будет выполнена. Кроме того, мы упоминали, что драйвер флоппи-дисковода должен дождаться, пока раскрутится двигатель, а также должен выключить его, если в течение некоторого времени не было сделано ни одного обращения. Существуют принтеры, которые умеют печатать 120 символов/с (8,3 мс/символ), но даже они не в силах выполнить возврат каретки за 8,3 мс, поэтому драйвер принтера должен приостановиться после передачи символа возврата каретки.

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

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



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

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

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

1. HARDJNT

2. GET.UPTIME

3. GET TIME

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

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

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

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

Сообщение GET UPTIME используется для определения времени, прошедшего с момента загрузки системы. GET TIME возвращает количество секунд, отсчитанных с 12 часов дня 1.01.1970, а SET TIME устанавливает текущее время. Последнее сообщение вправе отправлять только суперпользователь.

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

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

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

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



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

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

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

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

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

Каждому пользовательскому процессу разрешается устанавливать только один сигнальный таймер. Если процесс делает системный вызов alarm уже после запуска им другого таймера, предыдущий таймер отменяется. Таким образом, информа-



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 [ 80 ] 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

© 2000 - 2018 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.