Разработка приложений в среде Linux. Второе издание
Шрифт:
514: pipe(controlfds);
515:
516: if (!(newJob.progs[i].pid = fork)) {
517: signal(SIGTTOU, SIG_DFL);
518:
519: close(controlfds[1]);
520: /* это чтение вернет 0, когда закроется записывающая сторона*/
521: read(controlfds[0], &len, 1);
522: close(controlfds[0]);
Канал
controlfds
используется для приостановки дочернего процесса до того, как оболочка переместит этот
setpgid
в строке 546. Этот тип механизма необходим для гарантии того, что дочерний процесс перемещается в группу процессов до происшествия exec
. Если подождать до exec
, то не будет уверенности, что процесс попадет в правильную группу процессов, пока он не начнет доступ к терминалу (который может быть запрещен). Завершенные дочерние процессы проверяются
ladsh
два раза. Первый раз это происходит во время ожидания процессов в группе процессов переднего плана. После завершения либо остановки процесса переднего плана ladsh
проверяет изменения в состояниях своих фоновых процессов с помощью функции checkJobs
. Обе этих кодовых цепочки необходимо модифицировать с целью обработки остановленных и завершенных дочерних процессов. Добавление флага
WUNTRACED
к вызову waitpid
, ожидающему на процессах переднего плана, позволяет заметить также остановленные процессы. Когда процесс скорее останавливается, чем завершается, устанавливается флаг дочернего процесса isStopped
и увеличивается номер задания stoppedProgs
. Если все программы задания были остановлены, ladsh
снова перемещается на передний план и ожидает команды пользователя. Вот как выглядит часть главного цикла ladsh
, ожидающая на процессе переднего плана. 708: /* задание выполняется на переднем плане; ожидать его */
709: i = 0;
710: while (!jobList.fg->progs[i].pid ||
711: jobList.fg->progs[i].isStopped) i++;
712:
713: waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
714:
715: if (WIFSIGNALED(status) &&
716: (WTERMSIG(status) != SIGINT)) {
717: printf("%s\n", strsignal(status));
718: }
719:
720: if (WIFEXITED(status) || WIFSIGNALED(status)) {
721: /* дочерний процесс завершен */
722: jobList.fg->runningProgs--;
723: jobList.fg->progs[i].pid = 0;
724:
725: if (!jobList.fg->runningProgs) {
726: /* дочерний процесс завершен */
727:
728: removeJob(&jobList, jobList.fg);
729: jobList. fg = NULL;
730:
731: /* переместить оболочку на передний план */
732: if (tcsetpgrp (0, getpid))
733: perror("tcsetpgrp");
734: }
735: } else {
736: /*
дочерний процесс остановлен */
737: jobList.fg->stoppedProgs++;
738: jobList.fg->progs[i].isStopped = 1;
739:
740: if (jobList.fg->stoppedProgs ==
741: jobList.fg->runningProgs) {
742: printf ("\n" JOB_STATUS_FORMAT,
743: jobList.fg->jobId,
744: "Остановлен", jobList.fg->text);
745: jobList.fg = NULL;
746: }
747: }
748:
749: if (!jobList.fg) {
750: /* переместить оболочку на передний план */
751: if (tcsetpgrp (0, getpid))
752: perror("tcsetpgrp");
753: }
754: }
Подобным образом фоновые задания могут прерываться с помощью сигналов. Мы снова добавляем
WUNTRACED
к waitpid
, что проверяет состояния фоновых процессов. После остановки фонового процесса обновляются флаг isStopped
и счетчик stoppedProgs
, а в случае остановки всего задания выводится сообщение. Последняя возможность, требуемая для
ladsh
— перемещение задания между состоянием выполнения на переднем плане, состоянием выполнения в фоне и остановом. Это делается с помощью двух встроенных команд: fg
и bg
. Они являются ограниченными версиями нормальных команд оболочки, носящих те же имена. Оба принимают один параметр, являющийся номером задания, которому предшествует знак %
(для совместимости со стандартными оболочками). Команда fg
перемещает определенное задание на передний план, a bg
запускает его в фоне. Обе операции выполняются передачей
SIGCONT
каждому процессу в активизируемой группе процессов. Поскольку этот сигнал может передаваться каждому процессу с помощью отдельных вызовов kill
, несколько проще передать его всей группе процессов, используя отдельный вызов kill
. Ниже приведена реализация встроенных команд fg
и bg
. 461: } else if (! strcmp(newJob.progs[0].argv[0], "fg") ||
462: !strcmp(newJob.progs[0].argv[0], "bg")) {
463: if (!newJob.progs[0].argv[1] || newJob.progs[0].argv[2]) {
464: fprintf(stderr,
465: "%s: ожидался в точности один аргумент\n",
466: newJob.progs[0].argv[0]);
467: return 1;
468: }
469:
470: if (sscanf(newJob.progs[0].argv[l], "%%%d", &jobNum) != 1)
471: fprintf(stderr, "%s: ошибочный аргумент '%s'\n",
Поделиться:
Популярные книги
Черный Маг Императора 9
9. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому! Том II
2. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Социопата 7
7. Социопат
Фантастика:
боевая фантастика
6.22
рейтинг книги
Бремя империи
Бремя империи - 1.
Фантастика:
альтернативная история
9.34
рейтинг книги
Приручитель женщин-монстров. Том 5
5. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Мастер...
1. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
6.50
рейтинг книги
Эфемер
7. Стеллар
Фантастика:
боевая фантастика
рпг
7.23
рейтинг книги
Приручитель женщин-монстров. Том 4
4. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 3
3. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Дракон
5. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.31
рейтинг книги
Не грози Дубровскому! Том V
5. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Первый пользователь. Книга 2
2. Первый пользователь
Фантастика:
боевая фантастика
рпг
4.80
рейтинг книги
Последний попаданец 9
9. Последний попаданец
Фантастика:
юмористическая фантастика
рпг
5.00
рейтинг книги
Запретный Мир
1. Запретный Мир
Фантастика:
фэнтези
героическая фантастика
8.94