service_process_util_posix.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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/message_loop_proxy.h"
9
10namespace {
11int g_signal_socket = -1;
12}
13
14ServiceProcessShutdownMonitor::ServiceProcessShutdownMonitor(
15    Task* shutdown_task)
16    : shutdown_task_(shutdown_task) {
17}
18
19ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() {
20}
21
22void ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) {
23  if (shutdown_task_.get()) {
24    int buffer;
25    int length = read(fd, &buffer, sizeof(buffer));
26    if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) {
27      shutdown_task_->Run();
28      shutdown_task_.reset();
29    } else if (length > 0) {
30      LOG(ERROR) << "Unexpected read: " << buffer;
31    } else if (length == 0) {
32      LOG(ERROR) << "Unexpected fd close";
33    } else if (length < 0) {
34      PLOG(ERROR) << "read";
35    }
36  }
37}
38
39void ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) {
40  NOTIMPLEMENTED();
41}
42
43// "Forced" Shutdowns on POSIX are done via signals. The magic signal for
44// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
45// not, but we don't ever expect it to be called.
46static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
47  // TODO(dmaclach): add security here to make sure that we are being shut
48  //                 down by an appropriate process.
49  int message = ServiceProcessShutdownMonitor::kShutDownMessage;
50  if (write(g_signal_socket, &message, sizeof(message)) < 0) {
51    PLOG(ERROR) << "write";
52  }
53}
54
55ServiceProcessState::StateData::StateData() {}
56
57void ServiceProcessState::StateData::SignalReady() {
58  CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
59      sockets_[0], true, MessageLoopForIO::WATCH_READ,
60      &watcher_, shut_down_monitor_.get()));
61  g_signal_socket = sockets_[1];
62
63  // Set up signal handler for SIGTERM.
64  struct sigaction action;
65  action.sa_sigaction = SigTermHandler;
66  sigemptyset(&action.sa_mask);
67  action.sa_flags = SA_SIGINFO;
68  if (sigaction(SIGTERM, &action, &old_action_) == 0) {
69    // If the old_action is not default, somebody else has installed a
70    // a competing handler. Our handler is going to override it so it
71    // won't be called. If this occurs it needs to be fixed.
72    DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
73    set_action_ = true;
74#if defined(OS_LINUX)
75    initializing_lock_.reset();
76#endif  // OS_LINUX
77  } else {
78    PLOG(ERROR) << "sigaction";
79  }
80}
81
82ServiceProcessState::StateData::~StateData() {}
83
84bool ServiceProcessState::InitializeState() {
85  CHECK(!state_);
86  state_ = new StateData;
87  state_->AddRef();
88  state_->sockets_[0] = -1;
89  state_->sockets_[1] = -1;
90  state_->set_action_ = false;
91  return true;
92}
93
94bool ServiceProcessState::SignalReady(
95    base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) {
96  CHECK(state_);
97  CHECK_EQ(g_signal_socket, -1);
98
99#if defined(OS_LINUX)
100  state_->running_lock_.reset(TakeServiceRunningLock(true));
101  if (state_->running_lock_.get() == NULL) {
102    return false;
103  }
104#endif // OS_LINUX
105  state_->shut_down_monitor_.reset(
106      new ServiceProcessShutdownMonitor(shutdown_task));
107  if (pipe(state_->sockets_) < 0) {
108    PLOG(ERROR) << "pipe";
109    return false;
110  }
111  message_loop_proxy->PostTask(FROM_HERE,
112      NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady));
113  return true;
114}
115
116void ServiceProcessState::TearDownState() {
117  g_signal_socket = -1;
118  if (state_) {
119    if (state_->sockets_[0] != -1) {
120      close(state_->sockets_[0]);
121    }
122    if (state_->sockets_[1] != -1) {
123      close(state_->sockets_[1]);
124    }
125    if (state_->set_action_) {
126      if (sigaction(SIGTERM, &state_->old_action_, NULL) < 0) {
127        PLOG(ERROR) << "sigaction";
128      }
129    }
130    state_->Release();
131    state_ = NULL;
132  }
133}
134