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

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

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

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

В MINIX сигналы можно блокировать. Блокированный сигнал задерживается до тех пор, пока он не будет разблокирован. То есть, сигнал не доставляется, но и не теряется. Вызов SIGPROCMASK позволяет процессу задать набор блокируемых сигналов, передавая ядру битовую карту. Кроме того, процесс может узнать, какие сигналы произошли, но были заблокированы. Это позволяет сделать системный вызов SIGPENDING, возвращающий набор сигналов в виде битовой маски. Наконец, системный вызов SIGSUSPEND позволяет процессу атомарно задать битовую карту блокированных сигналов и приостановить свое выполнение.

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

command &

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

sigaction(SIGINT. SIGJGN. NULL): и

s1gact1on(SIGQUIT. SIG IGN, NULL):

Эти вызовы отключают обработку сигнала DEL и сигнала принудительного завершения процесса (этот сигнал вызывается нажатием Ctrl+\ и делает то же самое, что и Del, но, если его не обрабатывать или не блокировать, делает распечат-



ку памяти завершенного процесса). Для обычных процессов, выполняющихся не в фоновом режиме, игнорировать сигналы не нужно.

Нажать Del - не единственный способ послать процессу сигнал. Системный вызов KILL позволяет одному процессу послать сигнал другому (у обоих процессов должен быть одинаковый uid, так как не связанные процессы не могут послать друг другу сигналы). Возвращаясь к рассмотренному выше примеру, предположим, что запущенный фоновый процесс потребовалось завершить. Сигналы SIGQUIT и SIGINT этот процесс игнорирует, так что требуется что-то другое. Решение дает программа kill, которая с помощью системного вызова KILL может послать сигнал любому процессу. Процесс можно принудительно завершить, послав ему сигал 9 (SIGKILL). Этот сигнал нельзя обработать или игнорировать.

Во многих приложениях реального времени процесс нужно прерывать по истечении некоторого интервала времени, за который он должен успеть выполнить свою задачу. Например, повторно передать пакет данных по ненадежной линии связи. Для этой ситуации предназначен системный вызов ALARM. Параметр этого вызова описывает интервал времени, по истечении которого процессу передается сигнал SIGALARM. В любой момент времени процесс может запланировать только один сигнал. Если сделать вызов ALARM, указав задержку 10 секунд, а затем, по истечении 3 секунд, еще раз вызвать ALARM с параметром 20 секунд, придет сигнал только от того вызова, который сделан последним. Первый вызов отменяется. Чтобы отменить сделанный ранее вызов ALARM, нужно еще раз вызвать ALARM, передав в качестве аргумента 0. Если пришедший сигнал SIGALARM не обрабатывать, то выполняется действие по умолчанию, и процесс завершается.

Иногда возникают ситуации, когда процессу нечем заняться до прибытия сигнала. Например, рассмотрим компьютерную программу для проверки скорости чтения и внимательности. Эта программа выводит некоторый текст, а затем делает вызов ALARM с параметром 30 секунд. Пока ученик читает текст, программа ничего не должна делать. Программа может выполнять пустой цикл, но это будет бессмысленным расточением процессорного времени, которое может потребоваться другому процессу. Гораздо лучше использовать системный вызов PAUSE, который указывает MINIX приостановить выполнение процесса до прихода сигнала.

1.4.3. Системные вызовы для управления файлами

Многие системные вызовы имеют отношение к файловой системе. В этом разделе мы рассмотрим вызовы, работающие с отдельными файлами, а в следующем разделе обратимся к тем, которые оперируют каталогами или файловой системой в целом. Для создания нового файла служит вызов CREAT (ответ на вопрос, почему именно GREAT, а не CREATE затерялся в тумане времен). Его параметры - имя файла и права доступа. Так, команда

fd = creatCabc , 0751):

создаст файл с именем аЬс и установит для него права доступа 0751 (в С числа с ведущим нулем считаются восьмеричными). Младшие 9 бит этого числа пока-



зывают, что владелец файла имеет права доступа rwx (7 означает права на чтение, запись и исполнение), члены группы владельца имеют права на чтение и исполнение (5), а прочие пользователи - только на исполнение (1).

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

Чтобы создать специальный файл, нужно вызывать не GREAT, а MKNOD. Вот пример его типичного использования:

fd = tnknodC7dev/ttyc2 . 020744. 0x0402).

Эта команда создает файл с именем /dev/ttyc2 (обычно это имя соответствует второй консоли) и задает для него права доступа 020744 (специальный символьный файл с правами rwxr~r-). Третий параметр составлен из двух байт, из которых старший задает основное устройство (4), а младший - вторичное устройство (2). Основное устройство могло бы быть любым, а вторичное для /dev/ttyc2 должно быть равно 2. Делать вызов MKNOD может только суперпользователь, в противном случае возникает ошибка.

Чтобы прочитать или записать файл, его сначала нужно открыть при помощи вызова OPEN. Для этого вызова указывается имя открываемого файла (задается или абсолютный путь файла, или ссылка на рабочий каталог) и код 0 RDONLY, 0 WRONLY или 0 RDWR, означающий, что файл открывается для чтения, записи или и того и другого. Для создания нового файла используется код 0 CREAT. Возвращаемый дескриптор файла затем можно употребить при чтении или записи. Потом файл закрывается с помощью вызова GLOSE, который делает дескриптор файла доступным при следующем открытии (OPEN).

Наиболее часто используемыми вызовами, без сомнения, являются READ и WRITE. Вызов READ мы уже обсуждали, WRITE имеет те же самые параметры.

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

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

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



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