Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_по_ОС / ТОС_11_п_вв_выв_слайды.doc
Скачиваний:
43
Добавлен:
03.03.2016
Размер:
6.2 Mб
Скачать

Символьные устройства

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

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

Если процесс сделал системный вызов ввода/вывода, например, read(2)

Или write(2) со специальным файлом символьного устройства, запрос направляется

в файловую подсистему. Поскольку доступ к устройству обслу-

живаемой файловой системой specfs, рассмотренной ранее, в ответ на вы-

полнение системного вызова процесса ядро выполняет вызов функции

spec_read() или spec_write() соответственно для read(2) или write(2).

Действие функций spec read () и spec write () похожи. Обе проверяют тип vnode и определяют, что устройство является символьным. После этого, с помощью коммутатора, ядро выбирает соответствующую точку входа конвейера, используя старший номер, хранящийся в поле v_rdev vnode, вызывает эту функцию (соответственно xxread () или xxwrite(J)), передавая ей в качестве параметров старший и младший номера, ряд дополнительных параметров, зависящих от конкретного вызова, а также явно или неявно адресует область копирования данных в адресном пространст­ве процесса3.

Интерфейс доступа низкого уровня

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

Большинство таких драйверов отличаются от соответствующих им драйверов блочных устройств характером выполнения операций ввода/вывода.

В то время как драйверы блочных устройств производят обмен данными с буферным кэшем,

драйверы доступа низкого уровня обеспечивают обмен данных непосредственно с адресным пространством процесса.

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

Интерфейс доступа низкого уровня используется многими системными утилитами обслуживания файловой системы, например, fsck(lM), а также рядом приложений, работающих с накопителями на магнитной ленте,

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

На рис. 5.8 показаны отличия в характере выполнения операции ввода/вывода с блочными устройствами в случаях, когда запрос формируется при участии буферного кэша (драйверы блочных устройств) и когда манипуляция буфером производится драйвером самостоятельно (драйверы низкого уровня).

Буферизация

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

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

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

Первый способ заключается в использовании прерываний, когда при постотуплении на устройство следующего символа, генерируется аппаратное прерывание, которое обрабатывается функцией xxintr () драйвера не-

зависимо от функции xxwrite (). Функция обработки прерывания записывает данные в буфер, которые затем считываются функцией xxwrite ().

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

Буферизация данных для символьных устройств осуществляется с помо­щью специальных структур данных, называемых clist. Каждая структура clist имеет следующие поля:

int с_сс

struct cblcck *c_cf

struct cblock *c_cl

c_cc содержит число символов в буфере cblock.

c_cf и c_cl указывают, соответственно, на первый и последний элементы cblock,

организованные в виде связанного списка и фактически обеспечивающие буферы хранения данных.

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

Пример буферизации с использованием структуры clist в драйвере терминала показан на рис. 5.10.

Соседние файлы в папке Лекции_по_ОС