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

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

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

Чтение с терминала фундаментально отличается от чтения с диска. Драйвер диска отдает команды аппаратному обеспечению, и в итоге тоже возвращаются данные, если не произошел механический или электрический сбой. В случае терминала компьютер может высветить на экране приглашение, но не существует способа принудить сидящего за клавиатурой человека начать печатать. Хотя бы потому, что нет никакой гарантии, что за клавиатурой кто-то сидит. Чтобы обеспечить быстрый возврат, функция do read начинает с того, что сохраняет информацию о запросе. Благодаря этому он может выполнен позже, когда прибудет недостающая информация. Сначала должен быть проведен контроль ошибок. Ошибка возникает в случае, если устройство все еще ожидает ввод, чтобы выполнить предыдущий запрос, или если переданные в сообщении параметры неправильны. После того как проверка пройдена, информация готова к записи в поля записи tp->tty table, соответствующей устройству. Следующим шагом в переменную tp->inleft записывается количество полученных символов. Это важный шаг, так как ги роменная tp->inleft необходима для определения момента завершения чтения. В каноническом режиме значение tp->inleft декрементируется с каждым возвращенным символом до тех пор, пока не будет получен символ новой строки, после чего эта переменная сразу обнуляется. В неканоническом режиме она изменяется по-другому, но так или иначе, когда запрос выполнен, по тайм-ауту или после получения минимального необходимого количества символов, в эту переменную записывается нуль. Когда значение tp->tty inleft достигает нуля, отправляется ответное сообщение. Как мы увидим, ответное сообщение может генерироваться в нескольких местах кода. Кроме того, иногда необходимо удостовериться, что выполняющий чтение процесс ожидает ответа. Здесь индикатором служит ненулевое значение tp->ttyjnleft.

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



лается вызов settimer для запуска таймера, который по истечении заданного интервала времени прервет запрос DEV READ, даже если не будет прочитано ни одного байта. В переменную tp->tty min в этом случае записывается 1, чтобы вызов завершился немедленно после того, как до истечения тайм-аута будет получен хотя бы один символ. В этой точке не проверяется, имеются ли уже введенные символы, поэтому может оказаться, что запроса уже ожидают несколько символов. Как только обнаруживаются уже введенные символы, они возвращаются процессу, но не больше, чем задано при вызове read. В том случае, если и MIN и TIME не равны нулю, таймер ведет себя по-другому - отсчитывает время между символами. Он запускается только после того, как введен первый символ, и перезапускается с каждым новым. В переменной tp->tty eotct в неканоническом режиме подсчитываются введенные символы. Ее значение проверяется, и при равенстве нулю (ни одного символа еше не получено) таймер останавливается. Оба вызова settimer обрамлены вызовами lock и unlock, чтобы предотвратить прерывания от часов в то время, когда работает settimer.

В любом случае после этого блока условных операторов вызывается функция in transfer, чтобы напрямую передать уже имеющиеся во входной очереди символы на чтение процессу. Затем следует вызов handle events, который, в свою очередь, может поместить новые данные во входную очередь и который снова вызывает in transfer. Такое кажущееся дублирование вызовов требует дополнительных пояснений. Хотя до сих пор обсуждение велось в терминах клавиатурного ввода, функция do read не зависит от конкретных устройств и обслуживает в том числе удаленные терминалы, подключаемые по последовательной линии. Возможна ситуация, когда предыдущий поток ввода заполнил буфер, и ввод был приостановлен. Первый вызов in transfer не запускает поток, но вызов handle events может это сделать. То, что он при этом еще раз вызывает in transfer, это всего лишь небольшой довесок. Нам важно, что удаленный терминал снова получит разрешение отправлять данные. Оба вызова способны привести к тому, что запрос будет выполнен и файловой системе будет отправлено ответное сообщение. В качестве флага-индикатора отправки ответного сообщения используется переменная tp->tty inleft. Если ее значение не равно нулю, do read самостоятельно генерирует и отправляет ответ. За это отвечают последние девять строк кода функции. Если в исходном запросе было указано неблокирующее чтение, файловой системе дается указание вернуть код ошибки EAGAIN сделавшему вызов процессу. Если в запросе было затребовано обыкновенное блокирующее чтение, файловая система получает код SUSPEND, который разблокирует ее, но дает указание оставить процесс-инициатор вызова заблокированным. В данном случае в поле tp->ttyJnrepcode записывается значение REVIVE. Когда позднее вызов read будет выполнен (если вообще будет выполнен), этот код помещается в ответное сообщение файловой системе, с целью информировать ее о том, что запросивший чтение процесс был приостановлен и должен быть разбужен.

Функция do write подобна da read, но проще, так как при обработке системного вызова read нужно учитывать меньшее количество разнообразных настроек. Сначала делается ряд проверок, подобным проверкам в do read, из которых мы узнаем, что предыдущий запрос уже обработан и переданные параметры кор-



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

Таблица 3.15. Вызовы POSIX и операции ioctl

Функция POSIX

Операция POSIX

Тип ioctl

Параметр ioctl

tod rain

(нет)

TCDRAIN

(нет)

tcflow

TCOOFF

TCFLOW

int=TCOOFF

tcflow

TCOON

TCFLOW

int=TCOON

tcflow

TCIOFF

TCFLOW

int=TCIOFF

tcflow

TCION

TCFLOW

int=TCION

tcflush

TCIFLUSH

TCFLSH

int=TCIFLUSH

tcflush

TCOFLUSH

TCFLSH

int=TCOFLUSH

tcflush

TCIOFLUSH

TCFLSH

int=TCIOFLUSH

tcgetattr

(нет)

TCGETS

termios

tcsetattr

TCSANOW

TCSETS

termios

tcsetattr

TCSADRAIN

TCSETSW

termios

tcsetattr

TCSAFLUSH

TCSETSF

termios

tcsendbreak

(нет)

TCSBRK

int=duration

Далее следует довольно большая, но не сложная для понимания функция, dojoctl. Тело этой функции состоит из двух операторов switch. Первый определяет размер параметра, на который ссылается указатель в сообщении. Если размер параметра не равен нулю, проверяется его корректность. В этом месте нельзя контролировать содержимое, но можно удостовериться, что структура имеет требуемый размер, начинается по указанному адресу и умещается в том сегменте, где она должна находиться. Остаток функции составляет еще один оператор switch, проверяющий тип запрошенной операции ioctL К несчастью, поддержка требуемых стандартом POSIX операций подразумевает, что для операций ioctl необходимо изобретать имена, которые напоминают, но не дублируют POSIX-имена. Соответствие между именами запросов POSIX и параметрами вызова ioctl в MINIX показано в табл. 3.15. Операция TCGETS обслуживает пользовательский вызов tcgetattr и просто возвращает копию структуры tp->tty termios для терминального устройства. Следующие четыре типа запросов разделяют общий код. Типы запросов TGETSW, TCSETSF и TCSETS соответствуют вызовам функции POSIX tcsetattr, и основное действие в этом случае общее: структура termios копируется в структуру терминала tty. Для вызова TCSETS копирование происходит немедленно, а для TCSETSW и TCSETSF выполняется после того, как завершен вывод. Копирование производится вызовом phys copy, следующим за вызовом setattr. Если вызов tcsetattr был сделан с модификатором, требующим отложить выполнение до момента, пока не будет завершен текущий вывод, то, если проверка перемен-



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