15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/service_process_util_posix.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/multi_process_lock.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int g_signal_socket = -1; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempts to take a lock named |name|. If |waiting| is true then this will 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// make multiple attempts to acquire the lock. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Caller is responsible for ownership of the MultiProcessLock. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name)); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lock == NULL) return NULL; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool got_lock = false; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 10; ++i) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lock->TryLock()) { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_lock = true; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!waiting) break; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i)); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!got_lock) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lock.reset(); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return lock.release(); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor( 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::Closure& terminate_task) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : terminate_task_(terminate_task) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!terminate_task_.is_null()) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int buffer; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int length = read(fd, &buffer, sizeof(buffer)); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) terminate_task_.Run(); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) terminate_task_.Reset(); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (length > 0) { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Unexpected read: " << buffer; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (length == 0) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Unexpected fd close"; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (length < 0) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "read"; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTIMPLEMENTED(); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "Forced" Shutdowns on POSIX are done via signals. The magic signal for 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not, but we don't ever expect it to be called. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void SigTermHandler(int sig, siginfo_t* info, void* uap) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmaclach): add security here to make sure that we are being shut 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // down by an appropriate process. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int message = ServiceProcessTerminateMonitor::kTerminateMessage; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write(g_signal_socket, &message, sizeof(message)) < 0) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "write"; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessState::StateData::StateData() : set_action_(false) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(sockets_, -1, sizeof(sockets_)); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&old_action_, 0, sizeof(old_action_)); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal, 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* success) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(g_signal_socket, -1); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!signal->IsSignaled()); 89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) *success = base::MessageLoopForIO::current()->WatchFileDescriptor( 90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) sockets_[0], 91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) true, 92a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::MessageLoopForIO::WATCH_READ, 93a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &watcher_, 94a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) terminate_monitor_.get()); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*success) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "WatchFileDescriptor"; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal->Signal(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_socket = sockets_[1]; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set up signal handler for SIGTERM. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sigaction action; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&action, 0, sizeof(action)); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) action.sa_sigaction = SigTermHandler; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sigemptyset(&action.sa_mask); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) action.sa_flags = SA_SIGINFO; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *success = sigaction(SIGTERM, &action, &old_action_) == 0; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*success) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "sigaction"; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal->Signal(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the old_action is not default, somebody else has installed a 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a competing handler. Our handler is going to override it so it 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // won't be called. If this occurs it needs to be fixed. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(old_action_.sa_handler, SIG_DFL); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_action_ = true; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *success = WatchExecutable(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*success) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "WatchExecutable"; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal->Signal(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initializing_lock_.reset(); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // OS_POSIX 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal->Signal(); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceProcessState::StateData::~StateData() { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sockets_[0] != -1) { 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IGNORE_EINTR(close(sockets_[0]))) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "close"; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sockets_[1] != -1) { 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IGNORE_EINTR(close(sockets_[1]))) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "close"; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (set_action_) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sigaction(SIGTERM, &old_action_, NULL) < 0) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "sigaction"; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_socket = -1; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessState::CreateState() { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!state_); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = new StateData; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Explicitly adding a reference here (and removing it in TearDownState) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because StateData is refcounted on Mac and Linux so that methods can 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be called on other threads. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is not refcounted on Windows at this time. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_->AddRef(); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ServiceProcessState::SignalReady( 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MessageLoopProxy* message_loop_proxy, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::Closure& terminate_task) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(state_); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) && !defined(OS_MACOSX) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_->running_lock_.reset(TakeServiceRunningLock(true)); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_->running_lock_.get() == NULL) { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_->terminate_monitor_.reset( 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new ServiceProcessTerminateMonitor(terminate_task)); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pipe(state_->sockets_) < 0) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DPLOG(ERROR) << "pipe"; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WaitableEvent signal_ready(true, false); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = false; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop_proxy->PostTask(FROM_HERE, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&ServiceProcessState::StateData::SignalReady, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &signal_ready, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &success)); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signal_ready.Wait(); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServiceProcessState::TearDownState() { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_) { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_->Release(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = NULL; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 199