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

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

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

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

Задача терминала не пробуждается прерываниями терминала напрямую, так как это привело бы к значительным накладным расходам. Часы отправляют сообщение задаче терминала на следующий тик после того, как произошло прерывание терминала. Печатая со скоростью 100 слов/мин, машинистка вводит за секунду менее десяти символов. Поэтому даже если машинистка работает очень быстро, прерывание будет возникать для каждого символа. Если буфер переполнится, вводимые символы могут быть потеряны, но практика показывает, что буфер в 32 символа вполне удовлетворителен. В случае других устройств ввода скорость поступления может быть в тысячи раз выше, чем скорость работы машинистки, пример тому - последовательный порт, к которому подключен модем со скоростью 28 ООО бит/с. На такой скорости между тиками может быть получено около 48 символов, а если используется сжатие данных, скорость передачи данных может возрасти как минимум вдвое. Поэтому для последовательных линий в MINIX предусмотрен буфер объемом 1024 символа.

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

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



ляющий выбрать при данных условиях лучший вариант. Немалый опыт разработки операционных систем собран у Lampson (1984) и Brooks (1975). Эти книги, хотя и не новы, остаются классикой.

В завершение нашего обсуждения терминального ввода мы подведем итог и рассмотрим все события, которые происходят, когда задача терминала впервые активизируется по запросу на чтение или когда она повторно получает управление после клавиатурного ввода (рис. 3.25). В первом случае, когда задача терминала получает сообщение, запрашивающее вводимые с клавиатуры символы, главная процедура, tty task, вызывает do read, которая и выполняет запрос. Если имеющейся в буфере информации недостаточно для выполнения запроса, процедура сохраняет параметры запроса в tty table.

После этого, чтобы получить уже введенные данные, вызывается in transfer, а затем - handle events, которая, в свою очередь, вызывает kb read и еще раз in transfer, чтобы вытянуть из входного потока еще несколько символов. Функция kb read несколько раз вызывает другие подпрограммы, не показанные на рис. 3.25. Если нет доступных данных, ничего не копируется. Когда вызовы in transfer или handle events полностью выполнили запрос, файловой системе отправляется сообщение, чтобы она могла разблокировать запросивший данные процесс. Если чтение не завершено (не введено ни одного символа или введено недостаточное количество), функция do report информирует об этом файловую систему, чтобы та могла либо заблокировать вызвавший процесс, либо, если было запрошено неблокирующее чтение, отменить запрос.

Прием сообщения - ~ - Прием сообщения

от пользовательского - от часов

процесса

do read handle events

(JrTtrans

ndle evente kb read (njransferj

7Г\ -

Прочие функции

kb read ( transferj

Прочие функции

Рис. 3.25. Обработка ввода драйвером терминала. Правая часть соответствует процессу, запросившему символ. Левая часть выбирается, когда драйвер получил сообщение

о введенном символе

Правая часть рис. 3.25 подытоживает все события, возникающие, когда задача терминала просыпается вследствие прерывания от клавиатуры. Когда напечатан символ, обработчик прерываний kb hw int помещает его код в клавиатурный буфер, устанавливает флаг, позволяющий определить, какому из устройств на-



правлен ввод, и завершает работу. Обработка символа продолжится через небольшой временной интервал, на следующем тике таймера. При этом задача часов отправляет задаче терминала сообщение, говорящее ей о том, что что-то произошло. Получив такое сообщение, tty task проверяет наличие флага события у всех терминалов. Для каждого устройства, у которого флаг установлен, она вызывает handle event. Последняя для клавиатуры вызывает функции kb read и in transfer, как это делается и при получении исходного запроса на чтение. Отраженные в правой части рисунка события могут происходить несколько раз, до тех пор пока не поступит достаточное для выполнения запроса количество символов. Этот запрос поступает к do read после первого сообщения от файловой системы. Если файловая система пытается инициировать новый запрос до того, как устройство обслужило предыдущий, возвращается ошибка. Естественно, все устройства независимы; запрос на чтение с удаленного терминала обрабатывается отдельно от запроса чтения с клавиатуры.

Не показанные на рисунке функции, вызываемые kb read, это: тар кеу - преобразующая коды клавиш (коды опроса клавиатуры), генерируемые аппаратным обеспечением в АЗСП-коды, make break - отслеживающая состояние клавиш-модификаторов (таких как SHIFT), и in process - ответственная за такие возможности, как удаление неправильно введенного символа, обработка различных специальных символов и управление параметрами терминала. Кроме того, in process вызывает функцию echo, чтобы вводимые символы отображались на терминале.

Терминальный вывод

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

Обычно, когда процесс хочет что-нибудь напечатать, он вызывает printf. Эта функция делает системный вызов write, который отправляет файловой системе сообщение с указателем на символы, подлежащие выводу (но не сами символы). Затем файловая система посылает сообщение драйверу терминала, а тот копирует переданные ему символы в видеопамять. Основные подпрограммы, из которых складывается терминальный вывод, показаны на рис. 3.26.

Когда задача терминала получает сообщение, требующее от нее вывести что-либо на экран, вызывается подпрограмма do write, которая сохраняет параметры в соответствующей выбранной консоли структуре tty в массиве tty table. Затем вызывается handle event (та же функция, которая отрабатывает при обнаружении установленного флага tty events).



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.
Копирование материалов разрешено исключительно при условии цититирования.