service_process_util_posix.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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/message_loop_proxy.h" 9 10namespace { 11int g_signal_socket = -1; 12} 13 14ServiceProcessShutdownMonitor::ServiceProcessShutdownMonitor( 15 Task* shutdown_task) 16 : shutdown_task_(shutdown_task) { 17} 18 19ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() { 20} 21 22void ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) { 23 if (shutdown_task_.get()) { 24 int buffer; 25 int length = read(fd, &buffer, sizeof(buffer)); 26 if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) { 27 shutdown_task_->Run(); 28 shutdown_task_.reset(); 29 } else if (length > 0) { 30 LOG(ERROR) << "Unexpected read: " << buffer; 31 } else if (length == 0) { 32 LOG(ERROR) << "Unexpected fd close"; 33 } else if (length < 0) { 34 PLOG(ERROR) << "read"; 35 } 36 } 37} 38 39void ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) { 40 NOTIMPLEMENTED(); 41} 42 43// "Forced" Shutdowns on POSIX are done via signals. The magic signal for 44// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is 45// not, but we don't ever expect it to be called. 46static void SigTermHandler(int sig, siginfo_t* info, void* uap) { 47 // TODO(dmaclach): add security here to make sure that we are being shut 48 // down by an appropriate process. 49 int message = ServiceProcessShutdownMonitor::kShutDownMessage; 50 if (write(g_signal_socket, &message, sizeof(message)) < 0) { 51 PLOG(ERROR) << "write"; 52 } 53} 54 55ServiceProcessState::StateData::StateData() {} 56 57void ServiceProcessState::StateData::SignalReady() { 58 CHECK(MessageLoopForIO::current()->WatchFileDescriptor( 59 sockets_[0], true, MessageLoopForIO::WATCH_READ, 60 &watcher_, shut_down_monitor_.get())); 61 g_signal_socket = sockets_[1]; 62 63 // Set up signal handler for SIGTERM. 64 struct sigaction action; 65 action.sa_sigaction = SigTermHandler; 66 sigemptyset(&action.sa_mask); 67 action.sa_flags = SA_SIGINFO; 68 if (sigaction(SIGTERM, &action, &old_action_) == 0) { 69 // If the old_action is not default, somebody else has installed a 70 // a competing handler. Our handler is going to override it so it 71 // won't be called. If this occurs it needs to be fixed. 72 DCHECK_EQ(old_action_.sa_handler, SIG_DFL); 73 set_action_ = true; 74#if defined(OS_LINUX) 75 initializing_lock_.reset(); 76#endif // OS_LINUX 77 } else { 78 PLOG(ERROR) << "sigaction"; 79 } 80} 81 82ServiceProcessState::StateData::~StateData() {} 83 84bool ServiceProcessState::InitializeState() { 85 CHECK(!state_); 86 state_ = new StateData; 87 state_->AddRef(); 88 state_->sockets_[0] = -1; 89 state_->sockets_[1] = -1; 90 state_->set_action_ = false; 91 return true; 92} 93 94bool ServiceProcessState::SignalReady( 95 base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) { 96 CHECK(state_); 97 CHECK_EQ(g_signal_socket, -1); 98 99#if defined(OS_LINUX) 100 state_->running_lock_.reset(TakeServiceRunningLock(true)); 101 if (state_->running_lock_.get() == NULL) { 102 return false; 103 } 104#endif // OS_LINUX 105 state_->shut_down_monitor_.reset( 106 new ServiceProcessShutdownMonitor(shutdown_task)); 107 if (pipe(state_->sockets_) < 0) { 108 PLOG(ERROR) << "pipe"; 109 return false; 110 } 111 message_loop_proxy->PostTask(FROM_HERE, 112 NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady)); 113 return true; 114} 115 116void ServiceProcessState::TearDownState() { 117 g_signal_socket = -1; 118 if (state_) { 119 if (state_->sockets_[0] != -1) { 120 close(state_->sockets_[0]); 121 } 122 if (state_->sockets_[1] != -1) { 123 close(state_->sockets_[1]); 124 } 125 if (state_->set_action_) { 126 if (sigaction(SIGTERM, &state_->old_action_, NULL) < 0) { 127 PLOG(ERROR) << "sigaction"; 128 } 129 } 130 state_->Release(); 131 state_ = NULL; 132 } 133} 134