15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/service_process_util_posix.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/multi_process_lock.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int g_signal_socket = -1;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempts to take a lock named |name|. If |waiting| is true then this will
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// make multiple attempts to acquire the lock.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Caller is responsible for ownership of the MultiProcessLock.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name));
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lock == NULL) return NULL;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool got_lock = false;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < 10; ++i) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (lock->TryLock()) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      got_lock = true;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!waiting) break;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!got_lock) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lock.reset();
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return lock.release();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& terminate_task)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : terminate_task_(terminate_task) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!terminate_task_.is_null()) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int buffer;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int length = read(fd, &buffer, sizeof(buffer));
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      terminate_task_.Run();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      terminate_task_.Reset();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (length > 0) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(ERROR) << "Unexpected read: " << buffer;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (length == 0) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(ERROR) << "Unexpected fd close";
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (length < 0) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(ERROR) << "read";
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTIMPLEMENTED();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "Forced" Shutdowns on POSIX are done via signals. The magic signal for
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not, but we don't ever expect it to be called.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(dmaclach): add security here to make sure that we are being shut
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //                 down by an appropriate process.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int message = ServiceProcessTerminateMonitor::kTerminateMessage;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (write(g_signal_socket, &message, sizeof(message)) < 0) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DPLOG(ERROR) << "write";
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessState::StateData::StateData() : set_action_(false) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(sockets_, -1, sizeof(sockets_));
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&old_action_, 0, sizeof(old_action_));
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 bool* success) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(g_signal_socket, -1);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!signal->IsSignaled());
89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  *success = base::MessageLoopForIO::current()->WatchFileDescriptor(
90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      sockets_[0],
91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      true,
92a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      base::MessageLoopForIO::WATCH_READ,
93a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      &watcher_,
94a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      terminate_monitor_.get());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!*success) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "WatchFileDescriptor";
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signal->Signal();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_socket = sockets_[1];
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up signal handler for SIGTERM.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct sigaction action;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&action, 0, sizeof(action));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  action.sa_sigaction = SigTermHandler;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sigemptyset(&action.sa_mask);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  action.sa_flags = SA_SIGINFO;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *success = sigaction(SIGTERM, &action, &old_action_) == 0;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!*success) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DPLOG(ERROR) << "sigaction";
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signal->Signal();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the old_action is not default, somebody else has installed a
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a competing handler. Our handler is going to override it so it
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // won't be called. If this occurs it needs to be fixed.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_action_ = true;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *success = WatchExecutable();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!*success) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "WatchExecutable";
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signal->Signal();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initializing_lock_.reset();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_POSIX
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal->Signal();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessState::StateData::~StateData() {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sockets_[0] != -1) {
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IGNORE_EINTR(close(sockets_[0]))) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(ERROR) << "close";
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sockets_[1] != -1) {
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IGNORE_EINTR(close(sockets_[1]))) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(ERROR) << "close";
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (set_action_) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(ERROR) << "sigaction";
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_socket = -1;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessState::CreateState() {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!state_);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = new StateData;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Explicitly adding a reference here (and removing it in TearDownState)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because StateData is refcounted on Mac and Linux so that methods can
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be called on other threads.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is not refcounted on Windows at this time.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_->AddRef();
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ServiceProcessState::SignalReady(
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::MessageLoopProxy* message_loop_proxy,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& terminate_task) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(state_);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) && !defined(OS_MACOSX)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_->running_lock_.reset(TakeServiceRunningLock(true));
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_->running_lock_.get() == NULL) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_->terminate_monitor_.reset(
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ServiceProcessTerminateMonitor(terminate_task));
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pipe(state_->sockets_) < 0) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DPLOG(ERROR) << "pipe";
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WaitableEvent signal_ready(true, false);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_loop_proxy->PostTask(FROM_HERE,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ServiceProcessState::StateData::SignalReady,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 state_,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &signal_ready,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &success));
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal_ready.Wait();
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessState::TearDownState() {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_->Release();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = NULL;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
199