Merge changes I5e259fdd,I5b9ab456 into main
* changes: init: Make WaitToBeReaped() wait less long init: Create different file descriptors for SIGCHLD and SIGTERM
This commit is contained in:
commit
7d1f582d36
7 changed files with 66 additions and 12 deletions
|
@ -108,6 +108,7 @@ using android::base::SetProperty;
|
|||
using android::base::StringPrintf;
|
||||
using android::base::Timer;
|
||||
using android::base::Trim;
|
||||
using android::base::unique_fd;
|
||||
using android::fs_mgr::AvbHandle;
|
||||
using android::snapshot::SnapshotManager;
|
||||
|
||||
|
@ -116,7 +117,8 @@ namespace init {
|
|||
|
||||
static int property_triggers_enabled = 0;
|
||||
|
||||
static int signal_fd = -1;
|
||||
int sigchld_fd = -1;
|
||||
static int sigterm_fd = -1;
|
||||
static int property_fd = -1;
|
||||
|
||||
struct PendingControlMessage {
|
||||
|
@ -713,8 +715,9 @@ static void HandleSigtermSignal(const signalfd_siginfo& siginfo) {
|
|||
HandlePowerctlMessage("shutdown,container");
|
||||
}
|
||||
|
||||
static void HandleSignalFd() {
|
||||
static void HandleSignalFd(int signal) {
|
||||
signalfd_siginfo siginfo;
|
||||
const int signal_fd = signal == SIGCHLD ? sigchld_fd : sigterm_fd;
|
||||
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
|
||||
if (bytes_read != sizeof(siginfo)) {
|
||||
PLOG(ERROR) << "Failed to read siginfo from signal_fd";
|
||||
|
@ -748,6 +751,24 @@ static void UnblockSignals() {
|
|||
}
|
||||
}
|
||||
|
||||
static Result<int> CreateAndRegisterSignalFd(Epoll* epoll, int signal) {
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signal);
|
||||
unique_fd signal_fd(signalfd(-1, &mask, SFD_CLOEXEC));
|
||||
if (signal_fd == -1) {
|
||||
return ErrnoError() << "failed to create signalfd for signal " << signal;
|
||||
}
|
||||
|
||||
auto result = epoll->RegisterHandler(
|
||||
signal_fd.get(), [signal]() { HandleSignalFd(signal); }, EPOLLIN | EPOLLPRI);
|
||||
if (!result.ok()) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
return signal_fd.release();
|
||||
}
|
||||
|
||||
static void InstallSignalFdHandler(Epoll* epoll) {
|
||||
// Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving
|
||||
// SIGCHLD when a child process stops or continues (b/77867680#comment9).
|
||||
|
@ -774,14 +795,19 @@ static void InstallSignalFdHandler(Epoll* epoll) {
|
|||
LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
|
||||
}
|
||||
|
||||
signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
|
||||
if (signal_fd == -1) {
|
||||
PLOG(FATAL) << "failed to create signalfd";
|
||||
Result<int> cs_result = CreateAndRegisterSignalFd(epoll, SIGCHLD);
|
||||
if (!cs_result.ok()) {
|
||||
PLOG(FATAL) << cs_result.error();
|
||||
}
|
||||
sigchld_fd = cs_result.value();
|
||||
Service::SetSigchldFd(sigchld_fd);
|
||||
|
||||
constexpr int flags = EPOLLIN | EPOLLPRI;
|
||||
if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd, flags); !result.ok()) {
|
||||
LOG(FATAL) << result.error();
|
||||
if (sigismember(&mask, SIGTERM)) {
|
||||
Result<int> cs_result = CreateAndRegisterSignalFd(epoll, SIGTERM);
|
||||
if (!cs_result.ok()) {
|
||||
PLOG(FATAL) << cs_result.error();
|
||||
}
|
||||
sigterm_fd = cs_result.value();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
extern int sigchld_fd;
|
||||
|
||||
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
|
||||
Parser CreateApexConfigParser(ActionManager& action_manager, ServiceList& service_list);
|
||||
|
||||
|
|
|
@ -563,7 +563,7 @@ static void StopServices(const std::set<std::string>& services, std::chrono::mil
|
|||
}
|
||||
}
|
||||
if (timeout > 0ms) {
|
||||
WaitToBeReaped(pids, timeout);
|
||||
WaitToBeReaped(sigchld_fd, pids, timeout);
|
||||
} else {
|
||||
// Even if we don't to wait for services to stop, we still optimistically reap zombies.
|
||||
ReapAnyOutstandingChildren();
|
||||
|
|
|
@ -136,6 +136,7 @@ static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigsto
|
|||
|
||||
unsigned long Service::next_start_order_ = 1;
|
||||
bool Service::is_exec_service_running_ = false;
|
||||
int Service::sigchld_fd_ = -1;
|
||||
|
||||
Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
|
||||
const std::string& filename, const std::vector<std::string>& args)
|
||||
|
|
|
@ -156,6 +156,7 @@ class Service {
|
|||
const Subcontext* subcontext() const { return subcontext_; }
|
||||
const std::string& filename() const { return filename_; }
|
||||
void set_filename(const std::string& name) { filename_ = name; }
|
||||
static void SetSigchldFd(int sigchld_fd) { sigchld_fd_ = sigchld_fd; }
|
||||
|
||||
private:
|
||||
void NotifyStateChange(const std::string& new_state) const;
|
||||
|
@ -168,8 +169,10 @@ class Service {
|
|||
void RunService(const std::vector<Descriptor>& descriptors, InterprocessFifo cgroups_activated,
|
||||
InterprocessFifo setsid_finished);
|
||||
void SetMountNamespace();
|
||||
|
||||
static unsigned long next_start_order_;
|
||||
static bool is_exec_service_running_;
|
||||
static int sigchld_fd_;
|
||||
|
||||
const std::string name_;
|
||||
std::set<std::string> classnames_;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
@ -31,6 +32,7 @@
|
|||
|
||||
#include <thread>
|
||||
|
||||
#include "epoll.h"
|
||||
#include "init.h"
|
||||
#include "service.h"
|
||||
#include "service_list.h"
|
||||
|
@ -121,8 +123,23 @@ void ReapAnyOutstandingChildren() {
|
|||
}
|
||||
}
|
||||
|
||||
void WaitToBeReaped(const std::vector<pid_t>& pids, std::chrono::milliseconds timeout) {
|
||||
static void DiscardSiginfo(int signal_fd) {
|
||||
signalfd_siginfo siginfo;
|
||||
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
|
||||
if (bytes_read != sizeof(siginfo)) {
|
||||
LOG(WARNING) << "Unexpected: " << __func__ << " read " << bytes_read << " bytes instead of "
|
||||
<< sizeof(siginfo);
|
||||
}
|
||||
}
|
||||
|
||||
void WaitToBeReaped(int sigchld_fd, const std::vector<pid_t>& pids,
|
||||
std::chrono::milliseconds timeout) {
|
||||
Timer t;
|
||||
Epoll epoll;
|
||||
// The init process passes a valid sigchld_fd argument but unit tests do not.
|
||||
if (sigchld_fd >= 0) {
|
||||
epoll.RegisterHandler(sigchld_fd, [sigchld_fd]() { DiscardSiginfo(sigchld_fd); });
|
||||
}
|
||||
std::vector<pid_t> alive_pids(pids.begin(), pids.end());
|
||||
while (!alive_pids.empty() && t.duration() < timeout) {
|
||||
pid_t pid;
|
||||
|
@ -135,7 +152,11 @@ void WaitToBeReaped(const std::vector<pid_t>& pids, std::chrono::milliseconds ti
|
|||
if (alive_pids.empty()) {
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(50ms);
|
||||
if (sigchld_fd >= 0) {
|
||||
epoll.Wait(std::max(timeout - t.duration(), 0ms));
|
||||
} else {
|
||||
std::this_thread::sleep_for(50ms);
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "Waiting for " << pids.size() << " pids to be reaped took " << t << " with "
|
||||
<< alive_pids.size() << " of them still running";
|
||||
|
|
|
@ -25,7 +25,8 @@ namespace init {
|
|||
|
||||
void ReapAnyOutstandingChildren();
|
||||
|
||||
void WaitToBeReaped(const std::vector<pid_t>& pids, std::chrono::milliseconds timeout);
|
||||
void WaitToBeReaped(int sigchld_fd, const std::vector<pid_t>& pids,
|
||||
std::chrono::milliseconds timeout);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
Loading…
Reference in a new issue