Обработка сигнала
Если для сигнала был задан обработчик, функция do signaio должна обеспечить его выполнение. С этой целью она вызывает функцию
handle_signal():
handle_signal(signr, &info, &ka, oldset, regs); if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; return 1;
Если у принятого сигнала установлен флаг sa oneshot, для обработки сигнала должно быть возвращено действие по умолчанию, т. е. последующие отправки этого сигнала не должны снова приводить к выполнению специального обработчика. Обратите внимание, что функция do signaio возвращает управление после обработки одиночного сигнала. Другие висящие сигналы не будут рассматриваться до следующего вызова функции do signai . Такой подход гарантирует, что сигналы реального времени будут обработаны в должном порядке.
Выполнение обработчика сигнала является довольно сложной задачей из-за необходимости аккуратно жонглировать” стеками при переключении с режима пользователя на режим ядра и обратно. Сейчас мы подробно разъясним, что при этом происходит.
Обработчики сигналов— это функции, определяемые процессами режима пользователя и включенные в сегмент кода режима пользователя. Функция handie signai о работает в режиме ядра, в то время как обработчики сигналов работают в режиме пользователя. Это означает, что текущий процесс должен вначале выполнить обработчик сигнала в режиме пользователя до того, как ему будет разрешено продолжить свое нормальное” выполнение. Кроме того, когда ядро пытается продолжить нормальное выполнение процесса, стек режима ядра уже не содержит аппаратный контекст прерванной программы, потому что стек режима ядра очищается при каждом переходе из режима пользователя в режим ядра.
Ситуация еще усложняется тем, что обработчики сигналов могут делать системные вызовы. В этом случае по окончании работы служебной процедуры управление должно быть возвращено обработчику сигнала, а не коду прерванной программы.
Подход, принятый в Linux, заключается в копировании аппаратного контекста, хранящегося в стеке режима ядра, в стек режима пользователя текущего процесса. Кроме того, стек режима пользователя модифицируется так, что по окончании выполнения обработчика сигнала автоматически делается системный вызов sigreturn , копирующий аппаратный контекст в стек режима ядра и восстанавливающий оригинальное содержимое стека режима пользователя.
показан ход выполнения функций, вовлеченных в обработку сигнала. Процессу посылается незаблокированный сигнал. Когда возникает прерывание или исключение, процесс переходит в режим ядра. Непосредственно перед возвращением в режим пользователя ядро вызывает функцию do signaio, которая обрабатывает сигнал (вызывая функцию handie_ signal о) и заполняет стек режима пользователя (вызывая функцию setup fгаше или setup rt fгаше ()). Когда процесс снова переключается в режим пользователя, он приступает к выполнению обработчика сигнала, поскольку начальный адрес обработчика был принудительно записан в счетчик команд. Когда функция-обработчик завершится, будет выполнен код, адрес которого был помещен в стек режима пользователя функциями setup frame о или setup rt frame о. Он Делает системный ВЫЗОВ sigreturno или rt sigreturno, а соответствующая служебная процедура копирует аппаратный контекст нормальной программы в стек режима ядра и восстанавливает первоначальное состояние стека режима пользователя (вызывая функцию restore sigcontext о). Когда системный вызов завершается, нормальная программа может продолжить свое выполнение.
Теперь рассмотрим работу этой схемы более подробно.
Предыдущая страница | 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 | Следующая страница