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 16 ServiceProcessShutdownMonitor::ServiceProcessShutdownMonitor( 17 Task* shutdown_task) 18 : shutdown_task_(shutdown_task) { 19 } 20 21 ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() { 22 } 23 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 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. 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 57 ServiceProcessState::StateData::StateData() : set_action_(false) { 58 memset(sockets_, -1, sizeof(sockets_)); 59 memset(&old_action_, 0, sizeof(old_action_)); 60 } 61 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 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 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 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 166 void ServiceProcessState::TearDownState() { 167 if (state_) { 168 state_->Release(); 169 state_ = NULL; 170 } 171 } 172