1 // Copyright (c) 2011 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.
4
5 #include "chrome/common/service_process_util_posix.h"
6
7 #include "base/basictypes.h"
8 #include "base/eintr_wrapper.h"
9 #include "base/message_loop_proxy.h"
10 #include "base/synchronization/waitable_event.h"
11
12 namespace {
13 int g_signal_socket = -1;
14 }
15
ServiceProcessShutdownMonitor(Task * shutdown_task)16 ServiceProcessShutdownMonitor::ServiceProcessShutdownMonitor(
17 Task* shutdown_task)
18 : shutdown_task_(shutdown_task) {
19 }
20
~ServiceProcessShutdownMonitor()21 ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() {
22 }
23
OnFileCanReadWithoutBlocking(int fd)24 void ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) {
25 if (shutdown_task_.get()) {
26 int buffer;
27 int length = read(fd, &buffer, sizeof(buffer));
28 if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) {
29 shutdown_task_->Run();
30 shutdown_task_.reset();
31 } else if (length > 0) {
32 LOG(ERROR) << "Unexpected read: " << buffer;
33 } else if (length == 0) {
34 LOG(ERROR) << "Unexpected fd close";
35 } else if (length < 0) {
36 PLOG(ERROR) << "read";
37 }
38 }
39 }
40
OnFileCanWriteWithoutBlocking(int fd)41 void ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) {
42 NOTIMPLEMENTED();
43 }
44
45 // "Forced" Shutdowns on POSIX are done via signals. The magic signal for
46 // a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
47 // not, but we don't ever expect it to be called.
SigTermHandler(int sig,siginfo_t * info,void * uap)48 static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
49 // TODO(dmaclach): add security here to make sure that we are being shut
50 // down by an appropriate process.
51 int message = ServiceProcessShutdownMonitor::kShutDownMessage;
52 if (write(g_signal_socket, &message, sizeof(message)) < 0) {
53 PLOG(ERROR) << "write";
54 }
55 }
56
StateData()57 ServiceProcessState::StateData::StateData() : set_action_(false) {
58 memset(sockets_, -1, sizeof(sockets_));
59 memset(&old_action_, 0, sizeof(old_action_));
60 }
61
SignalReady(base::WaitableEvent * signal,bool * success)62 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
63 bool* success) {
64 CHECK_EQ(g_signal_socket, -1);
65 CHECK(!signal->IsSignaled());
66 *success = MessageLoopForIO::current()->WatchFileDescriptor(
67 sockets_[0], true, MessageLoopForIO::WATCH_READ,
68 &watcher_, shut_down_monitor_.get());
69 if (!*success) {
70 LOG(ERROR) << "WatchFileDescriptor";
71 signal->Signal();
72 return;
73 }
74 g_signal_socket = sockets_[1];
75
76 // Set up signal handler for SIGTERM.
77 struct sigaction action;
78 action.sa_sigaction = SigTermHandler;
79 sigemptyset(&action.sa_mask);
80 action.sa_flags = SA_SIGINFO;
81 *success = sigaction(SIGTERM, &action, &old_action_) == 0;
82 if (!*success) {
83 PLOG(ERROR) << "sigaction";
84 signal->Signal();
85 return;
86 }
87
88 // If the old_action is not default, somebody else has installed a
89 // a competing handler. Our handler is going to override it so it
90 // won't be called. If this occurs it needs to be fixed.
91 DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
92 set_action_ = true;
93
94 #if defined(OS_LINUX)
95 initializing_lock_.reset();
96 #endif // OS_LINUX
97 #if defined(OS_MACOSX)
98 *success = WatchExecutable();
99 if (!*success) {
100 LOG(ERROR) << "WatchExecutable";
101 signal->Signal();
102 return;
103 }
104 #endif // OS_MACOSX
105 signal->Signal();
106 }
107
~StateData()108 ServiceProcessState::StateData::~StateData() {
109 if (sockets_[0] != -1) {
110 if (HANDLE_EINTR(close(sockets_[0]))) {
111 PLOG(ERROR) << "close";
112 }
113 }
114 if (sockets_[1] != -1) {
115 if (HANDLE_EINTR(close(sockets_[1]))) {
116 PLOG(ERROR) << "close";
117 }
118 }
119 if (set_action_) {
120 if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
121 PLOG(ERROR) << "sigaction";
122 }
123 }
124 g_signal_socket = -1;
125 }
126
CreateState()127 void ServiceProcessState::CreateState() {
128 CHECK(!state_);
129 state_ = new StateData;
130
131 // Explicitly adding a reference here (and removing it in TearDownState)
132 // because StateData is refcounted on Mac and Linux so that methods can
133 // be called on other threads.
134 // It is not refcounted on Windows at this time.
135 state_->AddRef();
136 }
137
SignalReady(base::MessageLoopProxy * message_loop_proxy,Task * shutdown_task)138 bool ServiceProcessState::SignalReady(
139 base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) {
140 CHECK(state_);
141
142 scoped_ptr<Task> scoped_shutdown_task(shutdown_task);
143 #if defined(OS_LINUX)
144 state_->running_lock_.reset(TakeServiceRunningLock(true));
145 if (state_->running_lock_.get() == NULL) {
146 return false;
147 }
148 #endif // OS_LINUX
149 state_->shut_down_monitor_.reset(
150 new ServiceProcessShutdownMonitor(scoped_shutdown_task.release()));
151 if (pipe(state_->sockets_) < 0) {
152 PLOG(ERROR) << "pipe";
153 return false;
154 }
155 base::WaitableEvent signal_ready(true, false);
156 bool success = false;
157
158 message_loop_proxy->PostTask(FROM_HERE,
159 NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady,
160 &signal_ready,
161 &success));
162 signal_ready.Wait();
163 return success;
164 }
165
TearDownState()166 void ServiceProcessState::TearDownState() {
167 if (state_) {
168 state_->Release();
169 state_ = NULL;
170 }
171 }
172