Я пишу библиотеку, которая использует fork() и exec() для запуска внешних программ.
Код в моей библиотеке работает как отдельный поток.
Поток библиотеки должен обратиться к waitpid() в разветвленном процессе, чтобы узнать код выхода дочернего процесса.
К сожалению, если приложение, использующее мою библиотеку, зарегистрирует обработчик сигнала для SIGCHLD, вызовы waitpid() вернутся с ошибкой ECHILD.
Как мне справиться с этим как с библиотекой с минимальным влиянием на приложение? По сути, я хочу, чтобы ребенок оставался зомби и мог контролировать, когда его пожнут.
Могу ли я оградить себя от действий приложения?
Могу ли я каким-то образом перехватить обработчик сигнала и вернуть его после того, как мой waitpid будет готов?
Прикомандированный. Для этого часто используются сокеты дейтаграмм домена Unix. Доменные сокеты Unix позволяют передавать дескрипторы файлов, например дескрипторы каналов, в / из разветвленного внучатого процесса обратно родительскому процессу, используя вспомогательные сообщения. Сообщения дейтаграмм домена Unix не переупорядочиваются и сохраняют границы сообщений (так что прием с достаточно большим буфером всегда будет получать полные сообщения); эти свойства делают общение простым и надежным. Для этого подхода вам может даже не понадобиться отдельный поток; вспомогательного процесса должно хватить.
Это давняя проблема с моделью вилки / ожидания Unix, и я не уверен, что есть какие-то простые решения.
Да, кажется, действительно сложная проблема. Спасибо за ответы! Поскольку моя библиотека используется очень контролируемым набором пользователей с известной функциональностью, я просто хочу сказать: «НЕ регистрировать обработчики сигналов».
Насколько я понимаю, стандартная функция system() страдает той же проблемой.
Вместо того, чтобы говорить им не устанавливать обработчики сигналов, предоставьте и задокументируйте функцию, которую они должны вызывать в начале своего обработчика SIGCHLD, чтобы ваша библиотека была довольна, и позаботьтесь о том, чтобы эта функция была безопасной для сигналов. И надеюсь, что другие библиотеки, которые использует программа, сами не управляют своими процессами, а оставят это основной программе, как и ваша библиотека тоже должна была сделать ;-)





Освобождение ресурсов, выделенных библиотекой, является ошибкой приложения. В принципе, это то же самое, как если бы приложение делало что-то вроде free(yourlib_create_context(...)), хотя, конечно, последствия менее серьезны. Нет причин пытаться поддерживать такого рода бессмысленное поведение приложения; просто документально подтвердите, что он недействителен.
Если вы хотите "защитить" от такого рода ошибок программирования, маска сигнализирует, а затем вызывает abort, если waitpid не работает с ECHLD. Это безоговорочно завершит процесс, и у заявителя не будет возможности его поймать.
Вы можете сделать так же, как system:
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed. During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.
Набросок может быть
pid_t pid;
sigset_t block, backup;
sigemptyset(&block);
sigaddset(&block, SIGCHLD);
sigprocmask(SIG_BLOCK, &block, &backup);
if ((pid = fork()) < 0) {
// error handle
} else if (pid == 0) { // child
sigprocmask(SIG_SETMASK, &backup, NULL);
// ...
} else {
// waitpid
sigprocmask(SIG_SETMASK, &backup, NULL);
}
// ...
Вы можете разветвить свой процесс собственный для обработки вашей собственной обработки процесса и заставить библиотеку взаимодействовать с автономным процессом через каналы или что-то подобное МПК. Затем вы также можете установить свои собственные обработчики сигналов, например, ваш собственный
SIGCHLDвместо того, чтобы полагаться только наwaitpid.