Skip to content

Commit ac9ba51

Browse files
committed
refactor: add container_monitor for better reusability
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
1 parent 173f400 commit ac9ba51

10 files changed

Lines changed: 358 additions & 257 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ set(linyaps-box_LIBRARY_SOURCE
147147
src/linyaps_box/config.h
148148
src/linyaps_box/container.cpp
149149
src/linyaps_box/container.h
150+
src/linyaps_box/container_monitor.cpp
151+
src/linyaps_box/container_monitor.h
150152
src/linyaps_box/container_ref.cpp
151153
src/linyaps_box/container_ref.h
152154
src/linyaps_box/container_status.cpp

src/linyaps_box/container.cpp

Lines changed: 30 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44

55
#include "linyaps_box/container.h"
66

7+
#include "linyaps_box/container_monitor.h"
78
#include "linyaps_box/impl/disabled_cgroup_manager.h"
8-
#include "linyaps_box/io/epoll.h"
9-
#include "linyaps_box/io/forwarder.h"
109
#include "linyaps_box/terminal.h"
1110
#include "linyaps_box/unixsocket.h"
1211
#include "linyaps_box/utils/cgroups.h"
@@ -2344,136 +2343,6 @@ void poststop_hooks(const linyaps_box::container &container) noexcept
23442343
}
23452344
}
23462345

2347-
struct wait_process_ctx
2348-
{
2349-
pid_t pid{ -1 };
2350-
std::optional<linyaps_box::terminal_master> master;
2351-
std::optional<linyaps_box::terminal_slave> host_tty;
2352-
linyaps_box::utils::file_descriptor in;
2353-
linyaps_box::utils::file_descriptor out;
2354-
};
2355-
2356-
[[nodiscard]] int wait_container_process(wait_process_ctx ctx)
2357-
{
2358-
LINYAPS_BOX_DEBUG() << "Wait container process: " << ctx.pid;
2359-
2360-
sigset_t set;
2361-
linyaps_box::utils::sigfillset(set);
2362-
linyaps_box::utils::sigprocmask(SIG_BLOCK, set, nullptr);
2363-
auto signalfd = linyaps_box::utils::create_signalfd(set);
2364-
2365-
int exit_code{ 0 };
2366-
bool child_exited{ false };
2367-
2368-
// try to reap child process. Child process may exit before we create signalfd and it wouldn't
2369-
// receive SIGCHLD anymore. If we don't do this, the child process (or its children) will be
2370-
// zombie process
2371-
auto ret = linyaps_box::utils::waitpid(ctx.pid, WNOHANG);
2372-
2373-
if (ret.status == linyaps_box::utils::WaitStatus::Reaped) {
2374-
child_exited = true;
2375-
exit_code = WIFSIGNALED(ret.exit_code) ? 128 + WTERMSIG(ret.exit_code)
2376-
: WEXITSTATUS(ret.exit_code);
2377-
} else if (ret.status == linyaps_box::utils::WaitStatus::NoChild) {
2378-
throw std::runtime_error("target pid " + std::to_string(ctx.pid) + " is not a child");
2379-
}
2380-
2381-
linyaps_box::io::Epoll epoll;
2382-
auto signalfd_pollable = epoll.add(signalfd, EPOLLIN);
2383-
assert(signalfd_pollable);
2384-
if (UNLIKELY(!signalfd_pollable)) {
2385-
throw std::runtime_error("failed to add signalfd to epoll");
2386-
}
2387-
2388-
constexpr auto buffer_size = 256 * 1024;
2389-
std::optional<linyaps_box::utils::file_descriptor> master_out;
2390-
std::optional<linyaps_box::io::Forwarder> in_fwd;
2391-
std::optional<linyaps_box::io::Forwarder> out_fwd;
2392-
2393-
if (ctx.master) {
2394-
master_out = ctx.master->get().duplicate();
2395-
master_out->set_nonblock(true);
2396-
2397-
if (!child_exited) {
2398-
in_fwd.emplace(epoll, buffer_size);
2399-
in_fwd->set_src(ctx.in);
2400-
in_fwd->set_dst(ctx.master->get());
2401-
}
2402-
2403-
out_fwd.emplace(epoll, buffer_size);
2404-
out_fwd->set_src(master_out.value());
2405-
out_fwd->set_dst(ctx.out);
2406-
}
2407-
2408-
auto handle_signal = [&] {
2409-
struct signalfd_siginfo info{};
2410-
if (signalfd.read(info) != linyaps_box::unixSocketClient::IOStatus::Success) {
2411-
return;
2412-
}
2413-
2414-
if (info.ssi_signo == SIGCHLD) {
2415-
auto res = linyaps_box::utils::waitpid(ctx.pid, WNOHANG);
2416-
if (res.status == linyaps_box::utils::WaitStatus::Reaped) {
2417-
child_exited = true;
2418-
in_fwd.reset();
2419-
exit_code = WIFSIGNALED(res.exit_code) ? 128 + WTERMSIG(res.exit_code)
2420-
: WEXITSTATUS(res.exit_code);
2421-
}
2422-
} else if (info.ssi_signo == SIGWINCH && ctx.master) {
2423-
ctx.master->resize(ctx.host_tty->get_size());
2424-
} else if (!child_exited) {
2425-
kill(ctx.pid, info.ssi_signo);
2426-
}
2427-
};
2428-
2429-
while (!child_exited || out_fwd) {
2430-
bool keep_pumping{ false };
2431-
2432-
if (in_fwd) {
2433-
auto s = in_fwd->handle_forwarding();
2434-
if (s == linyaps_box::io::Forwarder::Status::Finished) {
2435-
in_fwd.reset();
2436-
} else if (s == linyaps_box::io::Forwarder::Status::Busy
2437-
&& !in_fwd->is_src_pollable()) {
2438-
keep_pumping = true;
2439-
}
2440-
}
2441-
2442-
if (out_fwd) {
2443-
auto s = out_fwd->handle_forwarding();
2444-
if (s == linyaps_box::io::Forwarder::Status::Finished) {
2445-
out_fwd.reset();
2446-
} else if (s == linyaps_box::io::Forwarder::Status::Busy
2447-
&& !out_fwd->is_dst_pollable()) {
2448-
keep_pumping = true;
2449-
}
2450-
}
2451-
2452-
const auto &events = epoll.wait(keep_pumping ? 0 : -1);
2453-
for (const auto &ev : events) {
2454-
if (ev.data.fd == signalfd.get()) {
2455-
handle_signal();
2456-
if (child_exited) {
2457-
break;
2458-
}
2459-
2460-
continue;
2461-
}
2462-
}
2463-
2464-
if (child_exited && out_fwd) {
2465-
auto status = out_fwd->handle_forwarding();
2466-
if (status == linyaps_box::io::Forwarder::Status::Finished) {
2467-
out_fwd.reset();
2468-
} else if (status == linyaps_box::io::Forwarder::Status::Busy) {
2469-
keep_pumping = true;
2470-
}
2471-
}
2472-
}
2473-
2474-
return exit_code;
2475-
}
2476-
24772346
} // namespace runtime_ns
24782347

