| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/common/service_process_util_posix.h" | 5 #include "chrome/common/service_process_util_posix.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/eintr_wrapper.h" | 8 #include "base/eintr_wrapper.h" |
| 9 #include "base/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
| 10 #include "base/synchronization/waitable_event.h" | 10 #include "base/synchronization/waitable_event.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 } | 22 } |
| 23 | 23 |
| 24 void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) { | 24 void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) { |
| 25 if (terminate_task_.get()) { | 25 if (terminate_task_.get()) { |
| 26 int buffer; | 26 int buffer; |
| 27 int length = read(fd, &buffer, sizeof(buffer)); | 27 int length = read(fd, &buffer, sizeof(buffer)); |
| 28 if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) { | 28 if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) { |
| 29 terminate_task_->Run(); | 29 terminate_task_->Run(); |
| 30 terminate_task_.reset(); | 30 terminate_task_.reset(); |
| 31 } else if (length > 0) { | 31 } else if (length > 0) { |
| 32 LOG(ERROR) << "Unexpected read: " << buffer; | 32 DLOG(ERROR) << "Unexpected read: " << buffer; |
| 33 } else if (length == 0) { | 33 } else if (length == 0) { |
| 34 LOG(ERROR) << "Unexpected fd close"; | 34 DLOG(ERROR) << "Unexpected fd close"; |
| 35 } else if (length < 0) { | 35 } else if (length < 0) { |
| 36 PLOG(ERROR) << "read"; | 36 DPLOG(ERROR) << "read"; |
| 37 } | 37 } |
| 38 } | 38 } |
| 39 } | 39 } |
| 40 | 40 |
| 41 void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) { | 41 void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) { |
| 42 NOTIMPLEMENTED(); | 42 NOTIMPLEMENTED(); |
| 43 } | 43 } |
| 44 | 44 |
| 45 // "Forced" Shutdowns on POSIX are done via signals. The magic signal for | 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 | 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. | 47 // not, but we don't ever expect it to be called. |
| 48 static void 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 | 49 // TODO(dmaclach): add security here to make sure that we are being shut |
| 50 // down by an appropriate process. | 50 // down by an appropriate process. |
| 51 int message = ServiceProcessTerminateMonitor::kTerminateMessage; | 51 int message = ServiceProcessTerminateMonitor::kTerminateMessage; |
| 52 if (write(g_signal_socket, &message, sizeof(message)) < 0) { | 52 if (write(g_signal_socket, &message, sizeof(message)) < 0) { |
| 53 PLOG(ERROR) << "write"; | 53 DPLOG(ERROR) << "write"; |
| 54 } | 54 } |
| 55 } | 55 } |
| 56 | 56 |
| 57 ServiceProcessState::StateData::StateData() : set_action_(false) { | 57 ServiceProcessState::StateData::StateData() : set_action_(false) { |
| 58 memset(sockets_, -1, sizeof(sockets_)); | 58 memset(sockets_, -1, sizeof(sockets_)); |
| 59 memset(&old_action_, 0, sizeof(old_action_)); | 59 memset(&old_action_, 0, sizeof(old_action_)); |
| 60 } | 60 } |
| 61 | 61 |
| 62 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal, | 62 void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal, |
| 63 bool* success) { | 63 bool* success) { |
| 64 CHECK_EQ(g_signal_socket, -1); | 64 DCHECK_EQ(g_signal_socket, -1); |
| 65 CHECK(!signal->IsSignaled()); | 65 DCHECK(!signal->IsSignaled()); |
| 66 *success = MessageLoopForIO::current()->WatchFileDescriptor( | 66 *success = MessageLoopForIO::current()->WatchFileDescriptor( |
| 67 sockets_[0], true, MessageLoopForIO::WATCH_READ, | 67 sockets_[0], true, MessageLoopForIO::WATCH_READ, |
| 68 &watcher_, terminate_monitor_.get()); | 68 &watcher_, terminate_monitor_.get()); |
| 69 if (!*success) { | 69 if (!*success) { |
| 70 LOG(ERROR) << "WatchFileDescriptor"; | 70 DLOG(ERROR) << "WatchFileDescriptor"; |
| 71 signal->Signal(); | 71 signal->Signal(); |
| 72 return; | 72 return; |
| 73 } | 73 } |
| 74 g_signal_socket = sockets_[1]; | 74 g_signal_socket = sockets_[1]; |
| 75 | 75 |
| 76 // Set up signal handler for SIGTERM. | 76 // Set up signal handler for SIGTERM. |
| 77 struct sigaction action; | 77 struct sigaction action; |
| 78 memset(&action, 0, sizeof(action)); | 78 memset(&action, 0, sizeof(action)); |
| 79 action.sa_sigaction = SigTermHandler; | 79 action.sa_sigaction = SigTermHandler; |
| 80 sigemptyset(&action.sa_mask); | 80 sigemptyset(&action.sa_mask); |
| 81 action.sa_flags = SA_SIGINFO; | 81 action.sa_flags = SA_SIGINFO; |
| 82 *success = sigaction(SIGTERM, &action, &old_action_) == 0; | 82 *success = sigaction(SIGTERM, &action, &old_action_) == 0; |
| 83 if (!*success) { | 83 if (!*success) { |
| 84 PLOG(ERROR) << "sigaction"; | 84 DPLOG(ERROR) << "sigaction"; |
| 85 signal->Signal(); | 85 signal->Signal(); |
| 86 return; | 86 return; |
| 87 } | 87 } |
| 88 | 88 |
| 89 // If the old_action is not default, somebody else has installed a | 89 // If the old_action is not default, somebody else has installed a |
| 90 // a competing handler. Our handler is going to override it so it | 90 // a competing handler. Our handler is going to override it so it |
| 91 // won't be called. If this occurs it needs to be fixed. | 91 // won't be called. If this occurs it needs to be fixed. |
| 92 DCHECK_EQ(old_action_.sa_handler, SIG_DFL); | 92 DCHECK_EQ(old_action_.sa_handler, SIG_DFL); |
| 93 set_action_ = true; | 93 set_action_ = true; |
| 94 | 94 |
| 95 #if defined(OS_MACOSX) | 95 #if defined(OS_MACOSX) |
| 96 *success = WatchExecutable(); | 96 *success = WatchExecutable(); |
| 97 if (!*success) { | 97 if (!*success) { |
| 98 LOG(ERROR) << "WatchExecutable"; | 98 DLOG(ERROR) << "WatchExecutable"; |
| 99 signal->Signal(); | 99 signal->Signal(); |
| 100 return; | 100 return; |
| 101 } | 101 } |
| 102 #elif defined(OS_POSIX) | 102 #elif defined(OS_POSIX) |
| 103 initializing_lock_.reset(); | 103 initializing_lock_.reset(); |
| 104 #endif // OS_POSIX | 104 #endif // OS_POSIX |
| 105 signal->Signal(); | 105 signal->Signal(); |
| 106 } | 106 } |
| 107 | 107 |
| 108 ServiceProcessState::StateData::~StateData() { | 108 ServiceProcessState::StateData::~StateData() { |
| 109 if (sockets_[0] != -1) { | 109 if (sockets_[0] != -1) { |
| 110 if (HANDLE_EINTR(close(sockets_[0]))) { | 110 if (HANDLE_EINTR(close(sockets_[0]))) { |
| 111 PLOG(ERROR) << "close"; | 111 DPLOG(ERROR) << "close"; |
| 112 } | 112 } |
| 113 } | 113 } |
| 114 if (sockets_[1] != -1) { | 114 if (sockets_[1] != -1) { |
| 115 if (HANDLE_EINTR(close(sockets_[1]))) { | 115 if (HANDLE_EINTR(close(sockets_[1]))) { |
| 116 PLOG(ERROR) << "close"; | 116 DPLOG(ERROR) << "close"; |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 if (set_action_) { | 119 if (set_action_) { |
| 120 if (sigaction(SIGTERM, &old_action_, NULL) < 0) { | 120 if (sigaction(SIGTERM, &old_action_, NULL) < 0) { |
| 121 PLOG(ERROR) << "sigaction"; | 121 DPLOG(ERROR) << "sigaction"; |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 g_signal_socket = -1; | 124 g_signal_socket = -1; |
| 125 } | 125 } |
| 126 | 126 |
| 127 void ServiceProcessState::CreateState() { | 127 void ServiceProcessState::CreateState() { |
| 128 CHECK(!state_); | 128 DCHECK(!state_); |
| 129 state_ = new StateData; | 129 state_ = new StateData; |
| 130 | 130 |
| 131 // Explicitly adding a reference here (and removing it in TearDownState) | 131 // Explicitly adding a reference here (and removing it in TearDownState) |
| 132 // because StateData is refcounted on Mac and Linux so that methods can | 132 // because StateData is refcounted on Mac and Linux so that methods can |
| 133 // be called on other threads. | 133 // be called on other threads. |
| 134 // It is not refcounted on Windows at this time. | 134 // It is not refcounted on Windows at this time. |
| 135 state_->AddRef(); | 135 state_->AddRef(); |
| 136 } | 136 } |
| 137 | 137 |
| 138 bool ServiceProcessState::SignalReady( | 138 bool ServiceProcessState::SignalReady( |
| 139 base::MessageLoopProxy* message_loop_proxy, Task* terminate_task) { | 139 base::MessageLoopProxy* message_loop_proxy, Task* terminate_task) { |
| 140 CHECK(state_); | 140 DCHECK(state_); |
| 141 | 141 |
| 142 scoped_ptr<Task> scoped_terminate_task(terminate_task); | 142 scoped_ptr<Task> scoped_terminate_task(terminate_task); |
| 143 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 143 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| 144 state_->running_lock_.reset(TakeServiceRunningLock(true)); | 144 state_->running_lock_.reset(TakeServiceRunningLock(true)); |
| 145 if (state_->running_lock_.get() == NULL) { | 145 if (state_->running_lock_.get() == NULL) { |
| 146 return false; | 146 return false; |
| 147 } | 147 } |
| 148 #endif | 148 #endif |
| 149 state_->terminate_monitor_.reset( | 149 state_->terminate_monitor_.reset( |
| 150 new ServiceProcessTerminateMonitor(scoped_terminate_task.release())); | 150 new ServiceProcessTerminateMonitor(scoped_terminate_task.release())); |
| 151 if (pipe(state_->sockets_) < 0) { | 151 if (pipe(state_->sockets_) < 0) { |
| 152 PLOG(ERROR) << "pipe"; | 152 DPLOG(ERROR) << "pipe"; |
| 153 return false; | 153 return false; |
| 154 } | 154 } |
| 155 base::WaitableEvent signal_ready(true, false); | 155 base::WaitableEvent signal_ready(true, false); |
| 156 bool success = false; | 156 bool success = false; |
| 157 | 157 |
| 158 message_loop_proxy->PostTask(FROM_HERE, | 158 message_loop_proxy->PostTask(FROM_HERE, |
| 159 NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady, | 159 NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady, |
| 160 &signal_ready, | 160 &signal_ready, |
| 161 &success)); | 161 &success)); |
| 162 signal_ready.Wait(); | 162 signal_ready.Wait(); |
| 163 return success; | 163 return success; |
| 164 } | 164 } |
| 165 | 165 |
| 166 void ServiceProcessState::TearDownState() { | 166 void ServiceProcessState::TearDownState() { |
| 167 if (state_) { | 167 if (state_) { |
| 168 state_->Release(); | 168 state_->Release(); |
| 169 state_ = NULL; | 169 state_ = NULL; |
| 170 } | 170 } |
| 171 } | 171 } |
| OLD | NEW |