Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / service_process_util_posix.cc
blob9ec327c3dd29fd8da84f8e32620ff1340d164793
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.
5 #include "chrome/common/service_process_util_posix.h"
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/location.h"
10 #include "base/posix/eintr_wrapper.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "chrome/common/multi_process_lock.h"
15 namespace {
16 int g_signal_socket = -1;
19 // Attempts to take a lock named |name|. If |waiting| is true then this will
20 // make multiple attempts to acquire the lock.
21 // Caller is responsible for ownership of the MultiProcessLock.
22 MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
23 scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name));
24 if (lock == NULL) return NULL;
25 bool got_lock = false;
26 for (int i = 0; i < 10; ++i) {
27 if (lock->TryLock()) {
28 got_lock = true;
29 break;
31 if (!waiting) break;
32 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
34 if (!got_lock) {
35 lock.reset();
37 return lock.release();
40 ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
41 const base::Closure& terminate_task)
42 : terminate_task_(terminate_task) {
45 ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() {
48 void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) {
49 if (!terminate_task_.is_null()) {
50 int buffer;
51 int length = read(fd, &buffer, sizeof(buffer));
52 if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) {
53 terminate_task_.Run();
54 terminate_task_.Reset();
55 } else if (length > 0) {
56 DLOG(ERROR) << "Unexpected read: " << buffer;
57 } else if (length == 0) {
58 DLOG(ERROR) << "Unexpected fd close";
59 } else if (length < 0) {
60 DPLOG(ERROR) << "read";
65 void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) {
66 NOTIMPLEMENTED();
69 // "Forced" Shutdowns on POSIX are done via signals. The magic signal for
70 // a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
71 // not, but we don't ever expect it to be called.
72 static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
73 // TODO(dmaclach): add security here to make sure that we are being shut
74 // down by an appropriate process.
75 int message = ServiceProcessTerminateMonitor::kTerminateMessage;
76 if (write(g_signal_socket, &message, sizeof(message)) < 0) {
77 DPLOG(ERROR) << "write";
81 ServiceProcessState::StateData::StateData() : set_action(false) {
82 memset(sockets, -1, sizeof(sockets));
83 memset(&old_action, 0, sizeof(old_action));
86 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
87 bool* success) {
88 DCHECK_EQ(g_signal_socket, -1);
89 DCHECK(!signal->IsSignaled());
90 *success = base::MessageLoopForIO::current()->WatchFileDescriptor(
91 sockets[0],
92 true,
93 base::MessageLoopForIO::WATCH_READ,
94 &watcher,
95 terminate_monitor.get());
96 if (!*success) {
97 DLOG(ERROR) << "WatchFileDescriptor";
98 signal->Signal();
99 return;
101 g_signal_socket = sockets[1];
103 // Set up signal handler for SIGTERM.
104 struct sigaction action;
105 memset(&action, 0, sizeof(action));
106 action.sa_sigaction = SigTermHandler;
107 sigemptyset(&action.sa_mask);
108 action.sa_flags = SA_SIGINFO;
109 *success = sigaction(SIGTERM, &action, &old_action) == 0;
110 if (!*success) {
111 DPLOG(ERROR) << "sigaction";
112 signal->Signal();
113 return;
116 // If the old_action is not default, somebody else has installed a
117 // a competing handler. Our handler is going to override it so it
118 // won't be called. If this occurs it needs to be fixed.
119 DCHECK_EQ(old_action.sa_handler, SIG_DFL);
120 set_action = true;
122 #if defined(OS_MACOSX)
123 *success = WatchExecutable();
124 if (!*success) {
125 DLOG(ERROR) << "WatchExecutable";
126 signal->Signal();
127 return;
129 #elif defined(OS_POSIX)
130 initializing_lock.reset();
131 #endif // OS_POSIX
132 signal->Signal();
135 ServiceProcessState::StateData::~StateData() {
136 if (sockets[0] != -1) {
137 if (IGNORE_EINTR(close(sockets[0]))) {
138 DPLOG(ERROR) << "close";
141 if (sockets[1] != -1) {
142 if (IGNORE_EINTR(close(sockets[1]))) {
143 DPLOG(ERROR) << "close";
146 if (set_action) {
147 if (sigaction(SIGTERM, &old_action, NULL) < 0) {
148 DPLOG(ERROR) << "sigaction";
151 g_signal_socket = -1;
154 void ServiceProcessState::CreateState() {
155 DCHECK(!state_);
156 state_ = new StateData;
158 // Explicitly adding a reference here (and removing it in TearDownState)
159 // because StateData is refcounted on Mac and Linux so that methods can
160 // be called on other threads.
161 // It is not refcounted on Windows at this time.
162 state_->AddRef();
165 bool ServiceProcessState::SignalReady(base::SingleThreadTaskRunner* task_runner,
166 const base::Closure& terminate_task) {
167 DCHECK(state_);
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;
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;
181 base::WaitableEvent signal_ready(true, false);
182 bool success = false;
184 task_runner->PostTask(FROM_HERE,
185 base::Bind(&ServiceProcessState::StateData::SignalReady,
186 state_, &signal_ready, &success));
187 signal_ready.Wait();
188 return success;
191 void ServiceProcessState::TearDownState() {
192 if (state_) {
193 state_->Release();
194 state_ = NULL;