1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Use of this source code is governed by a BSD-style license that can be
3731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// found in the LICENSE file.
4731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/common/service_process_util_posix.h"
6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/basictypes.h"
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/eintr_wrapper.h"
972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/message_loop_proxy.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/synchronization/waitable_event.h"
11731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace {
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint g_signal_socket = -1;
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
16dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenServiceProcessShutdownMonitor::ServiceProcessShutdownMonitor(
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    Task* shutdown_task)
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : shutdown_task_(shutdown_task) {
19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() {
2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) {
2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (shutdown_task_.get()) {
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int buffer;
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int length = read(fd, &buffer, sizeof(buffer));
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) {
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      shutdown_task_->Run();
3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      shutdown_task_.reset();
3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (length > 0) {
3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LOG(ERROR) << "Unexpected read: " << buffer;
3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (length == 0) {
3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LOG(ERROR) << "Unexpected fd close";
3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (length < 0) {
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      PLOG(ERROR) << "read";
3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) {
42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  NOTIMPLEMENTED();
4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// "Forced" Shutdowns on POSIX are done via signals. The magic signal for
4672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// not, but we don't ever expect it to be called.
4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic void SigTermHandler(int sig, siginfo_t* info, void* uap) {
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // TODO(dmaclach): add security here to make sure that we are being shut
5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  //                 down by an appropriate process.
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int message = ServiceProcessShutdownMonitor::kShutDownMessage;
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (write(g_signal_socket, &message, sizeof(message)) < 0) {
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    PLOG(ERROR) << "write";
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenServiceProcessState::StateData::StateData() : set_action_(false) {
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  memset(sockets_, -1, sizeof(sockets_));
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  memset(&old_action_, 0, sizeof(old_action_));
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                 bool* success) {
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK_EQ(g_signal_socket, -1);
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(!signal->IsSignaled());
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *success = MessageLoopForIO::current()->WatchFileDescriptor(
67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      sockets_[0], true, MessageLoopForIO::WATCH_READ,
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &watcher_, shut_down_monitor_.get());
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!*success) {
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(ERROR) << "WatchFileDescriptor";
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    signal->Signal();
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
74dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  g_signal_socket = sockets_[1];
75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Set up signal handler for SIGTERM.
77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  struct sigaction action;
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  action.sa_sigaction = SigTermHandler;
79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  sigemptyset(&action.sa_mask);
80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  action.sa_flags = SA_SIGINFO;
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *success = sigaction(SIGTERM, &action, &old_action_) == 0;
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!*success) {
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PLOG(ERROR) << "sigaction";
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    signal->Signal();
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If the old_action is not default, somebody else has installed a
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // a competing handler. Our handler is going to override it so it
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // won't be called. If this occurs it needs to be fixed.
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  set_action_ = true;
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_LINUX)
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  initializing_lock_.reset();
96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif  // OS_LINUX
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_MACOSX)
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *success = WatchExecutable();
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!*success) {
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(ERROR) << "WatchExecutable";
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    signal->Signal();
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif  // OS_MACOSX
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  signal->Signal();
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenServiceProcessState::StateData::~StateData() {
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (sockets_[0] != -1) {
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (HANDLE_EINTR(close(sockets_[0]))) {
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      PLOG(ERROR) << "close";
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (sockets_[1] != -1) {
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (HANDLE_EINTR(close(sockets_[1]))) {
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      PLOG(ERROR) << "close";
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (set_action_) {
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      PLOG(ERROR) << "sigaction";
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  g_signal_socket = -1;
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ServiceProcessState::CreateState() {
12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CHECK(!state_);
12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  state_ = new StateData;
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Explicitly adding a reference here (and removing it in TearDownState)
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // because StateData is refcounted on Mac and Linux so that methods can
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // be called on other threads.
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // It is not refcounted on Windows at this time.
13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  state_->AddRef();
13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool ServiceProcessState::SignalReady(
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) {
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CHECK(state_);
14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<Task> scoped_shutdown_task(shutdown_task);
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_LINUX)
14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  state_->running_lock_.reset(TakeServiceRunningLock(true));
14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (state_->running_lock_.get() == NULL) {
14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif // OS_LINUX
14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  state_->shut_down_monitor_.reset(
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      new ServiceProcessShutdownMonitor(scoped_shutdown_task.release()));
15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (pipe(state_->sockets_) < 0) {
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    PLOG(ERROR) << "pipe";
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::WaitableEvent signal_ready(true, false);
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool success = false;
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  message_loop_proxy->PostTask(FROM_HERE,
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady,
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        &signal_ready,
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        &success));
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  signal_ready.Wait();
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return success;
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ServiceProcessState::TearDownState() {
16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (state_) {
16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    state_->Release();
16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    state_ = NULL;
17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
172