Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: chrome/common/service_process_util_posix.cc

Issue 6349029: Get service processes working on Mac and Linux. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Some code cleanup Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 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.h" 5 #include "chrome/common/service_process_util.h"
6 6
7 #include <signal.h>
8 #include <unistd.h>
9
7 #include "base/file_util.h" 10 #include "base/file_util.h"
8 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/message_loop.h"
13 #include "base/message_pump_libevent.h"
9 #include "base/path_service.h" 14 #include "base/path_service.h"
10 #include "chrome/common/chrome_paths.h" 15 #include "chrome/common/chrome_paths.h"
11 #include "chrome/common/chrome_version_info.h" 16 #include "chrome/common/chrome_version_info.h"
17 #include "chrome/common/multi_process_lock.h"
12 18
13 namespace { 19 namespace {
14 20
21 int g_signal_socket = -1;
22
15 // Gets the name of the lock file for service process. 23 // Gets the name of the lock file for service process.
16 FilePath GetServiceProcessLockFilePath() { 24 FilePath GetServiceProcessLockFilePath() {
17 FilePath user_data_dir; 25 FilePath user_data_dir;
18 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 26 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
19 chrome::VersionInfo version_info; 27 chrome::VersionInfo version_info;
20 std::string lock_file_name = version_info.Version() + "Service Process Lock"; 28 std::string lock_file_name = version_info.Version() + "Service Process Lock";
21 return user_data_dir.Append(lock_file_name); 29 return user_data_dir.Append(lock_file_name);
22 } 30 }
23 31
32 // Attempts to take a lock named |name|. If |waiting| then is will
33 // make multiple attempts before failing.
34 // Caller is responsible for ownership of the MultiProcessLock.
35 MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
36 scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name));
37 if (lock == NULL) return NULL;
38 bool got_lock = false;
39 for (int i = 0; i < 10; ++i) {
40 if (lock->TryLock()) {
41 got_lock = true;
42 break;
43 }
44 if (!waiting) break;
45 base::PlatformThread::Sleep(100 * i);
46 }
47 if (!got_lock) {
48 lock.reset();
49 }
50 return lock.release();
51 }
52
53 MultiProcessLock* TakeServiceRunningLock(bool waiting) {
54 std::string lock_name =
55 GetServiceProcessScopedName("_service_running");
56 return TakeNamedLock(lock_name, waiting);
57 }
58
59 MultiProcessLock* TakeServiceInitializingLock(bool waiting) {
60 std::string lock_name =
61 GetServiceProcessScopedName("_service_initializing");
62 return TakeNamedLock(lock_name, waiting);
63 }
64
65 // Watches for |kShutDownMessage| to be written to the file descriptor it is
66 // watching. When it reads |kShutDownMessage|, it performs |shutdown_task_|.
67 // Used here to monitor the socket listening to g_signal_socket.
68 class ServiceProcessShutdownMonitor
69 : public base::MessagePumpLibevent::Watcher {
70 public:
71
72 static const int kShutDownMessage = 0xdecea5e;
73
74 explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
75 : shutdown_task_(shutdown_task) {
76 }
77
78 virtual ~ServiceProcessShutdownMonitor();
79
80 virtual void OnFileCanReadWithoutBlocking(int fd);
81 virtual void OnFileCanWriteWithoutBlocking(int fd);
82
83 private:
84 scoped_ptr<Task> shutdown_task_;
85 };
86
87 ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() {
88 }
89
90 void ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) {
91 if (shutdown_task_.get()) {
92 int buffer;
93 int length = read(fd, &buffer, sizeof(buffer));
94 if (length == sizeof(kShutDownMessage) &&
95 memcmp(&buffer, &kShutDownMessage, length) == 0) {
96 shutdown_task_->Run();
97 shutdown_task_.reset();
98 } else if (length > 0) {
99 LOG(ERROR) << "Unexpected read: " << buffer;
100 } else if (length == 0) {
101 LOG(ERROR) << "Unexpected fd close";
102 } else if (length < 0) {
103 PLOG(ERROR) << "read";
104 }
105 }
106 }
107
108 void ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) {
109 NOTIMPLEMENTED();
110 }
111
112 // "Forced" Shutdowns on POSIX are done via signals. The magic signal for
113 // a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
114 // not, but we don't ever expect it to be called.
115 void SigTermHandler(int sig, siginfo_t* info, void* uap) {
116 // TODO(dmaclach): add security here to make sure that we are being shut
117 // down by an appropriate process.
118 if (write(g_signal_socket, &ServiceProcessShutdownMonitor::kShutDownMessage,
119 sizeof(ServiceProcessShutdownMonitor::kShutDownMessage)) < 0) {
120 PLOG(ERROR) << "write";
121 }
122 }
123
24 } // namespace 124 } // namespace
25 125
26 bool ForceServiceProcessShutdown(const std::string& version) { 126 // See comment for SigTermHandler.
27 NOTIMPLEMENTED(); 127 bool ForceServiceProcessShutdown(const std::string& version,
28 return false; 128 base::ProcessId process_id) {
129 if (kill(process_id, SIGTERM) < 0) {
130 PLOG(ERROR) << "kill";
131 return false;
132 }
133 return true;
29 } 134 }
30 135
31 bool CheckServiceProcessReady() { 136 bool CheckServiceProcessReady() {
32 const FilePath path = GetServiceProcessLockFilePath(); 137 scoped_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false));
33 return file_util::PathExists(path); 138 return running_lock.get() == NULL;
34 } 139 }
35 140
36 struct ServiceProcessState::StateData { 141 struct ServiceProcessState::StateData
37 // No state yet for Posix. 142 : public base::RefCountedThreadSafe<ServiceProcessState::StateData> {
143 scoped_ptr<MultiProcessLock> initializing_lock_;
144 scoped_ptr<MultiProcessLock> running_lock_;
145 scoped_ptr<ServiceProcessShutdownMonitor> shut_down_monitor_;
146 base::MessagePumpLibevent::FileDescriptorWatcher watcher_;
147 int sockets_[2];
148 struct sigaction old_action_;
149 bool set_action_;
150
151 // WatchFileDescriptor needs to be set up by the thread that is going
152 // to be monitoring it.
153 void SignalReady() {
154 CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
155 sockets_[0], true, MessageLoopForIO::WATCH_READ,
156 &watcher_, shut_down_monitor_.get()));
157 g_signal_socket = sockets_[1];
158
159 // Set up signal handler for SIGTERM.
160 struct sigaction action;
161 action.sa_sigaction = SigTermHandler;
162 sigemptyset(&action.sa_mask);
163 action.sa_flags = SA_SIGINFO;
164 if (sigaction(SIGTERM, &action, &old_action_) == 0) {
165 // If the old_action is not default, somebody else has installed a
166 // a competing handler. Our handler is going to override it so it
167 // won't be called. If this occurs it needs to be fixed.
168 DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
169 set_action_ = true;
170 initializing_lock_.reset();
171 } else {
172 PLOG(ERROR) << "sigaction";
173 }
174 }
38 }; 175 };
39 176
40 bool ServiceProcessState::TakeSingletonLock() { 177 bool ServiceProcessState::TakeSingletonLock() {
41 // TODO(sanjeevr): Implement singleton mechanism for POSIX. 178 CHECK(!state_);
42 NOTIMPLEMENTED(); 179 state_ = new StateData;
180 state_->AddRef();
181 state_->sockets_[0] = -1;
182 state_->sockets_[1] = -1;
183 state_->set_action_ = false;
184 state_->initializing_lock_.reset(TakeServiceInitializingLock(true));
185 return state_->initializing_lock_.get();
186 }
187
188 bool ServiceProcessState::SignalReady(MessageLoop* message_loop,
189 Task* shutdown_task) {
190 CHECK(state_);
191 CHECK_EQ(g_signal_socket, -1);
192 DCHECK_EQ(message_loop->type(), MessageLoop::TYPE_IO);
193
194 state_->running_lock_.reset(TakeServiceRunningLock(true));
195 if (state_->running_lock_.get() == NULL) {
196 return false;
197 }
198 state_->shut_down_monitor_.reset(
199 new ServiceProcessShutdownMonitor(shutdown_task));
200 if (pipe(state_->sockets_) < 0) {
201 PLOG(ERROR) << "pipe";
202 return false;
203 }
204 message_loop->PostTask(FROM_HERE,
205 NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady));
43 return true; 206 return true;
44 } 207 }
45 208
46 void ServiceProcessState::SignalReady(Task* shutdown_task) {
47 // TODO(hclam): Implement better mechanism for these platform.
48 // Also we need to save shutdown task. For now we just delete the shutdown
49 // task because we have not way to listen for shutdown requests.
50 delete shutdown_task;
51 const FilePath path = GetServiceProcessLockFilePath();
52 FILE* file = file_util::OpenFile(path, "wb+");
53 if (!file)
54 return;
55 VLOG(1) << "Created Service Process lock file: " << path.value();
56 file_util::TruncateFile(file) && file_util::CloseFile(file);
57 }
58
59 void ServiceProcessState::SignalStopped() {
60 const FilePath path = GetServiceProcessLockFilePath();
61 file_util::Delete(path, false);
62 shared_mem_service_data_.reset();
63 }
64
65 bool ServiceProcessState::AddToAutoRun() { 209 bool ServiceProcessState::AddToAutoRun() {
66 NOTIMPLEMENTED(); 210 NOTIMPLEMENTED();
67 return false; 211 return false;
68 } 212 }
69 213
70 bool ServiceProcessState::RemoveFromAutoRun() { 214 bool ServiceProcessState::RemoveFromAutoRun() {
71 NOTIMPLEMENTED(); 215 NOTIMPLEMENTED();
72 return false; 216 return false;
73 } 217 }
74 218
75 void ServiceProcessState::TearDownState() { 219 void ServiceProcessState::TearDownState() {
220 g_signal_socket = -1;
221 if (state_) {
222 if (state_->sockets_[0] != -1) {
223 close(state_->sockets_[0]);
224 }
225 if (state_->sockets_[1] != -1) {
226 close(state_->sockets_[1]);
227 }
228 if (state_->set_action_) {
229 if (sigaction(SIGTERM, &state_->old_action_, NULL) < 0) {
230 PLOG(ERROR) << "sigaction";
231 }
232 }
233 state_->Release();
234 state_ = NULL;
235 }
76 } 236 }
77 237
78 bool ServiceProcessState::ShouldHandleOtherVersion() { 238 bool ServiceProcessState::ShouldHandleOtherVersion() {
79 // On POSIX, the shared memory is a file in disk. We may have a stale file 239 scoped_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false));
80 // lying around from a previous run. So the check is not reliable. 240 return running_lock.get() == NULL;
81 return false;
82 } 241 }
83
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698