Данный сигнал генерируется также фоновым процессом, вызывающим tcflush()
, tcflow()
, tcsetattr()
, tcsetpgrp()
, tcdrain()
или tcsendbreak()
.
Действием по умолчанию каждого из этих трех сигналов является останов процесса. Все эти процессы можно поймать или игнорировать. В обоих случаях процесс не останавливается.
15.1.3. Обработка сигналов управления заданиями
Хотя многие приложения можно останавливать и перезапускать без побочных эффектов, другим процессам требуется обрабатывать состояния останова и запуска. Например, большинству редакторов необходимо модифицировать параметры терминала в рабочем состоянии. Когда пользователи приостанавливают процесс, они ожидают, что их терминал восстановит свое состояние по умолчанию.
Когда процессу нужно выполнять действия перед приостановкой, должен быть предусмотрен обработчик сигнала для SIGTSTP
. Это позволяет ядру уведомлять процесс о необходимости приостановки.
При получении SIGTSTP
процесс должен немедленно выполнить все необходимые ему действия, чтобы разрешить приостановку (например, восстановление исходного состояния терминала) и приостановиться самому. Самый простой способ приостановки процесса — передача самому себе сигнала SIGSTOP
. Однако большинство оболочек отображают сообщения с типом сигнала, вызвавшего остановку процесса, и если процесс передаст себе sigstop, он будет отличаться от большинства приостановленных процессов. Во избежание этого неудобства многие приложения сбрасывают свой обработчик SIGTSTP
в SIG_DFL
и передают себе SIGTSTP
.
Процессам, которые требуют специальный код для правильных приостановок, обычно необходимо выполнять специальные действия при перезапуске. Это легко делается предоставлением обработчика сигнала для SIGCONT
, который выполняет такие действия. Если процесс приостанавливается с помощью SIGTSTP
, такие специальные действия, возможно, включают установку обработчика сигнала для SIGTSTP
.
Ниже приведен код простого обработчика сигналов SIGCONT
и SIGTSTP
. Когда пользователь приостанавливает или перезапускает процесс, последний отображает сообщение перед остановкой или продолжением.
1: /* monitor.с */
2:
3: #include
4: #include
5: #include
6: #include
7:
8: void catchSignal(int sigNum, int useDefault);
9:
10: void handler(int signum) {
11: if (signum == SIGTSTP) {
12: write(STDOUT_FILENO, "получен SIGTSTP\n", 12);
13: catchSignal(SIGTSTP, 1);
14: kill(getpid(), SIGTSTP);
15: } else {
16: write(STDOUT_FILENO, "получен SIGCONT\n", 12);
17: catchSignal(SIGTSTP, 0);
18: }
19: }
20:
21: void catchSignal(int sigNum, int useDefault) {
22: struct sigaction sa;
23:
24: memset(&sa, 0, sizeof(sa));
25:
26: if (useDefault)
27: sa.sa_handler = SIG_DFL;
28: else
29: sa.sa_handler = handler;
30:
31: if (sigaction(sigNum, &sa, NULL)) perror("sigaction");
32: }
33:
34: int main() {
35: catchSignal(SIGTSTP, 0);
36: catchSignal(SIGCONT, 0);
37:
38: while(1);
39:
40: return 0;
41: }
15.2. Управление заданиями в ladsh
Добавление управления заданиями к ladsh
— это последнее добавление к простой оболочке, окончательный исходный код которой можно найти в приложении Б. Для начала потребуется добавить по элементу в структуры struct childProgram
, struct job
и struct jobSet
. Поскольку ladsh
некоторое время не рассматривался, вернитесь в главу 10, где были впервые представлены эти структуры данных. Ниже показано окончательное определение struct childProgram
.
35: struct childProgram {
36: pid_t pid; /* 0 на выходе */
37: char ** argv; /* имя программы с аргументами * /
38: int numRedirections; /* элементы в массиве переадресации */
39: struct redirectionSpecifier * redirections; /* переадресации ввода-вывода */