blob: 74f6eb50667cbe27ac9457a6c6e1915599cfb868 [file] [log] [blame]
// Copyright 2012 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "watchdog.h"
#ifndef _WIN32
#include <unistd.h>
#endif
#include "callback.h"
#include "compiler_specific.h"
#include "compile_service.h"
#include "glog/logging.h"
#include "glog/stl_logging.h"
#include "ioutil.h"
#include "mypath.h"
#include "path.h"
#include "threadpool_http_server.h"
#include "util.h"
#ifdef _WIN32
#include "posix_helper_win.h"
#endif
namespace devtools_goma {
#ifndef _WIN32
static const char *kGomaccName = "gomacc";
#else
static const char *kGomaccName = "gomacc.exe";
#endif
Watchdog::Watchdog()
: dir_(GetMyDirectory()),
gomacc_path_(file::JoinPath(dir_, kGomaccName)),
server_(nullptr),
idle_counter_(0),
service_(nullptr),
closure_id_(ThreadpoolHttpServer::kInvalidClosureId) {
}
Watchdog::~Watchdog() {
LOG(INFO) << "stop watchdog";
if (server_ && closure_id_ != ThreadpoolHttpServer::kInvalidClosureId) {
server_->UnregisterIdleClosure(closure_id_);
closure_id_ = ThreadpoolHttpServer::kInvalidClosureId;
}
server_ = nullptr;
service_ = nullptr;
}
void Watchdog::Start(ThreadpoolHttpServer* server, int count) {
LOG(INFO) << "start watchdog in " << count << " idle count.";
server_ = server;
idle_counter_ = count;
std::unique_ptr<PermanentClosure> closure(
NewPermanentCallback(this, &Watchdog::Check));
closure_id_ = server_->RegisterIdleClosure(
ThreadpoolHttpServer::SOCKET_IPC, count,
std::move(closure));
}
void Watchdog::SetTarget(CompileService* service,
const std::vector<string>& goma_ipc_env) {
service_ = service;
goma_ipc_env_ = goma_ipc_env;
LOG(INFO) << "watchdog target:" << goma_ipc_env;
}
void Watchdog::Check() {
if (server_ == nullptr || service_ == nullptr) {
LOG(ERROR) << "watchdog: no server or service.";
return;
}
int last_idle_counter =
server_->idle_counter(ThreadpoolHttpServer::SOCKET_IPC);
if (last_idle_counter < idle_counter_) {
LOG(WARNING) << "not idle:" << last_idle_counter << " < " << idle_counter_;
return;
}
// Watchdog runs "gomacc port", which will call /portz, but we don't want
// to make server as active by this request.
// Keep idle while it's checking port via goma ipc.
server_->SuspendIdleCounter();
if (access(gomacc_path_.c_str(), X_OK) != 0) {
LOG(INFO) << "gomacc:" << gomacc_path_ << " not found";
service_->Quit();
return;
}
std::vector<string> argv;
argv.push_back(gomacc_path_);
argv.push_back("port");
std::vector<string> env(goma_ipc_env_);
int32_t status = 0;
const string out = ReadCommandOutput(gomacc_path_, argv, env, dir_,
MERGE_STDOUT_STDERR, &status);
if (status != 0) {
LOG(ERROR) << "ReadCommandOutput gets non-zero exit code. Going to quit."
<< " gomacc_path=" << gomacc_path_
<< " status=" << status
<< " cwd=" << dir_;
service_->Quit();
return;
}
int port = atoi(out.c_str());
if (port != server_->port()) {
LOG(INFO) << "gomacc port:" << port << " not match with"
<< " my port:" << server_->port()
<< " gomacc-out:" << out;
service_->Quit();
return;
}
LOG(INFO) << "gomacc port match with my port:" << port;
server_->ResumeIdleCounter();
FlushLogFiles();
}
} // namespace devtools_goma