Extract SIGPIPE ignoring code to a common place.
[chromium-blink-merge.git] / chrome / common / service_process_util_posix.cc
blobe41218fa62daab946acf44c99c722b4890b98749
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/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"
14 namespace {
15 int g_signal_socket = -1;
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;
30 if (!waiting) break;
31 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
33 if (!got_lock) {
34 lock.reset();
36 return lock.release();
39 ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
40 const base::Closure& terminate_task)
41 : terminate_task_(terminate_task) {
44 ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() {
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";
64 void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) {
65 NOTIMPLEMENTED();
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";
80 ServiceProcessState::StateData::StateData() : set_action_(false) {
81 memset(sockets_, -1, sizeof(sockets_));
82 memset(&old_action_, 0, sizeof(old_action_));
85 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
86 bool* success) {
87 DCHECK_EQ(g_signal_socket, -1);
88 DCHECK(!signal->IsSignaled());
89 *success = MessageLoopForIO::current()->WatchFileDescriptor(
90 sockets_[0], true, MessageLoopForIO::WATCH_READ,
91 &watcher_, terminate_monitor_.get());
92 if (!*success) {
93 DLOG(ERROR) << "WatchFileDescriptor";
94 signal->Signal();
95 return;
97 g_signal_socket = sockets_[1];
99 // Set up signal handler for SIGTERM.
100 struct sigaction action;
101 memset(&action, 0, sizeof(action));
102 action.sa_sigaction = SigTermHandler;
103 sigemptyset(&action.sa_mask);
104 action.sa_flags = SA_SIGINFO;
105 *success = sigaction(SIGTERM, &action, &old_action_) == 0;
106 if (!*success) {
107 DPLOG(ERROR) << "sigaction";
108 signal->Signal();
109 return;
112 // If the old_action is not default, somebody else has installed a
113 // a competing handler. Our handler is going to override it so it
114 // won't be called. If this occurs it needs to be fixed.
115 DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
116 set_action_ = true;
118 #if defined(OS_MACOSX)
119 *success = WatchExecutable();
120 if (!*success) {
121 DLOG(ERROR) << "WatchExecutable";
122 signal->Signal();
123 return;
125 #elif defined(OS_POSIX)
126 initializing_lock_.reset();
127 #endif // OS_POSIX
128 signal->Signal();
131 ServiceProcessState::StateData::~StateData() {
132 if (sockets_[0] != -1) {
133 if (HANDLE_EINTR(close(sockets_[0]))) {
134 DPLOG(ERROR) << "close";
137 if (sockets_[1] != -1) {
138 if (HANDLE_EINTR(close(sockets_[1]))) {
139 DPLOG(ERROR) << "close";
142 if (set_action_) {
143 if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
144 DPLOG(ERROR) << "sigaction";
147 g_signal_socket = -1;
150 void ServiceProcessState::CreateState() {
151 DCHECK(!state_);
152 state_ = new StateData;
154 // Explicitly adding a reference here (and removing it in TearDownState)
155 // because StateData is refcounted on Mac and Linux so that methods can
156 // be called on other threads.
157 // It is not refcounted on Windows at this time.
158 state_->AddRef();
161 bool ServiceProcessState::SignalReady(
162 base::MessageLoopProxy* message_loop_proxy,
163 const base::Closure& terminate_task) {
164 DCHECK(state_);
166 #if defined(OS_POSIX) && !defined(OS_MACOSX)
167 state_->running_lock_.reset(TakeServiceRunningLock(true));
168 if (state_->running_lock_.get() == NULL) {
169 return false;
171 #endif
172 state_->terminate_monitor_.reset(
173 new ServiceProcessTerminateMonitor(terminate_task));
174 if (pipe(state_->sockets_) < 0) {
175 DPLOG(ERROR) << "pipe";
176 return false;
178 base::WaitableEvent signal_ready(true, false);
179 bool success = false;
181 message_loop_proxy->PostTask(FROM_HERE,
182 base::Bind(&ServiceProcessState::StateData::SignalReady,
183 state_,
184 &signal_ready,
185 &success));
186 signal_ready.Wait();
187 return success;
190 void ServiceProcessState::TearDownState() {
191 if (state_) {
192 state_->Release();
193 state_ = NULL;