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"
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"
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()) {
32 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i
));
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()) {
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
) {
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
,
88 DCHECK_EQ(g_signal_socket
, -1);
89 DCHECK(!signal
->IsSignaled());
90 *success
= base::MessageLoopForIO::current()->WatchFileDescriptor(
93 base::MessageLoopForIO::WATCH_READ
,
95 terminate_monitor
.get());
97 DLOG(ERROR
) << "WatchFileDescriptor";
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;
111 DPLOG(ERROR
) << "sigaction";
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
);
122 #if defined(OS_MACOSX)
123 *success
= WatchExecutable();
125 DLOG(ERROR
) << "WatchExecutable";
129 #elif defined(OS_POSIX)
130 initializing_lock
.reset();
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";
147 if (sigaction(SIGTERM
, &old_action
, NULL
) < 0) {
148 DPLOG(ERROR
) << "sigaction";
151 g_signal_socket
= -1;
154 void ServiceProcessState::CreateState() {
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.
165 bool ServiceProcessState::SignalReady(base::SingleThreadTaskRunner
* task_runner
,
166 const base::Closure
& terminate_task
) {
169 #if defined(OS_POSIX) && !defined(OS_MACOSX)
170 state_
->running_lock
.reset(TakeServiceRunningLock(true));
171 if (state_
->running_lock
.get() == NULL
) {
175 state_
->terminate_monitor
.reset(
176 new ServiceProcessTerminateMonitor(terminate_task
));
177 if (pipe(state_
->sockets
) < 0) {
178 DPLOG(ERROR
) << "pipe";
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
));
191 void ServiceProcessState::TearDownState() {