Читать книгу 📗 "Linux программирование в примерах - Роббинс Арнольд"
41 /* childhandler --- перехват SIGCHLD, сбор сведений со всех доступных потомков */4243 void childhandler(int sig)44 {45 int status, ret;46 int i;47 char buf[100];48 static const char entered[] = "Entered childhandlern" ;49 static const char exited[] = "Exited childhandlern";5051 writed, entered, strlen(entered));52 for (i =0; i < nkids; i++) {53 if (kids[i] == NOT_USED)54 continue;5556 retry:57 if ((ret = waitpid(kids[i], &status, WNOHANG)) == kids[i]) {58 strcpy(buf, "treaped process ");59 strcat(buf, format_num(ret));60 strcat(buf, "n");61 write(1, buf, strlen(buf));62 kids[i] = NOT_USED;63 } else if (ret == 0) {64 strcpy(buf, "tpid ");65 strcat(buf, format_num(kids[i]));66 strcat(buf, " not available yetn");67 write(1, buf, strlen(buf));68 } else if (ret == -1 && errno == EINTR) {69 write(1, "tretryingn", 10);70 goto retry;71 } else {72 strcpy(buf, "twaitpid() failed: ");73 strcat(buf, strerror(errno));74 strcat(buf, "n");75 write(1, buf, strlen(buf));76 }77 }78 write(1, exited, strlen(exited));79 }Строки 51 и 58 выводят «входное» и «завершающее» сообщения, так что мы можем ясно видеть, когда вызывается обработчик сигнала. Другие сообщения начинаются с ведущего символа TAB.
Главной частью обработчика сигнала является большой цикл, строки 52–77. Строки 53–54 проверяют на
NOT_USEDСтрока 57 вызывает
waitpid()kidsWNOHANGwaitpid()Основываясь на возвращенном значении, код предпринимает соответствующее действие. Строки 57–62 обрабатывают случай обнаружения потомка, выводя сообщение и помещая в соответствующий слот в
kidsNOT_USEDСтроки 63–67 обрабатывают случай, когда затребованный потомок недоступен. В этом случае возвращается значение 0, поэтому выводится сообщение, и выполнение продолжается.
Строки 68–70 обрабатывают случай, при котором был прерван системный вызов. В этом случае самым подходящим способом обработки является
gotowaitpid()main()Строки 71–76 обрабатывают любую другую ошибку, выводя соответствующее сообщение об ошибке.
81 /* main --- установка связанных с порожденными процессами сведений и сигналов, создание порожденных процессов */8283 int main(int argc, char **argv)84 {85 struct sigaction sa;86 sigset_t childset, emptyset;87 int i;8889 for (i = 0; i < nkids; i++)90 kids[i] = NOT_USED;9192 sigemptyset(&emptyset);9394 sa.sa_flags =SA_NOCLDSTOP;95 sa.sa_handler = childhandler;96 sigfillset(&sa.sa_mask); /* блокировать все при вызове обработчика */97 sigaction(SIGCHLD, &sa, NULL);9899 sigemptyset(&childset);100 sigaddset(&childset, SIGCHLD);101102 sigprocmask(SIG_SETMASK, &childset, NULL); /* блокировать его в коде main */103104 for (nkids = 0; nkids < 5; nkids++) {105 if ((kids[nkids] = fdrk()) == 0) {106 sleep(3);107 _exit(0);108 }109 }110111 sleep(5); /* дать потомкам возможность завершения */112113 printf("waiting for signaln");114 sigsuspend(&emptyset);115 116 return 0;117 }Строки 89–90 инициализируют
kidsemptysetSIGCHLDSA_NOCLDSTOP