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

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 поддерживает две функции, sigaction и signal, позволяющие процессу изменять свою реакцию на сигнал. Функция sigaction регламентирована стандартом POSIX и является предпочтительным способом для всех целей, но библиотечная функция signal удовлетворяет ANSI С, и, если программа должна быть переносима на не-POSIX системы, она должна использовать вторую функцию. Код do sigaction начинается с проверок правильности номера сигнала и того, что не делается попытки изменить реакцию на сигнал KILL. (Сигнал SIGKILL нельзя ни игнорировать, ни блокировать, ни обрабатывать. Это исключительно то средство, при помощи которого пользователь может контролировать собственные процессы, а системный оператор может контролировать пользователей.) При вызове sigaction передаются указатели на структуру типа sigaction, это sig osa, куда помещаются старые значения атрибутов, и sig nsa, где хранится новый набор атрибутов.

На первом шаге, чтобы скопировать текущие значения атрибутов по указателю sig osa, вызывается системная задача. Далее, при вызове sigaction указатель sig nsa может иметь значение NULL Это означает, что требуется считать текущие значения атрибутов, не меняя их. В таком случае sigaction немедленно возвращает управление. Если указатель sig nsa не равен NULL, в пространство менеджера памяти копируется новая структура, описывающая действие сигнала. Затем модифицируются битовые карты mp catch, mpjgnore и mp sigpending, чтобы указанный сигнал либо игнорировался, либо обрабатывался по умолчанию, либо вызывал обработчик. При этом используются библиотечные функции sigaddset и sigdelset, хотя те же действия можно было реализовать и при помощи макроса, как и другие простые манипуляции с битами. Тем не менее эти функции требуются по стандарту POSIX с целью упростить перенос программ на другие системы, в том числе и на те, в которых общее число сигналов превышает число битов в целом значении. Использование библиотечных функций упрощает и перенос самой MINIX на различные архитектуры.

В завершение заполняются другие относящиеся к сигналам поля той части таблицы процессов, которая принадлежит менеджеру памяти. Для каждого потенциального сигнала здесь есть битовая карта, sa mask, определяющая, какие сигналы будут блокироваться при выполнении его обработчика. Кроме того, для каждого сигнала хранится указатель, sa handler. Он может содержать либо указатель на функцию-обработчик, либо специальное значение, означающее, что сигнал должен быть блокирован или обработан по умолчанию. Адрес библиотечной функции, по завершении обработчика запускающей системный вызов sigreturn, хранится в поле mp sigretrun. Этот адрес передается в одном из полей сообщения, которое получает менеджер памяти.

POSIX позволяет процессу изменять способ обработки получаемых им сигналов даже внутри обработчика. Благодаря этому можно, например, изменить реакцию на сигнал на время его обработки, а затем восстановить нормальный отклик. Следующая группа системных вызовов и служит средствами подобной манипуляции сигналами. Вызов sigpending выполняется функцией do sigpending, возвращающей битовую карту mp sigpending, по которой процесс может определить, имеются ли задержанные сигналы. Вызов sigprocmask, обслуживаемый



функцией do sigprocmask, возвращает набор блокируемых сигналов. Кроме того, с его помощью можно изменить блокировку либо одного сигнала из набора, либо сразу установить новый набор. В тот момент, когда с сигнала снимается блокировка, стоит проверить, есть ли задержанные сигналы, для этого в конце вариантов SIG SETMASK и SIG UNBLOCK вызывается check pending. Функция do sigsuspend выполняет системный вызов sigsuspend. Этот вызов приостанавливает выполнение процесса до тех пор, пока не будет получен сигнал. Как и другие обсуждаемые здесь функции, do sigsuspend манипулирует битовыми картами. Помимо того, она устанавливает в поле mp flags бит SIGSUSPENDED, что и предотвращает выполнение процесса. Опять же, в заверщение здесь стоит вызвать check pending. Наконец, функция do sigretrun обслуживает системный вызов sigreturn, используемый для возврата из пользовательского обработчика сигнала. Эта функция восстанавливает контекст сигналов, предшествующий входу в обработчик, а также вызывает check pending.

