- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / common / service_process_util_posix.cc
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.
4
5 #include "chrome/common/service_process_util_posix.h"
6
7 #include "base/basictypes.h"
8 #include "base/bind.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"
13
14 namespace {
15 int g_signal_socket = -1;
16 }
17
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;
29     }
30     if (!waiting) break;
31     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
32   }
33   if (!got_lock) {
34     lock.reset();
35   }
36   return lock.release();
37 }
38
39 ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
40     const base::Closure& terminate_task)
41     : terminate_task_(terminate_task) {
42 }
43
44 ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() {
45 }
46
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";
60     }
61   }
62 }
63
64 void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) {
65   NOTIMPLEMENTED();
66 }
67
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";
77   }
78 }
79
80 ServiceProcessState::StateData::StateData() : set_action_(false) {
81   memset(sockets_, -1, sizeof(sockets_));
82   memset(&old_action_, 0, sizeof(old_action_));
83 }
84
85 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
86                                                  bool* success) {
87   DCHECK_EQ(g_signal_socket, -1);
88   DCHECK(!signal->IsSignaled());
89   *success = base::MessageLoopForIO::current()->WatchFileDescriptor(
90       sockets_[0],
91       true,
92       base::MessageLoopForIO::WATCH_READ,
93       &watcher_,
94       terminate_monitor_.get());
95   if (!*success) {
96     DLOG(ERROR) << "WatchFileDescriptor";
97     signal->Signal();
98     return;
99   }
100   g_signal_socket = sockets_[1];
101
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;
109   if (!*success) {
110     DPLOG(ERROR) << "sigaction";
111     signal->Signal();
112     return;
113   }
114
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);
119   set_action_ = true;
120
121 #if defined(OS_MACOSX)
122   *success = WatchExecutable();
123   if (!*success) {
124     DLOG(ERROR) << "WatchExecutable";
125     signal->Signal();
126     return;
127   }
128 #elif defined(OS_POSIX)
129   initializing_lock_.reset();
130 #endif  // OS_POSIX
131   signal->Signal();
132 }
133
134 ServiceProcessState::StateData::~StateData() {
135   if (sockets_[0] != -1) {
136     if (HANDLE_EINTR(close(sockets_[0]))) {
137       DPLOG(ERROR) << "close";
138     }
139   }
140   if (sockets_[1] != -1) {
141     if (HANDLE_EINTR(close(sockets_[1]))) {
142       DPLOG(ERROR) << "close";
143     }
144   }
145   if (set_action_) {
146     if (sigaction(SIGTERM, &old_action_, NULL) < 0) {
147       DPLOG(ERROR) << "sigaction";
148     }
149   }
150   g_signal_socket = -1;
151 }
152
153 void ServiceProcessState::CreateState() {
154   DCHECK(!state_);
155   state_ = new StateData;
156
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.
161   state_->AddRef();
162 }
163
164 bool ServiceProcessState::SignalReady(
165     base::MessageLoopProxy* message_loop_proxy,
166     const base::Closure& terminate_task) {
167   DCHECK(state_);
168
169 #if defined(OS_POSIX) && !defined(OS_MACOSX)
170   state_->running_lock_.reset(TakeServiceRunningLock(true));
171   if (state_->running_lock_.get() == NULL) {
172     return false;
173   }
174 #endif
175   state_->terminate_monitor_.reset(
176       new ServiceProcessTerminateMonitor(terminate_task));
177   if (pipe(state_->sockets_) < 0) {
178     DPLOG(ERROR) << "pipe";
179     return false;
180   }
181   base::WaitableEvent signal_ready(true, false);
182   bool success = false;
183
184   message_loop_proxy->PostTask(FROM_HERE,
185       base::Bind(&ServiceProcessState::StateData::SignalReady,
186                  state_,
187                  &signal_ready,
188                  &success));
189   signal_ready.Wait();
190   return success;
191 }
192
193 void ServiceProcessState::TearDownState() {
194   if (state_) {
195     state_->Release();
196     state_ = NULL;
197   }
198 }