signal(SIGCLD, catcher);
}
Рисунок 7.35. Программа, в которой процесс принимает сигналы типа „гибель потомка“
7. Когда процесс получает сигналы определенного типа и не обрабатывает их, ядро дампирует образ процесса в том виде, который был у него в момент получения сигнала. Ядро создает в текущем каталоге процесса файл с именем „core“ и копирует в него пространство процесса, области команд, данных и стека. Впоследствии пользователь может тщательно изучить дамп образа процесса с помощью стандартных средств отладки. Опишите алгоритм, которому на Ваш взгляд должно следовать ядро в процессе создания файла „core“. Что нужно предпринять в том случае, если в текущем каталоге файл с таким именем уже существует? Как должно вести себя ядро, когда в одном и том же каталоге дампируют свои образы сразу несколько процессов?
8. Еще раз обратимся к программе (Рисунок 7.12), описывающей, как один процесс забрасывает другой процесс сигналами, которые принимаются их адресатом. Подумайте, что произошло бы в том случае, если бы алгоритм обработки сигналов был переработан в любом из следующих направлений:
• ядро не заменяет функцию обработки сигналов до тех пор, пока пользователь явно не потребует этого;
• ядро заставляет процесс игнорировать сигналы до тех пор, пока пользователь не обратится к функции signal вновь.
9. Переработайте алгоритм обработки сигналов так, чтобы ядро автоматически перенастраивало процесс на игнорирование всех последующих поступлений сигналов по возвращении из функции, обрабатывающей их. Каким образом ядро может узнать о завершении функции обработки сигналов, выполняющейся в режиме задачи? Такого рода перенастройка приблизила бы нас к трактовке сигналов в системе BSD.
*10. Если процесс получает сигнал, находясь в состоянии приостанова во время выполнения системной функции с допускающим прерывания приоритетом, он выходит из функции по алгоритму longjump. Ядро производит необходимые установки для запуска функции обработки сигнала; когда процесс выйдет из функции обработки сигнала, в версии V это будет выглядеть так, словно он вернулся из системной функции с признаком ошибки (как бы прервав свое выполнение). В системе BSD системная функция в этом случае автоматически перезапускается. Каким образом можно реализовать этот момент в нашей системе?
11. В традиционной реализации команды mkdir для создания новой вершины в дереве каталогов используется системная функция mknod, после чего дважды вызывается системная функция link, привязывающая точки входа в каталог с именами "." и ".." к новой вершине и к ее родительскому каталогу. Без этих трех операций каталог не будет иметь надлежащий формат. Что произойдет, если во время исполнения команды mkdir процесс получит сигнал? Что если при этом будет получен сигнал SIGKILL, который процесс не распознает? Эту же проблему рассмотрите применительно к реализации системной функции mkdir.
12. Процесс проверяет наличие сигналов в моменты перехода в состояние приостанова и выхода из него (если в состоянии приостанова процесс находился с приоритетом, допускающим прерывания), а также в момент перехода в режим задачи из режима ядра по завершении исполнения системной функции или после обработки прерывания. Почему процесс не проверяет наличие сигналов в момент обращения к системной функции?
*13. Предположим, что после исполнения системной функции процесс готовится к возвращению в режим задачи и не обнаруживает ни одного необработанного сигнала. Сразу после этого ядро обрабатывает прерывание и посылает процессу сигнал. (Например, пользователем была нажата клавиша "break".) Что делает процесс после того, как ядро завершает обработку прерывания?
*14. Если процессу одновременно посылается несколько сигналов, ядро обрабатывает их в том порядке, в каком они перечислены в описании. Существуют три способа реагирования на получение сигнала — прием сигналов, завершение выполнения со сбросом на внешний носитель (дампированием) образа процесса в памяти и завершение выполнения без дампирования. Можно ли указать наилучший порядок обработки одновременно поступающих сигналов? Например, если процесс получает сигнал о выходе (вызывающий дампирование образа процесса в памяти) и сигнал о прерывании (выход без дампирования), то какой из этих сигналов имело бы смысл обработать первым?
15. Запомните новую системную функцию newpgrp(pid,ngrp); которая включает процесс с идентификатором pid в группу процессов с номером ngrp (устанавливает для процесса новую группу). Подумайте, для каких целей она может использоваться и какие опасности таит в себе ее вызов.
16. Прокомментируйте следующее утверждение: по алгоритму wait процесс может приостановиться до наступления какого-либо события и это не отразилось бы на работе всей системы.
17. Рассмотрим новую системную функцию
nowait(pid);
где pid — идентификатор процесса, являющегося потомком того процесса, который вызывает функцию. Вызывая функцию, процесс тем самым сообщает ядру о том, что он не собирается дожидаться завершения выполнения своего потомка, поэтому ядро может по окончании существования потомка сразу же очистить занимаемое им место в таблице процессов. Каким образом это реализуется на практике? Оцените достоинства новой функции и сравните ее использование с использованием сигналов типа "гибель потомка".
18. Загрузчик модулей на Си автоматически подключает к основному модулю начальную процедуру (startup), которая вызывает функцию main, принадлежащую программе пользователя. Если в пользовательской программе отсутствует вызов функции exit, процедура startup сама вызывает эту функцию при выходе из функции main. Что произошло бы в том случае, если бы и в процедуре startup отсутствовал вызов функции exit (из-за ошибки загрузчика)?
19. Какую информацию получит процесс, выполняющий функцию wait, если его потомок запустит функцию exit без параметра? Имеется в виду, что процесс-потомок вызовет функцию в формате exit() вместо exit(n). Если программист постоянно использует вызов функции exit без параметра, то насколько предсказуемо значение, ожидаемое функцией wait? Докажите свой ответ.
20. Объясните, что произойдет, если процесс, исполняющий программу на Рисунке 7.36 запустит с помощью функции exec самого себя. Как в таком случае ядро сможет избежать возникновения тупиковых ситуаций, связанных с блокировкой индексов?
main(argc,argv)
int argc;
char *argv[];
{
execl(argv[0], argv[0], 0);
}
Рисунок 7.36
21. По условию первым аргументом функции exec является имя (последняя компонента имени пути поиска) исполняемого процессом файла. Что произойдет в результате выполнения программы, приведенной на Рисунке 7.37? Каков будет эффект, если в качестве файла "a.out" выступит загрузочный модуль, полученный в результате трансляции программы, приведенной на Рисунке 7.36?
main() {
if (fork() == 0) {
execl("a.out", 0);
printf("неудачное завершение функции exec\n");
}
}
Рисунок 7.37
22. Предположим, что в языке Си поддерживается новый тип данных "read-only" (только для чтения), причем процесс, пытающийся записать информацию в поле с этим типом, получает отказ системы защиты. Опишите реализацию этого момента. (Намек: сравните это понятие с понятием "разделяемая область команд".) В какие из алгоритмов ядра потребуется внести изменения? Какие еще объекты могут быть реализованы аналогичным с областью образом?