Некоторые сигналы, такие как SIGINT, исходят из самого ядра. Такие сигналы обслуживаются подобно тому, как обслуживаются сигналы, генерируемые пользовательскими процессами при вызове kill. Поэтому две процедуры, do kill и do ksig, основаны на сходных идеях. Обе они заставляют менеджер памяти отправить сигнал. Так как при помощи одного вызова kill можно отправить сигнал группе процессов, do kill просто вызывает функцию check sig, которая ищет во всей таблице процессов подходящих получателей. Функция do ksing вызывается тогда, когда получено сообщение от ядра. Это сообщение содержит битовую карту, при помощи которой ядро может генерировать несколько сигналов одним сообщением. Как и в случае kill, каждый из сигналов доставляется как одному процессу, та и их группе. Цикл внутри do ksig бит за битом обрабатывает переданную битовую карту. Отдельным сигналам требуется особое внимание: в некоторых случаях меняется идентификатор процесса с той целью, чтобы сигнал был доставлен группе процессов (варианты SIGQUIT и SIGKILL), а SIGALRM, если он не был запрошен, игнорируется. За исключением этих специальных случаев, каждый установленный бит приводит к вызову check sig, как и в do kilL

Системный вызов alarm вьшолняется функцией do alarm. Она вызывает следующую функцию, set alarm, которая отправляет задаче часов сообщение, запуская таймер. Код set alarm вынесен в отдельную функцию потому, что он также используется для отключения таймера, когда процесс завершается, а таймер еще работает. Когда заданный промежуток времени истекает, ядро сообщает этот факт менеджеру памяти, отправляя ему сообщение типа KSIG, которое, как говорилось выше, влечет за собой запуск do ksig. По умолчанию сигнал SIGALRM приводит к завершению процесса. Если он должен обрабатываться, вызовом sigaction задается соответствующий обработчик. Вся последовательность событий обработки сигнала SIGALRM показана на рис. 4.37. Здесь представлены три последовательности сообщений. При помощи сообщений 1, 2 и 3 пользователь делает системный вызов alarm (сообщение менеджеру памяти), менеджер памяти отправляет запрос задаче часов, а задача часов передает подтверждение. В сообщениях 4, 5 и 6 задача часов докладывает менеджеру памяти о срабатывании таймера, менеджер памяти подает прошение системной задаче приготовить стек процесса к выпол-



нению обработчика (как на рис. 4.37), и задача системы отправляет ответ. Сообщение 7 - это вызов sigretrun, который происходит после завершения обработчика. В ответ менеджер памяти отправляет системной задаче сообщение 8, чтобы она закончила обработку, а задача системы отвечает 9. Сообщение 6 само по себе не приводит к запуску обработчика, но он будет стартован позже, так как задаче часов, благодаря принятой в MINIX системе планирования с приоритетами, будет позволено завершить свою работу. Обработчик является частью пользовательского процесса, поэтому не может быть запущен на выполнение до того, как системная задача не закончит свои дела.

Уровень

/МПользоватепь

(работчикА1КМ)

(Часы (СистемГ


Управление процессами

Рис. 4.37. Сообщения при работе таймера. Самые главные из них: - пользователь делает вызов alarm; 4 - после истечения заданного интервала времени прибывает сигнал; 7 - обработчик завершается вызовом sigreturn. Подробности смотрите в тексте

Функция do pause заботится о системном вызове pause. Все, что ей нужно сделать, - это установить бит и не отвечать, удерживая сделавший вызов процесс заблокированным. Не нужно даже информировать ядро, так как оно уже знает, что процесс заблокирован.

Последний системный вызов, код которого расположен в signal.c, - это вызов reboot. Он делается только специализированными программами, под руководством суперпользователя, ввиду важности возложенной на этот вызов роли. Он проверяет, что все процессы корректно завершены и файловая система синхронизирована, прежде чем передать задаче системы указание завершить работу системы. Для завершения процессов при помощи check sig всем процессам, за исключением init, отправляется сигнал SIGKILL. Именно поэтому код reboot помещен в данном файле.



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