Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/common/service_process_util_posix.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/eintr_wrapper.h"
      9 #include "base/message_loop_proxy.h"
     10 #include "base/synchronization/waitable_event.h"
     11 
     12 namespace {
     13 int g_signal_socket = -1;
     14 }
     15 
     16 ServiceProcessShutdownMonitor::ServiceProcessShutdownMonitor(
     17     Task* shutdown_task)
     18     : shutdown_task_(shutdown_task) {
     19 }
     20 
     21 ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() {
     22 }
     23 
     24 void ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) {
     25   if (shutdown_task_.get()) {
     26     int buffer;
     27     int length = read(fd, &buffer, sizeof(buffer));
     28     if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) {
     29       shutdown_task_->Run();
     30       shutdown_task_.reset();
     31     } else if (length > 0) {
     32       LOG(ERROR) << "Unexpected read: " << buffer;
     33     } else if (length == 0) {
     34       LOG(ERROR) << "Unexpected fd close";
     35     } else if (length < 0) {
     36       PLOG(ERROR) << "read";
     37     }
     38   }
     39 }
     40 
     41 void ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) {
     42   NOTIMPLEMENTED();
     43 }
     44 
     45 // "Forced" Shutdowns on POSIX are done via signals. The magic signal for
     46 // a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
     47 // not, but we don't ever expect it to be called.
     48 static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
     49   // TODO(dmaclach): add security here to make sure that we are being shut
     50   //                 down by an appropriate process.
     51   int message = ServiceProcessShutdownMonitor::kShutDownMessage;
     52   if (write(g_signal_socket, &message, sizeof(message)) < 0) {
     53     PLOG(ERROR) << "write";
     54   }
     55 }
     56 
     57 ServiceProcessState::StateData::StateData() : set_action_(false) {
     58   memset(sockets_, -1, sizeof(sockets_));
     59   memset(&old_action_, 0, sizeof(old_action_));
     60 }
     61 
     62 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
     63                                                  bool* success) {
     64   CHECK_EQ(g_signal_socket, -1);
     65   CHECK(!signal->IsSignaled());
     66    *success = MessageLoopForIO::current()->WatchFileDescriptor(
     67       sockets_[0], true, MessageLoopForIO::WATCH_READ,
     68       &watcher_, shut_down_monitor_.get());
     69   if (!*success) {
     70     LOG(ERROR) << "WatchFileDescriptor";
     71     signal->Signal();
     72     return;
     73   }
     74   g_signal_socket = sockets_[1];
     75 
     76   // Set up signal handler for SIGTERM.
     77   struct sigaction action;
     78   action.sa_sigaction = SigTermHandler;
     79   sigemptyset(&action.sa_mask);
     80   action.sa_flags = SA_SIGINFO;
     81   *success = sigaction(SIGTERM, &action, &old_action_) == 0;
     82   if (!*success) {
     83     PLOG(ERROR) << "sigaction";
     84     signal->Signal();
     85     return;
     86   }
     87 
     88   // If the old_action is not default, somebody else has installed a
     89   // a competing handler. Our handler is going to override it so it
     90   // won't be called. If this occurs it needs to be fixed.
     91   DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
     92   set_action_ = true;
     93 
     94 #if defined(OS_LINUX)
     95   initializing_lock_.reset();
     96 #endif  // OS_LINUX
     97 #if defined(OS_MACOSX)
     98   *success = WatchExecutable();
     99   if (!*success) {
    100     LOG(ERROR) << "WatchExecutable";
    101     signal->Signal();
    102     return;
    103   }
    104 #endif  // OS_MACOSX
    105   signal->Signal();
    106 }
    107 
    108 ServiceProcessState::StateData::~StateData() {
    109   if (sockets_[0] != -1) {
    110     if (HANDLE_EINTR(close(sockets_[0]))) {
    111       PLOG(ERROR) << "close";
    112     }
    113   }
    114   if (sockets_[1] != -1) {
    115     if (HANDLE_EINTR(close(sockets_[1]))) {
    116       PLOG(ERROR) << "close";
    117     }
    118   }
    119   if (set_action_) {
    120     if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
    121       PLOG(ERROR) << "sigaction";
    122     }
    123   }
    124   g_signal_socket = -1;
    125 }
    126 
    127 void ServiceProcessState::CreateState() {
    128   CHECK(!state_);
    129   state_ = new StateData;
    130 
    131   // Explicitly adding a reference here (and removing it in TearDownState)
    132   // because StateData is refcounted on Mac and Linux so that methods can
    133   // be called on other threads.
    134   // It is not refcounted on Windows at this time.
    135   state_->AddRef();
    136 }
    137 
    138 bool ServiceProcessState::SignalReady(
    139     base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) {
    140   CHECK(state_);
    141 
    142   scoped_ptr<Task> scoped_shutdown_task(shutdown_task);
    143 #if defined(OS_LINUX)
    144   state_->running_lock_.reset(TakeServiceRunningLock(true));
    145   if (state_->running_lock_.get() == NULL) {
    146     return false;
    147   }
    148 #endif // OS_LINUX
    149   state_->shut_down_monitor_.reset(
    150       new ServiceProcessShutdownMonitor(scoped_shutdown_task.release()));
    151   if (pipe(state_->sockets_) < 0) {
    152     PLOG(ERROR) << "pipe";
    153     return false;
    154   }
    155   base::WaitableEvent signal_ready(true, false);
    156   bool success = false;
    157 
    158   message_loop_proxy->PostTask(FROM_HERE,
    159       NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady,
    160                         &signal_ready,
    161                         &success));
    162   signal_ready.Wait();
    163   return success;
    164 }
    165 
    166 void ServiceProcessState::TearDownState() {
    167   if (state_) {
    168     state_->Release();
    169     state_ = NULL;
    170   }
    171 }
    172