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/message_loop/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"
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()) {
31 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i
));
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()) {
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
) {
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
,
87 DCHECK_EQ(g_signal_socket
, -1);
88 DCHECK(!signal
->IsSignaled());
89 *success
= base::MessageLoopForIO::current()->WatchFileDescriptor(
92 base::MessageLoopForIO::WATCH_READ
,
94 terminate_monitor
.get());
96 DLOG(ERROR
) << "WatchFileDescriptor";
100 g_signal_socket
= sockets
[1];
102 // Set up signal handler for SIGTERM.
103 struct sigaction action
;
104 memset(&action
, 0, sizeof(action
));
105 action
.sa_sigaction
= SigTermHandler
;
106 sigemptyset(&action
.sa_mask
);
107 action
.sa_flags
= SA_SIGINFO
;
108 *success
= sigaction(SIGTERM
, &action
, &old_action
) == 0;
110 DPLOG(ERROR
) << "sigaction";
115 // If the old_action is not default, somebody else has installed a
116 // a competing handler. Our handler is going to override it so it
117 // won't be called. If this occurs it needs to be fixed.
118 DCHECK_EQ(old_action
.sa_handler
, SIG_DFL
);
121 #if defined(OS_MACOSX)
122 *success
= WatchExecutable();
124 DLOG(ERROR
) << "WatchExecutable";
128 #elif defined(OS_POSIX)
129 initializing_lock
.reset();
134 ServiceProcessState::StateData::~StateData() {
135 if (sockets
[0] != -1) {
136 if (IGNORE_EINTR(close(sockets
[0]))) {
137 DPLOG(ERROR
) << "close";
140 if (sockets
[1] != -1) {
141 if (IGNORE_EINTR(close(sockets
[1]))) {
142 DPLOG(ERROR
) << "close";
146 if (sigaction(SIGTERM
, &old_action
, NULL
) < 0) {
147 DPLOG(ERROR
) << "sigaction";
150 g_signal_socket
= -1;
153 void ServiceProcessState::CreateState() {
155 state_
= new StateData
;
157 // Explicitly adding a reference here (and removing it in TearDownState)
158 // because StateData is refcounted on Mac and Linux so that methods can
159 // be called on other threads.
160 // It is not refcounted on Windows at this time.
164 bool ServiceProcessState::SignalReady(
165 base::MessageLoopProxy
* message_loop_proxy
,
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 message_loop_proxy
->PostTask(FROM_HERE
,
185 base::Bind(&ServiceProcessState::StateData::SignalReady
,
193 void ServiceProcessState::TearDownState() {