2
0

async-teardown.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Asynchronous teardown
  3. *
  4. * Copyright IBM, Corp. 2022
  5. *
  6. * Authors:
  7. * Claudio Imbrenda <imbrenda@linux.ibm.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or (at your
  10. * option) any later version. See the COPYING file in the top-level directory.
  11. *
  12. */
  13. #include "qemu/osdep.h"
  14. #include <dirent.h>
  15. #include <sys/prctl.h>
  16. #include <sched.h>
  17. #include "qemu/async-teardown.h"
  18. #ifdef _SC_THREAD_STACK_MIN
  19. #define CLONE_STACK_SIZE sysconf(_SC_THREAD_STACK_MIN)
  20. #else
  21. #define CLONE_STACK_SIZE 16384
  22. #endif
  23. static pid_t the_ppid;
  24. /*
  25. * Close all open file descriptors.
  26. */
  27. static void close_all_open_fd(void)
  28. {
  29. struct dirent *de;
  30. int fd, dfd;
  31. DIR *dir;
  32. #ifdef CONFIG_CLOSE_RANGE
  33. int r = close_range(0, ~0U, 0);
  34. if (!r) {
  35. /* Success, no need to try other ways. */
  36. return;
  37. }
  38. #endif
  39. dir = opendir("/proc/self/fd");
  40. if (!dir) {
  41. /* If /proc is not mounted, there is nothing that can be done. */
  42. return;
  43. }
  44. /* Avoid closing the directory. */
  45. dfd = dirfd(dir);
  46. for (de = readdir(dir); de; de = readdir(dir)) {
  47. fd = atoi(de->d_name);
  48. if (fd != dfd) {
  49. close(fd);
  50. }
  51. }
  52. closedir(dir);
  53. }
  54. static void hup_handler(int signal)
  55. {
  56. /* Check every second if this process has been reparented. */
  57. while (the_ppid == getppid()) {
  58. /* sleep() is safe to use in a signal handler. */
  59. sleep(1);
  60. }
  61. /* At this point the parent process has terminated completely. */
  62. _exit(0);
  63. }
  64. static int async_teardown_fn(void *arg)
  65. {
  66. struct sigaction sa = { .sa_handler = hup_handler };
  67. sigset_t hup_signal;
  68. char name[16];
  69. /* Set a meaningful name for this process. */
  70. snprintf(name, 16, "cleanup/%d", the_ppid);
  71. prctl(PR_SET_NAME, (unsigned long)name);
  72. /*
  73. * Close all file descriptors that might have been inherited from the
  74. * main qemu process when doing clone, needed to make libvirt happy.
  75. * Not using close_range for increased compatibility with older kernels.
  76. */
  77. close_all_open_fd();
  78. /* Set up a handler for SIGHUP and unblock SIGHUP. */
  79. sigaction(SIGHUP, &sa, NULL);
  80. sigemptyset(&hup_signal);
  81. sigaddset(&hup_signal, SIGHUP);
  82. sigprocmask(SIG_UNBLOCK, &hup_signal, NULL);
  83. /* Ask to receive SIGHUP when the parent dies. */
  84. prctl(PR_SET_PDEATHSIG, SIGHUP);
  85. /*
  86. * Sleep forever, unless the parent process has already terminated. The
  87. * only interruption can come from the SIGHUP signal, which in normal
  88. * operation is received when the parent process dies.
  89. */
  90. if (the_ppid == getppid()) {
  91. pause();
  92. }
  93. /* At this point the parent process has terminated completely. */
  94. _exit(0);
  95. }
  96. /*
  97. * Allocate a new stack of a reasonable size, and return a pointer to its top.
  98. */
  99. static void *new_stack_for_clone(void)
  100. {
  101. size_t stack_size = CLONE_STACK_SIZE;
  102. char *stack_ptr;
  103. /* Allocate a new stack and get a pointer to its top. */
  104. stack_ptr = qemu_alloc_stack(&stack_size);
  105. #if !defined(HOST_HPPA)
  106. /* The top is at the end of the area, except on HPPA. */
  107. stack_ptr += stack_size;
  108. #endif
  109. return stack_ptr;
  110. }
  111. /*
  112. * Block all signals, start (clone) a new process sharing the address space
  113. * with qemu (CLONE_VM), then restore signals.
  114. */
  115. void init_async_teardown(void)
  116. {
  117. sigset_t all_signals, old_signals;
  118. the_ppid = getpid();
  119. sigfillset(&all_signals);
  120. sigprocmask(SIG_BLOCK, &all_signals, &old_signals);
  121. clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
  122. sigprocmask(SIG_SETMASK, &old_signals, NULL);
  123. }