Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Когда процессу нужно выполнять действия перед приостановкой, должен быть предусмотрен обработчик сигнала для 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; /* переадресации ввода-вывода */
40: glob_t globResult; /* результат универсализации параметров */
41: int freeGlob; /* должен ли освобождаться globResult? */
42: int isStopped; /* выполняется ли программа в данный момент?*/
43: };
Мы уже различаем работающие и завершенные дочерние программы с помощью элемента pid
структуры struct childProgram
, равного нулю в случае завершения дочерней программы, а в противном случае содержащего действительный идентификатор процесса. Новый элемент, isStopped
, не равен нулю, если процесс был остановлен, в ином же случае он равен нулю. Обратите внимание, что его значение неважно, если pid
равен нулю.
Аналогичные изменения потребуется внести и в struct job
. Ранее эта структура отслеживала определенное количество программ в задании и количество выполняющихся процессов. Ее новый элемент, stoppedProgs
, записывает количество процессов задания, остановленных в данный момент. Он может быть вычислен на основе элементов isStopped
дочерних программ, содержащихся в задании, но лучше отслеживать его отдельно. После этого изменения получаем окончательную форму структуры struct job
.
45: struct job {
46: int jobld; /* номер задания */
47: int numProgs; /* количество программ в задании */
48: int runningProgs; /* количество выполняющихся программ */
49: char * text; /* имя задания */
50: char * cmdBuf; /* буфер различных argv */
51: pid_t pgrp; /* идентификатор группы процессов задания */
52: struct childProgram* progs; /* массив программ в задании */
53: struct job * next; /* для слежения за фоновыми программами */
54: int stopped Progs; /* количество активных, однако остановленных программ */
55: };
Как и предыдущие версии ladsh
, код ladsh4.с
игнорирует SIGTTOU
. Это делается, чтобы позволить использовать tcsetpgrp()
даже тогда, когда оболочка не является процессом переднего плана. Однако поскольку оболочка уже будет поддерживать правильное управление заданиями, дочерним процессам не следует игнорировать сигнал. Как только новый процесс разветвляется с помощью runCommand()
, он устанавливает обработчик для SIGTTOU
в SIG_DFL
. Это позволяет драйверу терминала приостановить фоновые процессы, пытающиеся выполнить запись в терминал или провести с ним еще какие-то действия. Ниже приведен код, который начинается с создания дочернего процесса, где сбрасывается SIGTTOU
и выполняется дополнительная работа по синхронизации.
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()
. Обе этих кодовых цепочки необходимо модифицировать с целью обработки остановленных и завершенных дочерних процессов.
Интервал:
Закладка: