Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2012 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/bind.h"
      9 #include "base/message_loop/message_loop_proxy.h"
     10 #include "base/posix/eintr_wrapper.h"
     11 #include "base/synchronization/waitable_event.h"
     12 #include "chrome/common/multi_process_lock.h"
     13 
     14 namespace {
     15 int g_signal_socket = -1;
     16 }
     17 
     18 // Attempts to take a lock named |name|. If |waiting| is true then this will
     19 // make multiple attempts to acquire the lock.
     20 // Caller is responsible for ownership of the MultiProcessLock.
     21 MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
     22   scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name));
     23   if (lock == NULL) return NULL;
     24   bool got_lock = false;
     25   for (int i = 0; i < 10; ++i) {
     26     if (lock->TryLock()) {
     27       got_lock = true;
     28       break;
     29     }
     30     if (!waiting) break;
     31     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
     32   }
     33   if (!got_lock) {
     34     lock.reset();
     35   }
     36   return lock.release();
     37 }
     38 
     39 ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
     40     const base::Closure& terminate_task)
     41     : terminate_task_(terminate_task) {
     42 }
     43 
     44 ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() {
     45 }
     46 
     47 void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) {
     48   if (!terminate_task_.is_null()) {
     49     int buffer;
     50     int length = read(fd, &buffer, sizeof(buffer));
     51     if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) {
     52       terminate_task_.Run();
     53       terminate_task_.Reset();
     54     } else if (length > 0) {
     55       DLOG(ERROR) << "Unexpected read: " << buffer;
     56     } else if (length == 0) {
     57       DLOG(ERROR) << "Unexpected fd close";
     58     } else if (length < 0) {
     59       DPLOG(ERROR) << "read";
     60     }
     61   }
     62 }
     63 
     64 void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) {
     65   NOTIMPLEMENTED();
     66 }
     67 
     68 // "Forced" Shutdowns on POSIX are done via signals. The magic signal for
     69 // a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
     70 // not, but we don't ever expect it to be called.
     71 static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
     72   // TODO(dmaclach): add security here to make sure that we are being shut
     73   //                 down by an appropriate process.
     74   int message = ServiceProcessTerminateMonitor::kTerminateMessage;
     75   if (write(g_signal_socket, &message, sizeof(message)) < 0) {
     76     DPLOG(ERROR) << "write";
     77   }
     78 }
     79 
     80 ServiceProcessState::StateData::StateData() : set_action_(false) {
     81   memset(sockets_, -1, sizeof(sockets_));
     82   memset(&old_action_, 0, sizeof(old_action_));
     83 }
     84 
     85 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
     86                                                  bool* success) {
     87   DCHECK_EQ(g_signal_socket, -1);
     88   DCHECK(!signal->IsSignaled());
     89   *success = base::MessageLoopForIO::current()->WatchFileDescriptor(
     90       sockets_[0],
     91       true,
     92       base::MessageLoopForIO::WATCH_READ,
     93       &watcher_,
     94       terminate_monitor_.get());
     95   if (!*success) {
     96     DLOG(ERROR) << "WatchFileDescriptor";
     97     signal->Signal();
     98     return;
     99   }
    100   g_signal_socket = sockets_[1];
    101 
    102   // Set up signal handler for SIGTERM.
    103   struct sigaction action;
    104   memset(&action, 0, sizeof(action));
    105   action.sa_sigaction = SigTermHandler;
    106   sigemptyset(&action.sa_mask);
    107   action.sa_flags = SA_SIGINFO;
    108   *success = sigaction(SIGTERM, &action, &old_action_) == 0;
    109   if (!*success) {
    110     DPLOG(ERROR) << "sigaction";
    111     signal->Signal();
    112     return;
    113   }
    114 
    115   // If the old_action is not default, somebody else has installed a
    116   // a competing handler. Our handler is going to override it so it
    117   // won't be called. If this occurs it needs to be fixed.
    118   DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
    119   set_action_ = true;
    120 
    121 #if defined(OS_MACOSX)
    122   *success = WatchExecutable();
    123   if (!*success) {
    124     DLOG(ERROR) << "WatchExecutable";
    125     signal->Signal();
    126     return;
    127   }
    128 #elif defined(OS_POSIX)
    129   initializing_lock_.reset();
    130 #endif  // OS_POSIX
    131   signal->Signal();
    132 }
    133 
    134 ServiceProcessState::StateData::~StateData() {
    135   if (sockets_[0] != -1) {
    136     if (IGNORE_EINTR(close(sockets_[0]))) {
    137       DPLOG(ERROR) << "close";
    138     }
    139   }
    140   if (sockets_[1] != -1) {
    141     if (IGNORE_EINTR(close(sockets_[1]))) {
    142       DPLOG(ERROR) << "close";
    143     }
    144   }
    145   if (set_action_) {
    146     if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
    147       DPLOG(ERROR) << "sigaction";
    148     }
    149   }
    150   g_signal_socket = -1;
    151 }
    152 
    153 void ServiceProcessState::CreateState() {
    154   DCHECK(!state_);
    155   state_ = new StateData;
    156 
    157   // Explicitly adding a reference here (and removing it in TearDownState)
    158   // because StateData is refcounted on Mac and Linux so that methods can
    159   // be called on other threads.
    160   // It is not refcounted on Windows at this time.
    161   state_->AddRef();
    162 }
    163 
    164 bool ServiceProcessState::SignalReady(
    165     base::MessageLoopProxy* message_loop_proxy,
    166     const base::Closure& terminate_task) {
    167   DCHECK(state_);
    168 
    169 #if defined(OS_POSIX) && !defined(OS_MACOSX)
    170   state_->running_lock_.reset(TakeServiceRunningLock(true));
    171   if (state_->running_lock_.get() == NULL) {
    172     return false;
    173   }
    174 #endif
    175   state_->terminate_monitor_.reset(
    176       new ServiceProcessTerminateMonitor(terminate_task));
    177   if (pipe(state_->sockets_) < 0) {
    178     DPLOG(ERROR) << "pipe";
    179     return false;
    180   }
    181   base::WaitableEvent signal_ready(true, false);
    182   bool success = false;
    183 
    184   message_loop_proxy->PostTask(FROM_HERE,
    185       base::Bind(&ServiceProcessState::StateData::SignalReady,
    186                  state_,
    187                  &signal_ready,
    188                  &success));
    189   signal_ready.Wait();
    190   return success;
    191 }
    192 
    193 void ServiceProcessState::TearDownState() {
    194   if (state_) {
    195     state_->Release();
    196     state_ = NULL;
    197   }
    198 }
    199