• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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