24792348
} // namespace
@@ -2576,6 +2445,10 @@ int linyaps_box::container::run(run_container_options_t options) const
25762445
// TODO: cgroup preenter
25772446
auto [child_pid, socket] = runtime_ns::start_container_process(*this, options);
25782447

2448+
auto in = utils::file_descriptor{ utils::fileno(stdin), false };
2449+
auto out = utils::file_descriptor{ utils::fileno(stdout), false };
2450+
container_monitor monitor(child_pid);
2451+
25792452
{
25802453
auto status = this->status();
25812454
assert(status.status == container_status_t::runtime_status::CREATING);
@@ -2589,16 +2462,37 @@ int linyaps_box::container::run(run_container_options_t options) const
25892462
runtime_ns::create_runtime_hooks(*this, socket);
25902463
runtime_ns::wait_create_container_result(*this, socket);
25912464

2592-
auto master = [&recv_socketpair]() -> std::optional<linyaps_box::terminal_master> {
2465+
auto host_tty = [&recv_socketpair, &monitor, &in, &out]() -> std::optional<terminal_slave> {
25932466
if (!recv_socketpair) {
25942467
return std::nullopt;
25952468
}
25962469

2597-
auto ret = runtime_ns::recv_master_tty(recv_socketpair.value());
2470+
LINYAPS_BOX_DEBUG() << "Container requires a terminal";
2471+
2472+
auto master = runtime_ns::recv_master_tty(recv_socketpair.value());
25982473
recv_socketpair->release();
2599-
return ret;
2474+
2475+
in.set_nonblock(true);
2476+
out.set_nonblock(true);
2477+
2478+
std::optional<terminal_slave> host_tty;
2479+
if (utils::isatty(in)) {
2480+
host_tty.emplace(in.duplicate());
2481+
} else if (utils::isatty(out)) {
2482+
host_tty.emplace(out.duplicate());
2483+
} else {
2484+
auto default_tty = utils::open("/dev/tty", O_RDWR | O_CLOEXEC);
2485+
host_tty.emplace(std::move(default_tty));
2486+
}
2487+
2488+
host_tty->set_raw();
2489+
monitor.enable_io_forwarding(std::move(master), in, out);
2490+
2491+
return host_tty;
26002492
}();
26012493

2494+
monitor.enable_signal_forwarding(std::move(host_tty));
2495+
26022496
runtime_ns::wait_socket_close(socket);
26032497

26042498
{
@@ -2613,35 +2507,7 @@ int linyaps_box::container::run(run_container_options_t options) const
26132507

26142508
// TODO: support detach from the parent's process
26152509
// Now we wait for the container process to exit
2616-
runtime_ns::wait_process_ctx ctx;
2617-
ctx.pid = this->status().PID;
2618-
2619-
if (master) {
2620-
LINYAPS_BOX_DEBUG() << "Container requires a terminal";
2621-
2622-
master->get().set_nonblock(true);
2623-
2624-
ctx.in = utils::file_descriptor{ utils::fileno(stdin), false };
2625-
ctx.in.set_nonblock(true);
2626-
2627-
ctx.out = utils::file_descriptor{ utils::fileno(stdout), false };
2628-
ctx.out.set_nonblock(true);
2629-
2630-
if (utils::isatty(ctx.in)) {
2631-
ctx.host_tty = linyaps_box::terminal_slave{ ctx.in.duplicate() };
2632-
ctx.host_tty->set_raw();
2633-
} else if (utils::isatty(ctx.out)) {
2634-
ctx.host_tty = linyaps_box::terminal_slave{ ctx.out.duplicate() };
2635-
ctx.host_tty->set_raw();
2636-
} else {
2637-
auto default_tty = utils::open("/dev/tty", O_RDWR | O_CLOEXEC);
2638-
ctx.host_tty = linyaps_box::terminal_slave{ std::move(default_tty) };
2639-
}
2640-
}
2641-
2642-
ctx.master = std::move(master);
2643-
2644-
container_process_exit_code = runtime_ns::wait_container_process(std::move(ctx));
2510+
container_process_exit_code = monitor.wait_container_exit();
26452511

26462512
runtime_ns::poststop_hooks(*this);
26472513
} catch (const std::system_error &e) {

0 commit comments

Comments
 (0)