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

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

#include ‹signal.h›

main() {

 extern catcher();

 signal(SIGINT, catcher);

 kill(0, SIGINT);

}

catcher() {}

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

**** VAX DISASSEMBLER ****

_main()

 e4:

 e6: pushab 0x18(pc)

 ec: pushl $0x2

# в следующей строке вызывается функция signal

 ee: calls $0x2,0x23(pc)

 f5: pushl $0x2

 f7: clrl -(sp)

# в следующей строке вызывается библиотечная процедура kill

 f9: calls $0x2,0x8(pc)

 100: ret

 101: halt

 102: halt

 103: halt

_catcher()

 104:

 106: ret

 107: halt

_kill()

 108:

# в следующей строке вызывается внутреннее прерывание операционной системы

 10a: chmk $0x25

 10c: bgequ 0x6 ‹0x114›

 10e: jmp 0x14(pc)

 114: clrl r0

 116: ret

Рисунок 7.10. Результат дисассемблирования программы приема сигналов

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

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

Однако, возможна и следующая очередность наступления событий:

1. Порожденный процесс посылает родительскому процессу сигнал о прерывании.

2. Родительский процесс принимает сигнал и вызывает функцию обработки сигнала, но резервируется ядром, которое производит переключение контекста до того, как функция signal будет вызвана повторно.

3. Снова запускается порожденный процесс, который посылает родительскому процессу еще один сигнал о прерывании.

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

#include ‹signal.h›

sigcatcher() {

 printf("PID %d принял сигнал\n", getpid()); /* печать PID */

 signal(SIGINT, sigcatcher);

}

main() {

 int ppid;

 signal(SIGINT, sigcatcher);

 if (fork() == 0) {

  /* дать процессам время для выполнения установок */

  sleep(5); /* библиотечная функция приостанова на 5 секунд */

  ppid = getppid(); /* получить идентификатор родителя */

Перейти на страницу:

Все книги серии Серия книг по программному обеспечению издательства prentice hall

Похожие книги