ppc440_pcix: Rename QOM type define abd move it to common header
[qemu/armbru.git] / util / async-teardown.c
blob3ab19c8740cdf85222ad72dd7f7f722cdb99f1ce
1 /*
2 * Asynchronous teardown
4 * Copyright IBM, Corp. 2022
6 * Authors:
7 * Claudio Imbrenda <imbrenda@linux.ibm.com>
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.
14 #include "qemu/osdep.h"
15 #include "qemu/config-file.h"
16 #include "qemu/option.h"
17 #include "qemu/module.h"
18 #include <dirent.h>
19 #include <sys/prctl.h>
20 #include <sched.h>
22 #include "qemu/async-teardown.h"
24 #ifdef _SC_THREAD_STACK_MIN
25 #define CLONE_STACK_SIZE sysconf(_SC_THREAD_STACK_MIN)
26 #else
27 #define CLONE_STACK_SIZE 16384
28 #endif
30 static pid_t the_ppid;
33 * Close all open file descriptors.
35 static void close_all_open_fd(void)
37 struct dirent *de;
38 int fd, dfd;
39 DIR *dir;
41 #ifdef CONFIG_CLOSE_RANGE
42 int r = close_range(0, ~0U, 0);
43 if (!r) {
44 /* Success, no need to try other ways. */
45 return;
47 #endif
49 dir = opendir("/proc/self/fd");
50 if (!dir) {
51 /* If /proc is not mounted, there is nothing that can be done. */
52 return;
54 /* Avoid closing the directory. */
55 dfd = dirfd(dir);
57 for (de = readdir(dir); de; de = readdir(dir)) {
58 fd = atoi(de->d_name);
59 if (fd != dfd) {
60 close(fd);
63 closedir(dir);
66 static void hup_handler(int signal)
68 /* Check every second if this process has been reparented. */
69 while (the_ppid == getppid()) {
70 /* sleep() is safe to use in a signal handler. */
71 sleep(1);
74 /* At this point the parent process has terminated completely. */
75 _exit(0);
78 static int async_teardown_fn(void *arg)
80 struct sigaction sa = { .sa_handler = hup_handler };
81 sigset_t hup_signal;
82 char name[16];
84 /* Set a meaningful name for this process. */
85 snprintf(name, 16, "cleanup/%d", the_ppid);
86 prctl(PR_SET_NAME, (unsigned long)name);
89 * Close all file descriptors that might have been inherited from the
90 * main qemu process when doing clone, needed to make libvirt happy.
91 * Not using close_range for increased compatibility with older kernels.
93 close_all_open_fd();
95 /* Set up a handler for SIGHUP and unblock SIGHUP. */
96 sigaction(SIGHUP, &sa, NULL);
97 sigemptyset(&hup_signal);
98 sigaddset(&hup_signal, SIGHUP);
99 sigprocmask(SIG_UNBLOCK, &hup_signal, NULL);
101 /* Ask to receive SIGHUP when the parent dies. */
102 prctl(PR_SET_PDEATHSIG, SIGHUP);
105 * Sleep forever, unless the parent process has already terminated. The
106 * only interruption can come from the SIGHUP signal, which in normal
107 * operation is received when the parent process dies.
109 if (the_ppid == getppid()) {
110 pause();
113 /* At this point the parent process has terminated completely. */
114 _exit(0);
118 * Allocate a new stack of a reasonable size, and return a pointer to its top.
120 static void *new_stack_for_clone(void)
122 size_t stack_size = CLONE_STACK_SIZE;
123 char *stack_ptr;
125 /* Allocate a new stack and get a pointer to its top. */
126 stack_ptr = qemu_alloc_stack(&stack_size);
127 #if !defined(HOST_HPPA)
128 /* The top is at the end of the area, except on HPPA. */
129 stack_ptr += stack_size;
130 #endif
132 return stack_ptr;
136 * Block all signals, start (clone) a new process sharing the address space
137 * with qemu (CLONE_VM), then restore signals.
139 void init_async_teardown(void)
141 sigset_t all_signals, old_signals;
143 the_ppid = getpid();
145 sigfillset(&all_signals);
146 sigprocmask(SIG_BLOCK, &all_signals, &old_signals);
147 clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
148 sigprocmask(SIG_SETMASK, &old_signals, NULL);
151 static QemuOptsList qemu_run_with_opts = {
152 .name = "run-with",
153 .head = QTAILQ_HEAD_INITIALIZER(qemu_run_with_opts.head),
154 .desc = {
156 .name = "async-teardown",
157 .type = QEMU_OPT_BOOL,
159 { /* end of list */ }
163 static void register_teardown(void)
165 qemu_add_opts(&qemu_run_with_opts);
167 opts_init(register_teardown);