1
2
3
4
5
6
7
8
9
10
11
12
13#include <stdlib.h>
14#include <stdio.h>
15#include <sys/types.h>
16#include <dirent.h>
17#include <sys/prctl.h>
18#include <signal.h>
19#include <sched.h>
20#include <unistd.h>
21
22#include "qemu/osdep.h"
23#include "qemu/async-teardown.h"
24
25#ifdef _SC_THREAD_STACK_MIN
26#define CLONE_STACK_SIZE sysconf(_SC_THREAD_STACK_MIN)
27#else
28#define CLONE_STACK_SIZE 16384
29#endif
30
31static pid_t the_ppid;
32
33
34
35
36static void close_all_open_fd(void)
37{
38 struct dirent *de;
39 int fd, dfd;
40 DIR *dir;
41
42#ifdef CONFIG_CLOSE_RANGE
43 int r = close_range(0, ~0U, 0);
44 if (!r) {
45
46 return;
47 }
48#endif
49
50 dir = opendir("/proc/self/fd");
51 if (!dir) {
52
53 return;
54 }
55
56 dfd = dirfd(dir);
57
58 for (de = readdir(dir); de; de = readdir(dir)) {
59 fd = atoi(de->d_name);
60 if (fd != dfd) {
61 close(fd);
62 }
63 }
64 closedir(dir);
65}
66
67static void hup_handler(int signal)
68{
69
70 while (the_ppid == getppid()) {
71
72 sleep(1);
73 }
74
75
76 _exit(0);
77}
78
79static int async_teardown_fn(void *arg)
80{
81 struct sigaction sa = { .sa_handler = hup_handler };
82 sigset_t hup_signal;
83 char name[16];
84
85
86 snprintf(name, 16, "cleanup/%d", the_ppid);
87 prctl(PR_SET_NAME, (unsigned long)name);
88
89
90
91
92
93
94 close_all_open_fd();
95
96
97 sigaction(SIGHUP, &sa, NULL);
98 sigemptyset(&hup_signal);
99 sigaddset(&hup_signal, SIGHUP);
100 sigprocmask(SIG_UNBLOCK, &hup_signal, NULL);
101
102
103 prctl(PR_SET_PDEATHSIG, SIGHUP);
104
105
106
107
108
109
110 if (the_ppid == getppid()) {
111 pause();
112 }
113
114
115 _exit(0);
116}
117
118
119
120
121static void *new_stack_for_clone(void)
122{
123 size_t stack_size = CLONE_STACK_SIZE;
124 char *stack_ptr;
125
126
127 stack_ptr = qemu_alloc_stack(&stack_size);
128#if !defined(HOST_HPPA)
129
130 stack_ptr += stack_size;
131#endif
132
133 return stack_ptr;
134}
135
136
137
138
139
140void init_async_teardown(void)
141{
142 sigset_t all_signals, old_signals;
143
144 the_ppid = getpid();
145
146 sigfillset(&all_signals);
147 sigprocmask(SIG_BLOCK, &all_signals, &old_signals);
148 clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL);
149 sigprocmask(SIG_SETMASK, &old_signals, NULL);
150}
151