Архитектура операционной системы UNIX


         

В рассмотренном алгоритме обработки сигналов


В рассмотренном алгоритме обработки сигналов имеются некоторые несоответствия. Первое из них и наиболее важное связано с очисткой перед возвращением процесса в режим задачи того поля в пространстве процесса, которое содержит адрес пользовательской функции обработки сигнала. Если процессу снова понадобится обработать сигнал, ему опять придется прибегнуть к помощи системной функции signal. При этом могут возникнуть нежелательные последствия: например, могут создаться условия для конкуренции, если второй раз сигнал поступит до того, как процесс получит возможность запустить системную функцию. Поскольку процесс выполняется в режиме задачи, ядру следовало бы произвести переключение контекста, чтобы увеличить тем самым шансы процесса на получение сигнала до момента сброса значения поля функции обработки сигнала.
#include <signal.h> main() { extern catcher(); signal(SIGINT,catcher); kill(0,SIGINT); }

catcher() { }
Рисунок 7.9. Исходный текст программы приема сигналов

**** VAX DISASSEMBLER ****

_main() e4: e6: pushab Ox18(pc) ec: pushl $Ox2 # в следующей строке вызывается функция signal ee: calls $Ox2,Ox23(pc) f5: pushl $Ox2 f7: clrl -(sp) # в следующей строке вызывается библиотечная процеду- ра kill f9: calls $Ox2,Ox8(pc) 100: ret 101: halt 102: halt 103: halt _catcher() 104: 106: ret 107: halt _kill() 108: # в следующей строке вызывается внутреннее прерывание операционной системы 10a: chmk $Ox25 10c: bgequ Ox6 <Ox114> 10e: jmp Ox14(pc) 114: clrl r0 116: ret |
Рисунок 7.10. Результат дисассемблирования программы приема сигналов



Рисунок 7.11. Стек задачи и область сохранения структур ядра до и после получения сигнала

Эту ситуацию можно разобрать на примере программы, представленной на . Процесс обращается к системной функции signal для того, чтобы дать указание принимать сигналы о прерываниях и исполнять по их получении функцию sigcatcher. Затем он порождает новый процесс, запускает системную функцию nice, позволяющую сделать приоритет запуска процесса-родителя ниже приоритета его потомка (см. , и входит в бесконечный цикл. Порожденный процесс задерживает свое выполнение на 5 секунд, чтобы дать родительскому процессу время исполнить системную функцию nice и снизить свой приоритет. После этого порожденный процесс входит в цикл, в каждой итерации которого он посылает родительскому процессу сигнал о прерывании (посредством обращения к функции kill). Если в результате ошибки, например, из-за того, что родительский процесс больше не существует, kill завершается, то завершается и порожденный процесс. Вся идея состоит в том, что родительскому процессу следует запускать функцию обработки сигнала при каждом получении сигнала о прерывании. Функция обработки сигнала выводит сообщение и снова обращается к функции signal при очередном появлении сигнала о прерывании, родительский же процесс продолжает исполнять циклический набор команд.


Содержание  Назад  Вперед