blob: a715cd1c34304c399228a139d3d2c8b48cc6a9ea [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "host/commands/cvd/server_command_subprocess_waiter.h"
namespace cuttlefish {
namespace cvd_cmd_impl {
Result<void> SubprocessWaiter::Setup(Subprocess subprocess) {
std::unique_lock interrupt_lock(interruptible_);
if (interrupted_) {
return CF_ERR("Interrupted");
}
if (subprocess_) {
return CF_ERR("Already running");
}
subprocess_ = std::move(subprocess);
return {};
}
Result<siginfo_t> SubprocessWaiter::Wait() {
std::unique_lock interrupt_lock(interruptible_);
if (interrupted_) {
return CF_ERR("Interrupted");
}
CF_EXPECT(subprocess_.has_value());
siginfo_t infop{};
interrupt_lock.unlock();
// This blocks until the process exits, but doesn't reap it.
auto result = subprocess_->Wait(&infop, WEXITED | WNOWAIT);
CF_EXPECT(result != -1, "Lost track of subprocess pid");
interrupt_lock.lock();
// Perform a reaping wait on the process (which should already have exited).
result = subprocess_->Wait(&infop, WEXITED);
CF_EXPECT(result != -1, "Lost track of subprocess pid");
// The double wait avoids a race around the kernel reusing pids. Waiting
// with WNOWAIT won't cause the child process to be reaped, so the kernel
// won't reuse the pid until the Wait call below, and any kill signals won't
// reach unexpected processes.
subprocess_ = {};
return infop;
}
Result<void> SubprocessWaiter::Interrupt() {
std::scoped_lock interrupt_lock(interruptible_);
if (subprocess_) {
auto stop_result = subprocess_->Stop();
switch (stop_result) {
case StopperResult::kStopFailure:
return CF_ERR("Failed to stop subprocess");
case StopperResult::kStopCrash:
return CF_ERR("Stopper caused process to crash");
case StopperResult::kStopSuccess:
return {};
default:
return CF_ERR("Unknown stop result: " << (uint64_t)stop_result);
}
}
return {};
}
} // namespace cvd_cmd_impl
} // namespace cuttlefish