]> git.proxmox.com Git - mirror_qemu.git/blame - system/async-teardown.c
target: Use vaddr in gen_intermediate_code
[mirror_qemu.git] / system / async-teardown.c
CommitLineData
c891c24b
CI
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 */
2ca10fae
MA
13
14#include "qemu/osdep.h"
c891c24b
CI
15#include <dirent.h>
16#include <sys/prctl.h>
c891c24b 17#include <sched.h>
c891c24b 18
c891c24b
CI
19#include "qemu/async-teardown.h"
20
21#ifdef _SC_THREAD_STACK_MIN
22#define CLONE_STACK_SIZE sysconf(_SC_THREAD_STACK_MIN)
23#else
24#define CLONE_STACK_SIZE 16384
25#endif
26
27static pid_t the_ppid;
28
29/*
30 * Close all open file descriptors.
31 */
32static void close_all_open_fd(void)
33{
34 struct dirent *de;
35 int fd, dfd;
36 DIR *dir;
37
38#ifdef CONFIG_CLOSE_RANGE
39 int r = close_range(0, ~0U, 0);
40 if (!r) {
41 /* Success, no need to try other ways. */
42 return;
43 }
44#endif
45
46 dir = opendir("/proc/self/fd");
47 if (!dir) {
48 /* If /proc is not mounted, there is nothing that can be done. */
49 return;
50 }
51 /* Avoid closing the directory. */
52 dfd = dirfd(dir);
53
54 for (de = readdir(dir); de; de = readdir(dir)) {
55 fd = atoi(de->d_name);
56 if (fd != dfd) {
57 close(fd);
58 }
59 }
60 closedir(dir);
61}
62
63static void hup_handler(int signal)
64{
65 /* Check every second if this process has been reparented. */
66 while (the_ppid == getppid()) {
67 /* sleep() is safe to use in a signal handler. */
68 sleep(1);
69 }
70
71 /* At this point the parent process has terminated completely. */
72 _exit(0);
73}
74
75static int async_teardown_fn(void *arg)
76{
77 struct sigaction sa = { .sa_handler = hup_handler };
78 sigset_t hup_signal;
79 char name[16];
80
81 /* Set a meaningful name for this process. */
82 snprintf(name, 16, "cleanup/%d", the_ppid);
83 prctl(PR_SET_NAME, (unsigned long)name);
84
85 /*
86 * Close all file descriptors that might have been inherited from the
87 * main qemu process when doing clone, needed to make libvirt happy.
88 * Not using close_range for increased compatibility with older kernels.
89 */
90 close_all_open_fd();
91
92 /* Set up a handler for SIGHUP and unblock SIGHUP. */
93 sigaction(SIGHUP, &sa, NULL);
94 sigemptyset(&hup_signal);
95 sigaddset(&hup_signal, SIGHUP);
96 sigprocmask(SIG_UNBLOCK, &hup_signal, NULL);
97
98 /* Ask to receive SIGHUP when the parent dies. */
99 prctl(PR_SET_PDEATHSIG, SIGHUP);
100
101 /*
102 * Sleep forever, unless the parent process has already terminated. The
103 * only interruption can come from the SIGHUP signal, which in normal
104 * operation is received when the parent process dies.
105 */
106 if (the_ppid == getppid()) {
107 pause();
108 }
109
110 /* At this point the parent process has terminated completely. */
111 _exit(0);
112}
113
114/*
115 * Allocate a new stack of a reasonable size, and return a pointer to its top.
116 */
117static void *new_stack_for_clone(void)
118{
119 size_t stack_size = CLONE_STACK_SIZE;
120 char *stack_ptr;
121
122 /* Allocate a new stack and get a pointer to its top. */
123 stack_ptr = qemu_alloc_stack(&stack_size);
c891c24b 124 stack_ptr += stack_size;
c891c24b
CI
125
126 return stack_ptr;
127}
128
129/*
130 * Block all signals, start (clone) a new process sharing the address space
131 * with qemu (CLONE_VM), then restore signals.
132 */
133void init_async_teardown(void)
134{
135 sigset_t all_signals, old_signals;
136
137 the_ppid = getpid();
138
139 sigfillset(&all_signals);
140 sigprocmask(SIG_BLOCK, &all_signals, &old_signals);
141 clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
142 sigprocmask(SIG_SETMASK, &old_signals, NULL);
143}