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_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
= MessageLoopForIO::current()->WatchFileDescriptor(
90 sockets_
[0], true, MessageLoopForIO::WATCH_READ
,
91 &watcher_
, terminate_monitor_
.get());
93 DLOG(ERROR
) << "WatchFileDescriptor";
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;
107 DPLOG(ERROR
) << "sigaction";
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
);
118 #if defined(OS_MACOSX)
119 *success
= WatchExecutable();
121 DLOG(ERROR
) << "WatchExecutable";
125 #elif defined(OS_POSIX)
126 initializing_lock_
.reset();
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";
143 if (sigaction(SIGTERM
, &old_action_
, NULL
) < 0) {
144 DPLOG(ERROR
) << "sigaction";
147 g_signal_socket
= -1;
150 void ServiceProcessState::CreateState() {
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.
161 bool ServiceProcessState::SignalReady(
162 base::MessageLoopProxy
* message_loop_proxy
,
163 const base::Closure
& terminate_task
) {
166 #if defined(OS_POSIX) && !defined(OS_MACOSX)
167 state_
->running_lock_
.reset(TakeServiceRunningLock(true));
168 if (state_
->running_lock_
.get() == NULL
) {
172 state_
->terminate_monitor_
.reset(
173 new ServiceProcessTerminateMonitor(terminate_task
));
174 if (pipe(state_
->sockets_
) < 0) {
175 DPLOG(ERROR
) << "pipe";
178 base::WaitableEvent
signal_ready(true, false);
179 bool success
= false;
181 message_loop_proxy
->PostTask(FROM_HERE
,
182 base::Bind(&ServiceProcessState::StateData::SignalReady
,
190 void ServiceProcessState::TearDownState() {