This source file includes following definitions.
- TakeNamedLock
- OnFileCanReadWithoutBlocking
- OnFileCanWriteWithoutBlocking
- SigTermHandler
- SignalReady
- CreateState
- SignalReady
- TearDownState
#include "chrome/common/service_process_util_posix.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/posix/eintr_wrapper.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/common/multi_process_lock.h"
namespace {
int g_signal_socket = -1;
}
MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name));
if (lock == NULL) return NULL;
bool got_lock = false;
for (int i = 0; i < 10; ++i) {
if (lock->TryLock()) {
got_lock = true;
break;
}
if (!waiting) break;
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
}
if (!got_lock) {
lock.reset();
}
return lock.release();
}
ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
const base::Closure& terminate_task)
: terminate_task_(terminate_task) {
}
ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() {
}
void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) {
if (!terminate_task_.is_null()) {
int buffer;
int length = read(fd, &buffer, sizeof(buffer));
if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) {
terminate_task_.Run();
terminate_task_.Reset();
} else if (length > 0) {
DLOG(ERROR) << "Unexpected read: " << buffer;
} else if (length == 0) {
DLOG(ERROR) << "Unexpected fd close";
} else if (length < 0) {
DPLOG(ERROR) << "read";
}
}
}
void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) {
NOTIMPLEMENTED();
}
static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
int message = ServiceProcessTerminateMonitor::kTerminateMessage;
if (write(g_signal_socket, &message, sizeof(message)) < 0) {
DPLOG(ERROR) << "write";
}
}
ServiceProcessState::StateData::StateData() : set_action_(false) {
memset(sockets_, -1, sizeof(sockets_));
memset(&old_action_, 0, sizeof(old_action_));
}
void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
bool* success) {
DCHECK_EQ(g_signal_socket, -1);
DCHECK(!signal->IsSignaled());
*success = base::MessageLoopForIO::current()->WatchFileDescriptor(
sockets_[0],
true,
base::MessageLoopForIO::WATCH_READ,
&watcher_,
terminate_monitor_.get());
if (!*success) {
DLOG(ERROR) << "WatchFileDescriptor";
signal->Signal();
return;
}
g_signal_socket = sockets_[1];
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = SigTermHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
*success = sigaction(SIGTERM, &action, &old_action_) == 0;
if (!*success) {
DPLOG(ERROR) << "sigaction";
signal->Signal();
return;
}
DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
set_action_ = true;
#if defined(OS_MACOSX)
*success = WatchExecutable();
if (!*success) {
DLOG(ERROR) << "WatchExecutable";
signal->Signal();
return;
}
#elif defined(OS_POSIX)
initializing_lock_.reset();
#endif
signal->Signal();
}
ServiceProcessState::StateData::~StateData() {
if (sockets_[0] != -1) {
if (IGNORE_EINTR(close(sockets_[0]))) {
DPLOG(ERROR) << "close";
}
}
if (sockets_[1] != -1) {
if (IGNORE_EINTR(close(sockets_[1]))) {
DPLOG(ERROR) << "close";
}
}
if (set_action_) {
if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
DPLOG(ERROR) << "sigaction";
}
}
g_signal_socket = -1;
}
void ServiceProcessState::CreateState() {
DCHECK(!state_);
state_ = new StateData;
state_->AddRef();
}
bool ServiceProcessState::SignalReady(
base::MessageLoopProxy* message_loop_proxy,
const base::Closure& terminate_task) {
DCHECK(state_);
#if defined(OS_POSIX) && !defined(OS_MACOSX)
state_->running_lock_.reset(TakeServiceRunningLock(true));
if (state_->running_lock_.get() == NULL) {
return false;
}
#endif
state_->terminate_monitor_.reset(
new ServiceProcessTerminateMonitor(terminate_task));
if (pipe(state_->sockets_) < 0) {
DPLOG(ERROR) << "pipe";
return false;
}
base::WaitableEvent signal_ready(true, false);
bool success = false;
message_loop_proxy->PostTask(FROM_HERE,
base::Bind(&ServiceProcessState::StateData::SignalReady,
state_,
&signal_ready,
&success));
signal_ready.Wait();
return success;
}
void ServiceProcessState::TearDownState() {
if (state_) {
state_->Release();
state_ = NULL;
}
}