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

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

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

Таблица процессов

Родитепь

Потомок

Таблица filp


Указатель положения в файле для 1-узла

Таблица i-узлов


Рис. 5.29. Совместное использование файловых указателей родительским и дочерним процессами

5.6.8. Захват файлов

Специальная таблица нужна для реализации еще одного аспекта управления файловой системой. Это захват файлов. В MINIX поддерживается описываемый POSIX механизм добровольной блокировки файла (advisory file locking). Данный механизм позволяет отметить весь файл, его часть или несколько его частей как захваченные. Операционная система не мещает получать доступ к блокированным данным, но ожидается, что процессы будут вести себя прилежно и проверять наличие блокировки, прежде чем делать что-либо, что может привести к конфликту с другим процессом.

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

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



5.6.9. Каналы ввода/вывода и специальные файлы

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

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

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

С терминалами и прочими символьными устройствами ситуация немного иная. У каждого специального файла в i-узле хранятся два числа, это старшее устройство и младшее устройство. Первое из этих чисел характеризует класс устройства (то есть RAM-диск, жесткий диск, терминал). Оно используется как индекс в одной из таблиц файловой системы, которая ставит в соответствие этому номеру задачу ввода/вывода (другими словами, драйвер). В результате главный номер определяет, какой драйвер вызвать. Второе число передается драйверу как аргумент. Оно определяет, какое устройство использовать, например терминал 2 или диск 1.

В некоторых случаях, особенно это касается терминалов, в младшем номере закодирована информация о категории устройств, обслуживаемых задачей. Например, основная консоль MINIX, /dev/console, имеет номера 4, 0. Виртуальные консоли обслуживаются той же частью драйвера. Это устройства /dev/ttyd (4, 1), /dev/ttys2 (4, 2) и т. д. Для обслуживания терминалов на последовательных линиях требуется другое низкоуровневое программное обеспенение, и этим устройствам присваиваются следующие номера: 4, 16 (/dev/ttyOO) и 4, 17 (/dev/ttyOl). Аналогичным образом, для обслуживания сетевых псечдотерминалов нужен от-



дельный код низкого уровня, и эти устройства, ttypOl и ttyp02, получают такие номера, как 4, 128 и 4, 129. С каждым из псевдоустройств ассоциировано устройство ptypl, ptyp2 и так далее с номерами 4, 192; 4, 193... Эти номера выбираются так, чтобы задаче терминала было проще вызывать низкоуровневые функции, необходимые для работы с каждой из групп объектов. Никто не ожидает, что когда-нибудь кому-нибудь придет в голову оснастить систему с MINIX более чем 192 терминалами.

Когда процесс читает специальный файл, файловая система извлекает из его г-узла старщий и младщий номера и по старшему номеру при помощи таблицы в файловой системе определяет номер задачи. Определив задачу, файловая система отправляет ей сообщение, параметрами которого являются младший номер, выполняемая операция, номер сделавшего вызов процесса, адрес буфера и количество байтов. Формат совпадает с показанным в табл. 3.4, с той разницей, что поле POSITION не используется.

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

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

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

5.6.10. Пример: системный вызов read

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

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

п = read (fd. buffer, nbytes):

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



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