Сигналы и системные вызовы
В большинстве случаев, если процессу посылается сигнал во время выполнения им системного вызова, то обработка сигнала откладывается до завершения вызова. Но некоторые системные вызовы ведут себя по-другому, и их выполнение можно прервать при помощи сигнала. Это относится к вызовам ввода/вывода (fdread, fdwrite, fdopen, и т.д.), вызовам wait или pause (который мы обсудим в свое время). Во всех случаях, если процесс перехватывает вызов, то прерванный системный вызов возвращает значение –1 и помещает в переменную linuxerror значение Sys_EINTR. Такие ситуации можно обрабатывать при помощи следующего кода:
if fdwrite(tfd, buf, size) < 0 then
begin
if linuxerror = Sys_EINTR then
begin
warn('Вызов fdwrite прерван');
.
.
.
end;
end;
В этом случае, если программа хочет вернуться к системному вызову fdwrite, то она должна использовать цикл и оператор continue. Но процедура
sigactionrec позволяет автоматически повторять прерванный таким образом системный вызов. Это достигается установкой значения SA_RESTART в поле sa_flags структуры sigactionrec. Если установлен этот флаг, то системный вызов будет выполнен снова, и значение переменной linuxerror не будет установлено.
Важно отметить, что сигналы
UNIX обычно не могут накапливаться. Другими словами, в любой момент времени только один сигнал каждого типа может ожидать обработки данным процессом, хотя несколько сигналов разных типов могут ожидать обработки одновременно. Фактически то, что сигналы не могут накапливаться, означает, что они не могут использоваться в качестве полностью надежного метода межпроцессного взаимодействия, так как процесс не может быть уверен, что посланный им сигнал не будет «потерян».
Упражнение 6.1. Измените программу smallsh из предыдущей главы так, чтобы она обрабатывала клавиши прерывания и завершения как настоящий командный интерпретатор. Выполнение фоновых процессов не должно прерываться сигналами SIGINT и SIGQUIT. Некоторые командные интерпретаторы, (а именно C-shell и Korn shell) помещают фоновые процессы в другую группу процессов. В чем преимущества и недостатки этого подхода? (В последних версиях стандарта POSIX введено накопление сигналов, но в качестве необязательного расширения.)