Доставка сигнала
Мы предполагаем, что ядро обнаружило поступление сигнала и вызвало одну из функций, описанных в предыдущих разделах, чтобы подготовить дескриптор процесса, который, предположительно, будет принимать сигнал. Однако если данный процесс не выполнялся в тот момент, ядро отложило доставку сигнала. Сейчас мы обсудим действия, выполняемые ядром для обеспечения обработки процессом висящих сигналов.
Как было сказано в главе 4, ядро проверяет флаг tif sigpending процесса прежде, чем разрешит процессу возобновить работу в режиме пользователя. Так ядро проверяет наличие висящих сигналов всякий раз, когда оно завершает обработку прерывания или исключения.
Чтобы обработать незаблокированные висящие сигналы, ядро вызывает функцию do signai , которая принимает два параметра:
-regs — адрес области стека, в которой сохраняется содержимое регистров режима пользователя текущего процесса;
- oidset — адрес переменной, в которой функция сохранит битовый массив, представляющий собой маску заблокированных сигналов. Этот параметр равен null, если сохранять массив-маску нет необходимости.
При описании функции do signaio мы основное внимание уделили общим механизмам доставки сигналов. Реальный код перегружен обработкой ситуаций параллельного обращения и других специальных случаев, например, "зависания" системы, генерирования дампов, остановки и уничтожения целых групп потоков и т. д. Мы не станем вдаваться в обсуждение этих подробностей.
Как уже было сказано, функция do signaio обычно вызывается, лишь когда процессор собирается возвратиться в режим пользователя. По этой причине, если обработчик прерывания вызывает функцию do signai , она просто возвращает управление:
if ( (regs->xcs & 3) != 3) return 1;
Если параметр oidset равен null, функция инициализирует его адресом поля
current->blocked:
if (!oidset)
oidset = ¤t->blocked;
Важнейшей частью функции do signaio является цикл, многократно вызывающий функцию dequeue signaio, пока не будут обработаны все незаблокированные висящие сигналы в очередях частных и совместно используемых висящих сигналов. Код возврата функции dequeue signai о хранится в локальной переменной signr. Если он равен 0, это означает, что в очередях не осталось ни одного висящего сигнала, и функция do signaio может закончить работу. Если возвращается ненулевое значение, какой-то висящий сигнал ждет обработки. Функция dequeue signai о вызывается снова после того, как функция do signai обработает текущий сигнал.
Функция dequeue signai о сначала рассматривает все сигналы в очереди частных висящих сигналов, начиная с сигнала с наименьшим номером, а затем — сигналы в очереди совместно используемых сигналов. Она обновляет структуры данных, отмечая тот факт, что сигнал больше не является висящим, и возвращает его номер. Эта задача включает в себя сброс соответствующего бита В ПОЛе current->pending.signal ИЛИ current->signal-> shared pending. signal И ВЫЗОВ функции recalc sigpending , обновляющей значение флага tif_sigpending.
Рассмотрим, как функция do signaio обрабатывает висящий сигнал, номер которого возвращен функцией dequeue signaio. Вначале она проверяет, отслеживается ли процесс current (процесс-получатель) каким-нибудь другим процессом. В этом случае функция dosignaio вызывает функции
do_notify_parent_cidstop и schedule о, чтобы сообщить отслеживающему процессу об обработке сигнала.
Затем функция do signaio записывает в локальную переменную ка адрес структуры k sigaction сигнала, подлежащего обработке:
ka = ¤t->sig->action[signr-1];
В зависимости от содержимого структуры, возможен один из трех сценариев: игнорирование сигнала, выполнение действия по умолчанию и вызов обработчика сигнала.
Когда добавленный сигнал игнорируется явно, функция do signaio просто переходит на новый шаг цикла и, следовательно, рассматривает следующий висящий сигнал:
if (ka->sa.sa_handler == SIG_IGN) continue;
В следующих двух разделах мы опишем, как выполняется действие по умолчанию, а также как выполняется обработчик сигнала.
Выполнение действия по умолчанию по обработке сигнала
ЕСЛИ ПОЛе ka->sa.sa_handler содержит SIG DFL, функция do_signal() должна выполнить действие по умолчанию для данного сигнала. Единственным исключением является ситуация, в которой принимающим процессом является init. В этом случае сигнал просто отбрасывается, как описано в разд. "Действия, выполняемые при доставке сигнала"ранее в этой главе:
if (current->pid == 1) continue;
Для других процессов сигналы с действием по умолчанию игнорировать” обрабатываются достаточно легко:
if (signr==SIGCONT | | signr==SIGCHLD | |
signr==SIGWINCH | | signr==SIGURG) continue;
Сигналы с действием по умолчанию "остановить” способны остановить все процессы в группе. С этой целью функция do signai о переводит процессы в состояние task stopped и затем вызывает функцию schedule () (см. главу 7):
if (signr==SIGSTOP || signr==SIGTSTP ||
signr==SIGTTIN || signr==SIGTTOU) { if (signr != SIGSTOP &&
is_orphaned_pgrp(current->signal->pgrp)) continue; do_signal_stop(signr);}
Существует тонкое различие между сигналом sigstop и другими сигналами: sigstop всегда останавливает выполнение группы потоков, а прочие сигналы делают это, только когда группа не является "осиротевшей группой процессов”. Стандарт POSIX гласит, что группа процессов не является осиротев- шей”, пока в ней есть процесс, имеющий родителя в другой группе процессов, но в том же сеансе. Таким образом, если процесс-родитель уничтожен, но пользователь, запустивший его, не вышел из системы, группа процессов не считается осиротевшей”.
Функция do signal stopO проверяет, является ли процесс current первым останавливаемым процессом в группе. Если это так, функция производит групповую остановку”, а именно — записывает в поле group stop count дескриптора сигнала положительное число и пробуждает все процессы в группе. Каждый такой процесс проверяет это поле и обнаруживает, что происходит остановка группы. Тогда он изменяет свое состояние на task stopped и вызывает функцию schedule . Кроме ТОГО, функция do signal stopO посылает сигнал sigchld процессу-родителю лидера группы, если этот родитель не установил флаг sa_nocldstop для сигнала sigchld.
Сигналы, у которых действием по умолчанию является Выполнить дамп”, могут создать файл core в рабочем каталоге процесса. Этот файл будет хранить все содержимое адресного пространства процесса и регистров процессора. После того как функция do signai создаст такой файл, она уничтожит группу потоков. У остальных восемнадцати сигналов действием по умолчанию является Завершить выполнение”, которое сводится к уничтожению группы потоков. Чтобы уничтожить всю группу потоков, функция вызывает функцию do group exit , выполняющую корректный групповой выход”
Предыдущая страница | 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 | Следующая страница