You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

150 lines
3.2 KiB

  1. #include "reaper.h"
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/epoll.h>
  5. #include <sys/wait.h>
  6. #include <sys/signalfd.h>
  7. #define LOG_MODULE "reaper"
  8. #define LOG_ENABLE_DBG 0
  9. #include "log.h"
  10. #include "tllist.h"
  11. struct reaper {
  12. struct fdm *fdm;
  13. int fd;
  14. tll(pid_t) children;
  15. };
  16. static bool fdm_reap(struct fdm *fdm, int fd, int events, void *data);
  17. struct reaper *
  18. reaper_init(struct fdm *fdm)
  19. {
  20. sigset_t mask;
  21. sigemptyset(&mask);
  22. sigaddset(&mask, SIGCHLD);
  23. /* Block normal signal handling - we're using a signalfd instead */
  24. if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
  25. LOG_ERRNO("failed to block SIGCHLD");
  26. return NULL;
  27. }
  28. int fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
  29. if (fd < 0) {
  30. LOG_ERRNO("failed to create signal FD");
  31. sigprocmask(SIG_UNBLOCK, &mask, NULL);
  32. return NULL;
  33. }
  34. struct reaper *reaper = malloc(sizeof(*reaper));
  35. if (unlikely(reaper == NULL)) {
  36. LOG_ERRNO("malloc() failed");
  37. close(fd);
  38. sigprocmask(SIG_UNBLOCK, &mask, NULL);
  39. return NULL;
  40. }
  41. *reaper = (struct reaper){
  42. .fdm = fdm,
  43. .fd = fd,
  44. .children = tll_init(),
  45. };
  46. if (!fdm_add(fdm, fd, EPOLLIN, &fdm_reap, reaper)){
  47. LOG_ERR("failed to register with the FDM");
  48. goto err;
  49. }
  50. return reaper;
  51. err:
  52. tll_free(reaper->children);
  53. close(fd);
  54. free(reaper);
  55. return NULL;
  56. }
  57. void
  58. reaper_destroy(struct reaper *reaper)
  59. {
  60. if (reaper == NULL)
  61. return;
  62. fdm_del(reaper->fdm, reaper->fd);
  63. tll_free(reaper->children);
  64. free(reaper);
  65. sigset_t mask;
  66. sigemptyset(&mask);
  67. sigaddset(&mask, SIGCHLD);
  68. sigprocmask(SIG_UNBLOCK, &mask, NULL);
  69. }
  70. void
  71. reaper_add(struct reaper *reaper, pid_t pid)
  72. {
  73. LOG_DBG("adding pid=%d", pid);
  74. tll_push_back(reaper->children, pid);
  75. }
  76. static bool
  77. fdm_reap(struct fdm *fdm, int fd, int events, void *data)
  78. {
  79. struct reaper *reaper = data;
  80. bool pollin = events & EPOLLIN;
  81. bool hup = events & EPOLLHUP;
  82. if (hup && !pollin)
  83. return false;
  84. assert(pollin);
  85. struct signalfd_siginfo info;
  86. ssize_t amount = read(reaper->fd, &info, sizeof(info));
  87. if (amount < 0) {
  88. LOG_ERRNO("failed to read");
  89. return false;
  90. }
  91. assert((size_t)amount >= sizeof(info));
  92. if (info.ssi_signo != SIGCHLD) {
  93. LOG_WARN("got non-SIGCHLD signal: %d", info.ssi_signo);
  94. return true;
  95. }
  96. tll_foreach(reaper->children, it) {
  97. /* Don't use wait() since we don't want to accidentally reap
  98. * the PTS slave */
  99. pid_t pid = it->item;
  100. int result;
  101. int res = waitpid(pid, &result, WNOHANG);
  102. if (res <= 0) {
  103. if (res < 0)
  104. LOG_ERRNO("waitpid failed for pid=%d", pid);
  105. continue;
  106. }
  107. else if (WIFEXITED(result))
  108. LOG_DBG("pid=%d: exited with status=%d", pid, WEXITSTATUS(result));
  109. else if (WIFSIGNALED(result))
  110. LOG_DBG("pid=%d: killed by signal=%d", pid, WTERMSIG(result));
  111. else
  112. LOG_DBG("pid=%d: died of unknown resason", pid);
  113. tll_remove(reaper->children, it);
  114. }
  115. if (hup)
  116. return false;
  117. return true;
  118. }