init: fix process restarting

The time data types associated with restarting processes halfway moved
to std::chrono and halfway didn't.  In this intermediate state, the
times would get converted from nanoseconds to seconds then to
milliseconds.  The precision lost when converting to seconds would
cause the main loop of init to spin whenever a process was within a
second of being restarted.

This patch cleans up this logic and uses nanoseconds and milliseconds
explicitly, with a ceiling to milliseconds to prevent unneeded
spinning.

Test: boot bullhead, kill processes, see that they restart sanely.

Change-Id: I0b017ba0e50c09704b0c5cdfcde1dba461804593
This commit is contained in:
Tom Cherry 2017-07-31 13:23:18 -07:00
parent 379123f9ab
commit d269e3a795
3 changed files with 25 additions and 39 deletions

View File

@ -53,6 +53,7 @@
#include <fstream>
#include <memory>
#include <optional>
#include <vector>
#include "bootchart.h"
@ -84,7 +85,6 @@ static int property_triggers_enabled = 0;
static char qemu[32];
std::string default_console = "/dev/console";
static time_t process_needs_restart_at;
const char *ENV[32];
@ -219,12 +219,21 @@ void property_changed(const std::string& name, const std::string& value) {
}
}
static void restart_processes()
{
process_needs_restart_at = 0;
ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
s->RestartIfNeeded(&process_needs_restart_at);
static std::optional<boot_clock::time_point> RestartProcesses() {
std::optional<boot_clock::time_point> next_process_restart_time;
ServiceManager::GetInstance().ForEachService([&next_process_restart_time](Service* s) {
if (!(s->flags() & SVC_RESTARTING)) return;
auto restart_time = s->time_started() + 5s;
if (boot_clock::now() > restart_time) {
s->Start();
} else {
if (!next_process_restart_time || restart_time < *next_process_restart_time) {
next_process_restart_time = restart_time;
}
}
});
return next_process_restart_time;
}
void handle_control_message(const std::string& msg, const std::string& name) {
@ -1175,12 +1184,16 @@ int main(int argc, char** argv) {
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
if (!shutting_down) restart_processes();
if (!shutting_down) {
auto next_process_restart_time = RestartProcesses();
// If there's a process that needs restarting, wake up in time for that.
if (process_needs_restart_at != 0) {
epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
// If there's a process that needs restarting, wake up in time for that.
if (next_process_restart_time) {
epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
*next_process_restart_time - boot_clock::now())
.count();
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
}
// If there's more work to do, wake up again immediately.

View File

@ -890,22 +890,6 @@ void Service::Restart() {
} /* else: Service is restarting anyways. */
}
void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
boot_clock::time_point now = boot_clock::now();
boot_clock::time_point next_start = time_started_ + 5s;
if (now > next_start) {
flags_ &= (~SVC_RESTARTING);
Start();
return;
}
time_t next_start_time_t = time(nullptr) +
time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
*process_needs_restart_at = next_start_time_t;
}
}
// The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART.
void Service::StopOrReset(int how) {
// The service is still SVC_RUNNING until its process exits, but if it has
@ -1123,15 +1107,6 @@ void ServiceManager::ForEachServiceInClass(const std::string& classname,
}
}
void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
void (*func)(Service* svc)) const {
for (const auto& s : services_) {
if (s->flags() & matchflags) {
func(s.get());
}
}
}
void ServiceManager::RemoveService(const Service& svc) {
auto svc_it = std::find_if(services_.begin(), services_.end(),
[&svc] (const std::unique_ptr<Service>& s) {

View File

@ -83,7 +83,6 @@ class Service {
void Stop();
void Terminate();
void Restart();
void RestartIfNeeded(time_t* process_needs_restart_at);
void Reap();
void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
@ -94,6 +93,7 @@ class Service {
const std::set<std::string>& classnames() const { return classnames_; }
unsigned flags() const { return flags_; }
pid_t pid() const { return pid_; }
android::base::boot_clock::time_point time_started() const { return time_started_; }
int crash_count() const { return crash_count_; }
uid_t uid() const { return uid_; }
gid_t gid() const { return gid_; }
@ -217,8 +217,6 @@ class ServiceManager {
void ForEachServiceShutdownOrder(const std::function<void(Service*)>& callback) const;
void ForEachServiceInClass(const std::string& classname,
void (*func)(Service* svc)) const;
void ForEachServiceWithFlags(unsigned matchflags,
void (*func)(Service* svc)) const;
void ReapAnyOutstandingChildren();
void RemoveService(const Service& svc);
void DumpState() const;