Linux Kernel (Ядро линукса) (часть 2)


Проверка флагов сигнала

Заполнив стек режима пользователя, функция handie signai о проверяет значения флагов, ассоциированных с сигналом. Если у сигнала не установлен флаг SA NODEFER, СИГНаЛЫ В поле sa mask таблицы sigaction должны быть блокированы на время выполнения обработчика сигнала:
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); sigaddset(¤t->blocked, sig); recalc_sigpending(current);
spin_unlock_irq(¤t->sighand->siglock);}
Как было отмечено ранее, функция recaic_sigpending проверяет, есть ли у процесса незаблокированные висящие сигналы, и соответствующим образом устанавливает флаг tif_sigpending.

Затем функция возвращает управление функции do signaio, которая тоже немедленно возвращает управление.

Запуск обработчика сигналов

Когда функция do signaio возвращает управление, текущий процесс возобновляет свое выполнение в режиме пользователя. Благодаря подготовительной работе, проведенной функцией setup fгаше , регистр eip указывает на первую инструкцию обработчика сигнала, а регистр esp — на первую ячейку кадра, расположенного на верхушке стека режима пользователя. В результате выполняется обработчик сигнала.

Завершение обработчика сигнала

Когда обработчик сигнала завершает выполнение, адрес возврата на верхушке стека указывает на код на странице vsyscall, на который ссылается поле pretcode кадра:
kernel_sigreturn:
popl еах
movl $ NR_sigreturn, eax
int $0x80
Таким образом, номер сигнала (то есть поле sig кадра) выбрасывается из стека. Затем выполняется системный вызов sigreturn .
Функция sys sigreturno вычисляет адрес структуры regs, имеющей тип pt regs, которая содержит аппаратный контекст процесса в режиме пользователя По значению, хранящемуся в поле esp, функция может вычислить и проверить адрес кадра внутри стека режима пользователя:
frame = (struct sigframe )(regs.esp — 8); if (verify_area(VERIFY_READ, frame, sizeof(frame)) { force_sig(SIGSEGV, current); return 0;}
Затем функция копирует битовый массив (определяющий сигналы, заблокированные до вызова обработчика сигналов) из поля sc кадра в поле blocked процесса current. В результате все сигналы, замаскированные перед выполнением обработчика сигналов, перестают быть заблокированными. После ЭТОГО вызывается функция recalc_sigpending .

Функция sys sigreturno должна в этом месте скопировать аппаратный контекст процесса из поля sc кадра в стек режима ядра и удалить кадр из стека режима пользователя. Она выполняет эти действия с помощью функции
restore_sigcontext.

Если сигнал был послан системным ВЫЗОВОМ, например, rt_sigqueueinfo, которому требуется, чтобы с сигналом была ассоциирована таблица siginfo t, принцип работы тот же самый. Поле pretcode расширенного кадра
указывает на код kernei rt sigreturn на странице vsyscall, который делает
системный вызов rt sigreturno. Соответствующая служебная процедура sys rt sigreturn копирует аппаратный контекст процесса из расширенного кадра в стек режима ядра и восстанавливает оригинальное содержание стека режима пользователя, удаляя из него расширенный кадр.

Повторное выполнение системных вызовов

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

Если процесс переведен в состояние task interruptible, и какой-то другой процесс посылает ему сигнал, ядро переводит первый процесс в состояние task running, не завершив выполнение системного вызова Сигнал доставляется процессу при переключении в режим пользователя. Когда это происходит, служебная процедура системного вызова не завершает свою работу, а возвращает код ошибки eintr, erestartnohand, erestart_

RESTARTBLOCK, ERESTARTSYS ИЛИ ERESTARTNOINTR

На практике единственным кодом ошибки, который может быть получен процессом режима пользователя в такой ситуации, является eintr, и это означает, что системный вызов не был завершен. (Программист может проверить этот код и решить, следует ли повторить системный вызов.) Остальные коды ошибок предназначены для внутреннего пользования, и ядро применяет их для уточнения, может ли системный вызов быть выполнен повторно и автоматически по окончании обработчика сигнала.

Перечислены коды ошибок, имеющие отношение к незавершенным системным вызовам, и указано их влияние на каждое из трех действий по обработке сигналов.

В таблице употребляются следующие термины:
- Завершить выполнение — системный вызов не будет повторен автоматически. Процесс возобновит работу в режиме пользователя с инструкции, следующей за инструкцией int $0x8 о или sys enter, а регистр еах будет содержать значение -eintr;
- Выполнить повторно — ядро заставляет процесс режима пользователя заново загрузить в регистр номер системного вызова и выполнить инструкцию int $0x80 или sysenter. Процессу не известно, что выполнение является повторным, и код ошибки ему не передается;
- По обстоятельствам — системный вызов выполняется повторно, только если у доставленного сигнала установлен флаг sa restart. В противном случае системный вызов завершается с кодом ошибки -eintr.
При доставке сигнала ядро должно быть уверено, что процесс действительно сделал системный вызов прежде, чем оно попытается выполнить его повторно. Здесь важнейшую роль играет поле orig eax аппаратного контекста regs. Вспомним, как инициализируется это поле, когда запускается обработчик прерывания или исключения.
- Прерывание — поле содержит номер IRQ, ассоциированный с прерыванием, минус 256
- Исключение 0x80 (а также sysenter) — поле содержит номер системного вызова (см. главу 10).
- Прочие исключения — поле содержит значение -1
Таким образом, неотрицательное значение в поле orig eax свидетельствует о том, что сигнал разбудил процесс, который находится в состоянии task interruptible, и ждал завершения системного вызова. Служебная процедура распознает, что системный вызов был прерван, и возвращает один из вышеупомянутых кодов ошибки.

Предыдущая страница | 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 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...