2
0

async-teardown.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. static void hup_handler(int signal)
  25. {
  26. /* Check every second if this process has been reparented. */
  27. while (the_ppid == getppid()) {
  28. /* sleep() is safe to use in a signal handler. */
  29. sleep(1);
  30. }
  31. /* At this point the parent process has terminated completely. */
  32. _exit(0);
  33. }
  34. static int async_teardown_fn(void *arg)
  35. {
  36. struct sigaction sa = { .sa_handler = hup_handler };
  37. sigset_t hup_signal;
  38. char name[16];
  39. /* Set a meaningful name for this process. */
  40. snprintf(name, 16, "cleanup/%d", the_ppid);
  41. prctl(PR_SET_NAME, (unsigned long)name);
  42. /*
  43. * Close all file descriptors that might have been inherited from the
  44. * main qemu process when doing clone, needed to make libvirt happy.
  45. */
  46. qemu_close_all_open_fd(NULL, 0);
  47. /* Set up a handler for SIGHUP and unblock SIGHUP. */
  48. sigaction(SIGHUP, &sa, NULL);
  49. sigemptyset(&hup_signal);
  50. sigaddset(&hup_signal, SIGHUP);
  51. sigprocmask(SIG_UNBLOCK, &hup_signal, NULL);
  52. /* Ask to receive SIGHUP when the parent dies. */
  53. prctl(PR_SET_PDEATHSIG, SIGHUP);
  54. /*
  55. * Sleep forever, unless the parent process has already terminated. The
  56. * only interruption can come from the SIGHUP signal, which in normal
  57. * operation is received when the parent process dies.
  58. */
  59. if (the_ppid == getppid()) {
  60. pause();
  61. }
  62. /* At this point the parent process has terminated completely. */
  63. _exit(0);
  64. }
  65. /*
  66. * Allocate a new stack of a reasonable size, and return a pointer to its top.
  67. */
  68. static void *new_stack_for_clone(void)
  69. {
  70. size_t stack_size = CLONE_STACK_SIZE;
  71. char *stack_ptr;
  72. /* Allocate a new stack and get a pointer to its top. */
  73. stack_ptr = qemu_alloc_stack(&stack_size);
  74. stack_ptr += stack_size;
  75. return stack_ptr;
  76. }
  77. /*
  78. * Block all signals, start (clone) a new process sharing the address space
  79. * with qemu (CLONE_VM), then restore signals.
  80. */
  81. void init_async_teardown(void)
  82. {
  83. sigset_t all_signals, old_signals;
  84. the_ppid = getpid();
  85. sigfillset(&all_signals);
  86. sigprocmask(SIG_BLOCK, &all_signals, &old_signals);
  87. clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
  88. sigprocmask(SIG_SETMASK, &old_signals, NULL);
  89. }