Skip to content

Commit b21f596

Browse files
committed
feat: ll-init waits all child processes in the container
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
1 parent 19235c2 commit b21f596

1 file changed

Lines changed: 61 additions & 44 deletions

File tree

apps/ll-init/src/ll-init.cpp

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,28 @@
99
#include <csignal>
1010
#include <cstring>
1111
#include <iostream>
12-
#include <optional>
1312
#include <variant>
1413
#include <vector>
1514

1615
#include <sys/wait.h>
1716

1817
// no need to block these signals
19-
constexpr std::array<int, 11> unblock_signals{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGSYS,
20-
SIGTRAP, SIGXCPU, SIGXFSZ, SIGTTIN, SIGTTOU };
18+
constexpr std::array<int, 13> unblock_signals{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
19+
SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ, SIGTTIN,
20+
SIGTTOU, SIGINT, SIGTERM };
2121

2222
struct sig_conf
2323
{
2424
sigset_t cur_set{};
2525
sigset_t old_set{};
2626
struct sigaction ttin_action{};
2727
struct sigaction ttou_action{};
28+
struct sigaction int_action{};
29+
struct sigaction term_action{};
2830
};
2931

32+
sig_atomic_t received_signal{ 0 };
33+
3034
namespace {
3135

3236
void print_sys_error(std::string_view msg) noexcept
@@ -36,7 +40,14 @@ void print_sys_error(std::string_view msg) noexcept
3640

3741
void print_info(std::string_view msg) noexcept
3842
{
39-
std::cout << msg << std::endl;
43+
std::cerr << msg << std::endl;
44+
}
45+
46+
// ATTENTION: there is a potential risk that the signal will be overridden if multiple signals are
47+
// received at the same time.
48+
void sig_forward(int signo) noexcept
49+
{
50+
received_signal = signo;
4051
}
4152

4253
using sig_result = std::variant<int, sig_conf>;
@@ -49,6 +60,7 @@ sig_result handle_signals() noexcept
4960
::sigdelset(&conf.cur_set, signal);
5061
}
5162

63+
// ignore the rest of the signals
5264
auto ret = ::sigprocmask(SIG_SETMASK, &conf.cur_set, &conf.old_set);
5365
if (ret == -1) {
5466
print_sys_error("Failed to set signal mask");
@@ -71,6 +83,21 @@ sig_result handle_signals() noexcept
7183
return -1;
7284
}
7385

86+
// we only forward SIGINT, SIGTERM to the child process
87+
struct sigaction forward_action{};
88+
forward_action.sa_handler = sig_forward;
89+
forward_action.sa_flags = 0;
90+
91+
if (::sigaction(SIGINT, &forward_action, &conf.int_action) == -1) {
92+
print_sys_error("Failed to forward SIGINT");
93+
return -1;
94+
}
95+
96+
if (::sigaction(SIGTERM, &forward_action, &conf.term_action) == -1) {
97+
print_sys_error("Failed to forward SIGTERM");
98+
return -1;
99+
}
100+
74101
return conf;
75102
}
76103

@@ -124,32 +151,28 @@ pid_t run(std::vector<const char *> args, const sig_conf &conf) noexcept
124151
return -1;
125152
}
126153

154+
ret = ::sigaction(SIGINT, &conf.int_action, nullptr);
155+
if (ret == -1) {
156+
print_sys_error("Failed to restore SIGINT action");
157+
return -1;
158+
}
159+
160+
ret = ::sigaction(SIGTERM, &conf.term_action, nullptr);
161+
if (ret == -1) {
162+
print_sys_error("Failed to restore SIGTERM action");
163+
return -1;
164+
}
165+
127166
args.emplace_back(nullptr);
128167

129168
::execv(args[0], const_cast<char *const *>(args.data()));
130169
print_sys_error("Failed to exec");
131-
return -1;
170+
::_exit(EXIT_FAILURE);
132171
}
133172

134173
return pid;
135174
}
136175

137-
std::optional<int> handle_exited_child(pid_t child) noexcept
138-
{
139-
int status{};
140-
while (true) {
141-
auto ret = ::waitpid(-1, &status, WNOHANG);
142-
if (ret == 0) {
143-
break;
144-
}
145-
146-
if (ret == child) {
147-
return status;
148-
}
149-
}
150-
151-
return std::nullopt;
152-
}
153176
} // namespace
154177

155178
int main(int argc, char *argv[])
@@ -175,48 +198,42 @@ int main(int argc, char *argv[])
175198

176199
auto child = run(args, conf);
177200
if (child == -1) {
178-
return -1;
179-
}
180-
181-
auto sigfd = ::signalfd(-1, &conf.cur_set, 0);
182-
if (sigfd == -1) {
183-
print_sys_error("Failed to create signalfd");
201+
print_info("Failed to run child process");
184202
return -1;
185203
}
186204

187205
int child_status{};
188-
signalfd_siginfo info{};
189206
while (true) {
190-
std::memset(&info, 0, sizeof(info));
191-
auto ret = ::read(sigfd, &info, sizeof(info));
192-
if (ret == -1) {
193-
print_sys_error("Failed to read from signalfd");
194-
return -1;
207+
ret = waitpid(-1, &child_status, 0);
208+
if (ret != -1) {
209+
if (ret == child) {
210+
// if child process already exited, we will send the signal to all processes in this
211+
// pid namespace
212+
child = -1;
213+
}
214+
215+
continue;
195216
}
196217

197-
if (info.ssi_signo != SIGCHLD) {
198-
ret = ::kill(child, info.ssi_signo);
218+
if (errno == EINTR) {
219+
ret = ::kill(child, received_signal);
199220
if (ret == -1) {
200-
auto msg = std::string("Failed to forward signal ") + ::strsignal(info.ssi_signo);
221+
auto msg = std::string("Failed to forward signal ") + ::strsignal(received_signal);
201222
print_sys_error(msg);
202223
}
203224
}
204225

205-
auto child_exited = handle_exited_child(child);
206-
if (child_exited) {
207-
child_status = *child_exited;
226+
if (errno == ECHILD) {
208227
break;
209228
}
210229
}
211230

212-
::close(sigfd);
213-
214231
if (WIFEXITED(child_status)) {
215-
print_info("Child exited with status " + std::to_string(WEXITSTATUS(child_status)));
232+
print_info("Last child exited with status " + std::to_string(WEXITSTATUS(child_status)));
216233
} else if (WIFSIGNALED(child_status)) {
217-
print_info("Child exited with signal " + std::to_string(WTERMSIG(child_status)));
234+
print_info("Last child exited with signal " + std::to_string(WTERMSIG(child_status)));
218235
} else {
219-
print_info("Child exited with unknown status");
236+
print_info("Last child exited with unknown status");
220237
}
221238

222239
return 0;

0 commit comments

Comments
 (0)