1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Use of this source code is governed by a BSD-style license that can be 3731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// found in the LICENSE file. 4731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 5dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/common/service_process_util_posix.h" 6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/basictypes.h" 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/eintr_wrapper.h" 972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/message_loop_proxy.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/synchronization/waitable_event.h" 11731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 12731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace { 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint g_signal_socket = -1; 1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 16dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenServiceProcessShutdownMonitor::ServiceProcessShutdownMonitor( 17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Task* shutdown_task) 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : shutdown_task_(shutdown_task) { 19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 20731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() { 2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) { 2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (shutdown_task_.get()) { 2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int buffer; 2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int length = read(fd, &buffer, sizeof(buffer)); 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) { 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen shutdown_task_->Run(); 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen shutdown_task_.reset(); 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (length > 0) { 3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(ERROR) << "Unexpected read: " << buffer; 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (length == 0) { 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(ERROR) << "Unexpected fd close"; 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (length < 0) { 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen PLOG(ERROR) << "read"; 3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) { 42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick NOTIMPLEMENTED(); 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// "Forced" Shutdowns on POSIX are done via signals. The magic signal for 4672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is 4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// not, but we don't ever expect it to be called. 4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic void SigTermHandler(int sig, siginfo_t* info, void* uap) { 4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // TODO(dmaclach): add security here to make sure that we are being shut 5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // down by an appropriate process. 5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int message = ServiceProcessShutdownMonitor::kShutDownMessage; 5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (write(g_signal_socket, &message, sizeof(message)) < 0) { 5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen PLOG(ERROR) << "write"; 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenServiceProcessState::StateData::StateData() : set_action_(false) { 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen memset(sockets_, -1, sizeof(sockets_)); 59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen memset(&old_action_, 0, sizeof(old_action_)); 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal, 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool* success) { 64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CHECK_EQ(g_signal_socket, -1); 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CHECK(!signal->IsSignaled()); 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *success = MessageLoopForIO::current()->WatchFileDescriptor( 67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sockets_[0], true, MessageLoopForIO::WATCH_READ, 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &watcher_, shut_down_monitor_.get()); 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!*success) { 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen LOG(ERROR) << "WatchFileDescriptor"; 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signal->Signal(); 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 74dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen g_signal_socket = sockets_[1]; 75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Set up signal handler for SIGTERM. 77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen struct sigaction action; 78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen action.sa_sigaction = SigTermHandler; 79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen sigemptyset(&action.sa_mask); 80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen action.sa_flags = SA_SIGINFO; 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *success = sigaction(SIGTERM, &action, &old_action_) == 0; 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!*success) { 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PLOG(ERROR) << "sigaction"; 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signal->Signal(); 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // If the old_action is not default, somebody else has installed a 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // a competing handler. Our handler is going to override it so it 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // won't be called. If this occurs it needs to be fixed. 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK_EQ(old_action_.sa_handler, SIG_DFL); 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen set_action_ = true; 93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_LINUX) 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen initializing_lock_.reset(); 96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif // OS_LINUX 97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_MACOSX) 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *success = WatchExecutable(); 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!*success) { 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen LOG(ERROR) << "WatchExecutable"; 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signal->Signal(); 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif // OS_MACOSX 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signal->Signal(); 106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenServiceProcessState::StateData::~StateData() { 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (sockets_[0] != -1) { 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (HANDLE_EINTR(close(sockets_[0]))) { 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PLOG(ERROR) << "close"; 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (sockets_[1] != -1) { 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (HANDLE_EINTR(close(sockets_[1]))) { 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PLOG(ERROR) << "close"; 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (set_action_) { 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (sigaction(SIGTERM, &old_action_, NULL) < 0) { 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PLOG(ERROR) << "sigaction"; 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen g_signal_socket = -1; 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ServiceProcessState::CreateState() { 12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CHECK(!state_); 12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen state_ = new StateData; 130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Explicitly adding a reference here (and removing it in TearDownState) 132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // because StateData is refcounted on Mac and Linux so that methods can 133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // be called on other threads. 134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // It is not refcounted on Windows at this time. 13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen state_->AddRef(); 13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool ServiceProcessState::SignalReady( 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) { 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CHECK(state_); 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<Task> scoped_shutdown_task(shutdown_task); 143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_LINUX) 14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen state_->running_lock_.reset(TakeServiceRunningLock(true)); 14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (state_->running_lock_.get() == NULL) { 14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif // OS_LINUX 14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen state_->shut_down_monitor_.reset( 150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new ServiceProcessShutdownMonitor(scoped_shutdown_task.release())); 15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (pipe(state_->sockets_) < 0) { 15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen PLOG(ERROR) << "pipe"; 15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::WaitableEvent signal_ready(true, false); 156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool success = false; 157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen message_loop_proxy->PostTask(FROM_HERE, 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady, 160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &signal_ready, 161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &success)); 162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen signal_ready.Wait(); 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return success; 164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ServiceProcessState::TearDownState() { 16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (state_) { 16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen state_->Release(); 16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen state_ = NULL; 17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 172