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

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: fix up small typo in comment 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
« no previous file with comments | « chrome/common/service_process_util.cc ('k') | chrome/common/service_process_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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| is true then this will
33 // make multiple attempts to acquire the lock.
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 enum {
73 kShutDownMessage = 0xdecea5e
74 };
75
76 explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
77 : shutdown_task_(shutdown_task) {
78 }
79
80 virtual ~ServiceProcessShutdownMonitor();
81
82 virtual void OnFileCanReadWithoutBlocking(int fd);
83 virtual void OnFileCanWriteWithoutBlocking(int fd);
84
85 private:
86 scoped_ptr<Task> shutdown_task_;
87 };
88
89 ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() {
90 }
91
92 void ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) {
93 if (shutdown_task_.get()) {
94 int buffer;
95 int length = read(fd, &buffer, sizeof(buffer));
96 if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) {
97 shutdown_task_->Run();
98 shutdown_task_.reset();
99 } else if (length > 0) {
100 LOG(ERROR) << "Unexpected read: " << buffer;
101 } else if (length == 0) {
102 LOG(ERROR) << "Unexpected fd close";
103 } else if (length < 0) {
104 PLOG(ERROR) << "read";
105 }
106 }
107 }
108
109 void ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) {
110 NOTIMPLEMENTED();
111 }
112
113 // "Forced" Shutdowns on POSIX are done via signals. The magic signal for
114 // a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
115 // not, but we don't ever expect it to be called.
116 void SigTermHandler(int sig, siginfo_t* info, void* uap) {
117 // TODO(dmaclach): add security here to make sure that we are being shut
118 // down by an appropriate process.
119 int message = ServiceProcessShutdownMonitor::kShutDownMessage;
120 if (write(g_signal_socket, &message, sizeof(message)) < 0) {
121 PLOG(ERROR) << "write";
122 }
123 }
124
24 } // namespace 125 } // namespace
25 126
26 bool ForceServiceProcessShutdown(const std::string& version) { 127 // See comment for SigTermHandler.
27 NOTIMPLEMENTED(); 128 bool ForceServiceProcessShutdown(const std::string& version,
28 return false; 129 base::ProcessId process_id) {
130 if (kill(process_id, SIGTERM) < 0) {
131 PLOG(ERROR) << "kill";
132 return false;
133 }
134 return true;
29 } 135 }
30 136
31 bool CheckServiceProcessReady() { 137 bool CheckServiceProcessReady() {
32 const FilePath path = GetServiceProcessLockFilePath(); 138 scoped_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false));
33 return file_util::PathExists(path); 139 return running_lock.get() == NULL;
34 } 140 }
35 141
36 struct ServiceProcessState::StateData { 142 struct ServiceProcessState::StateData
37 // No state yet for Posix. 143 : public base::RefCountedThreadSafe<ServiceProcessState::StateData> {
144 scoped_ptr<MultiProcessLock> initializing_lock_;
145 scoped_ptr<MultiProcessLock> running_lock_;
146 scoped_ptr<ServiceProcessShutdownMonitor> shut_down_monitor_;
147 base::MessagePumpLibevent::FileDescriptorWatcher watcher_;
148 int sockets_[2];
149 struct sigaction old_action_;
150 bool set_action_;
151
152 // WatchFileDescriptor needs to be set up by the thread that is going
153 // to be monitoring it.
154 void SignalReady() {
155 CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
156 sockets_[0], true, MessageLoopForIO::WATCH_READ,
157 &watcher_, shut_down_monitor_.get()));
158 g_signal_socket = sockets_[1];
159
160 // Set up signal handler for SIGTERM.
161 struct sigaction action;
162 action.sa_sigaction = SigTermHandler;
163 sigemptyset(&action.sa_mask);
164 action.sa_flags = SA_SIGINFO;
165 if (sigaction(SIGTERM, &action, &old_action_) == 0) {
166 // If the old_action is not default, somebody else has installed a
167 // a competing handler. Our handler is going to override it so it
168 // won't be called. If this occurs it needs to be fixed.
169 DCHECK_EQ(old_action_.sa_handler, SIG_DFL);
170 set_action_ = true;
171 initializing_lock_.reset();
172 } else {
173 PLOG(ERROR) << "sigaction";
174 }
175 }
38 }; 176 };
39 177
40 bool ServiceProcessState::TakeSingletonLock() { 178 bool ServiceProcessState::TakeSingletonLock() {
41 // TODO(sanjeevr): Implement singleton mechanism for POSIX. 179 CHECK(!state_);
42 NOTIMPLEMENTED(); 180 state_ = new StateData;
181 state_->AddRef();
182 state_->sockets_[0] = -1;
183 state_->sockets_[1] = -1;
184 state_->set_action_ = false;
185 state_->initializing_lock_.reset(TakeServiceInitializingLock(true));
186 return state_->initializing_lock_.get();
187 }
188
189 bool ServiceProcessState::SignalReady(MessageLoop* message_loop,
190 Task* shutdown_task) {
191 CHECK(state_);
192 CHECK_EQ(g_signal_socket, -1);
193 DCHECK_EQ(message_loop->type(), MessageLoop::TYPE_IO);
194
195 state_->running_lock_.reset(TakeServiceRunningLock(true));
196 if (state_->running_lock_.get() == NULL) {
197 return false;
198 }
199 state_->shut_down_monitor_.reset(
200 new ServiceProcessShutdownMonitor(shutdown_task));
201 if (pipe(state_->sockets_) < 0) {
202 PLOG(ERROR) << "pipe";
203 return false;
204 }
205 message_loop->PostTask(FROM_HERE,
206 NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady));
43 return true; 207 return true;
44 } 208 }
45 209
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() { 210 bool ServiceProcessState::AddToAutoRun() {
66 NOTIMPLEMENTED(); 211 NOTIMPLEMENTED();
67 return false; 212 return false;
68 } 213 }
69 214
70 bool ServiceProcessState::RemoveFromAutoRun() { 215 bool ServiceProcessState::RemoveFromAutoRun() {
71 NOTIMPLEMENTED(); 216 NOTIMPLEMENTED();
72 return false; 217 return false;
73 } 218 }
74 219
75 void ServiceProcessState::TearDownState() { 220 void ServiceProcessState::TearDownState() {
221 g_signal_socket = -1;
222 if (state_) {
223 if (state_->sockets_[0] != -1) {
224 close(state_->sockets_[0]);
225 }
226 if (state_->sockets_[1] != -1) {
227 close(state_->sockets_[1]);
228 }
229 if (state_->set_action_) {
230 if (sigaction(SIGTERM, &state_->old_action_, NULL) < 0) {
231 PLOG(ERROR) << "sigaction";
232 }
233 }
234 state_->Release();
235 state_ = NULL;
236 }
76 } 237 }
77
78 bool ServiceProcessState::ShouldHandleOtherVersion() {
79 // On POSIX, the shared memory is a file in disk. We may have a stale file
80 // lying around from a previous run. So the check is not reliable.
81 return false;
82 }
83
OLDNEW
« no previous file with comments | « chrome/common/service_process_util.cc ('k') | chrome/common/service_process_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698