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

Side by Side Diff: tools/android/forwarder2/daemon.cc

Issue 11269036: Support HTTP test-server based net unit tests on Android. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove duplicate include Created 8 years, 1 month 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 | « tools/android/forwarder2/daemon.h ('k') | tools/android/forwarder2/device_controller.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "tools/android/forwarder2/daemon.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <sys/file.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16
17 #include <string>
18
19 #include "base/basictypes.h"
20 #include "base/eintr_wrapper.h"
21 #include "base/file_path.h"
22 #include "base/file_util.h"
23 #include "base/logging.h"
24 #include "base/safe_strerror_posix.h"
25 #include "base/string_number_conversions.h"
26 #include "base/stringprintf.h"
27
28 namespace {
29
30 const char kLogFilePath[] = "/tmp/host_forwarder_log";
digit1 2012/10/29 12:07:32 Generally speaking, it's better to create UID-spec
Philippe 2012/10/30 13:54:37 I see your point. I would like to prevent this use
31
32 void PError(const char* msg) {
33 LOG(ERROR) << msg << ": " << safe_strerror(errno);
34 }
35
36 void CloseFD(int fd) {
37 if (HANDLE_EINTR(close(fd)) < 0)
digit1 2012/10/29 12:07:32 Would you want to preserve errno here?
Philippe 2012/10/30 13:54:37 Good point.
38 PError("close");
39 }
40
41 class FileDescriptorAutoCloser {
42 public:
43 explicit FileDescriptorAutoCloser(int fd) : fd_(fd) {
44 DCHECK(fd_ >= 0);
45 }
46
47 ~FileDescriptorAutoCloser() {
48 if (fd_ > -1)
49 CloseFD(fd_);
50 }
51
52 int Release() {
53 const int fd = fd_;
54 fd_ = -1;
55 return fd;
56 }
57
58 private:
59 int fd_;
60
61 DISALLOW_COPY_AND_ASSIGN(FileDescriptorAutoCloser);
62 };
63
64 // Handles creation and destruction of the PID file.
65 class PIDFile {
66 public:
67 static scoped_ptr<PIDFile> Create(const std::string& path) {
68 scoped_ptr<PIDFile> pid_file;
69 const int pid_file_fd = HANDLE_EINTR(
70 open(path.c_str(), O_CREAT | O_WRONLY, 0600));
71 if (pid_file_fd < 0) {
72 PError("open()");
73 return pid_file.Pass();
74 }
75 FileDescriptorAutoCloser fd_closer(pid_file_fd);
76 if (HANDLE_EINTR(flock(pid_file_fd, LOCK_EX | LOCK_NB)) < 0) {
77 if (errno == EAGAIN || errno == EACCES) {
78 LOG(ERROR) << "Daemon already running (PID file already locked)";
79 return pid_file.Pass();
80 }
81 PError("lockf()");
82 return pid_file.Pass();
83 }
84 const std::string pid_string = base::StringPrintf("%d\n", getpid());
85 CHECK(HANDLE_EINTR(write(pid_file_fd, pid_string.c_str(),
86 pid_string.length())));
87 pid_file.reset(new PIDFile(fd_closer.Release(), path));
88 return pid_file.Pass();
89 }
90
91 ~PIDFile() {
92 CloseFD(fd_); // This also releases the lock.
93 if (remove(path_.c_str()) < 0)
94 PError("remove");
95 }
96
97 private:
98 PIDFile(int fd, const std::string& path) : fd_(fd), path_(path) {
99 DCHECK(fd_ >= 0);
100 }
101
102 const int fd_;
103 const std::string path_;
104
105 DISALLOW_COPY_AND_ASSIGN(PIDFile);
106 };
107
108 // Takes ownership of |data|.
109 void ReleaseDaemonResourcesAtExit(void* data) {
110 DCHECK(data);
111 delete reinterpret_cast<PIDFile*>(data);
112 }
113
114 void InitLogging(const char* log_file) {
115 CHECK(
116 logging::InitLogging(
117 log_file,
118 logging::LOG_ONLY_TO_FILE,
119 logging::DONT_LOCK_LOG_FILE,
120 logging::APPEND_TO_OLD_LOG_FILE,
121 logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS));
122 }
123
124 void SigChildHandler(int signal_number) {
125 DCHECK_EQ(signal_number, SIGCHLD);
126 // The daemon should not terminate while its parent is still running.
127 int status;
128 pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG);
129 if (child_pid < 0) {
130 PError("waitpid");
131 return;
132 }
133 if (child_pid == 0)
134 return;
135 LOG(ERROR) << "Daemon (pid=" << child_pid << ") died unexpectedly with ";
digit1 2012/10/29 12:07:32 I'm not sure you can use LOG() in a signal handler
Philippe 2012/10/30 13:54:37 Good catch, indeed. I added common.{cc,h} that pro
136 if (WIFEXITED(status))
137 LOG(ERROR) << "status " << WEXITSTATUS(status);
138 else if (WIFSIGNALED(status))
139 LOG(ERROR) << "signal " << WTERMSIG(status);
140 else
141 LOG(ERROR) << "unknown reason";
142 }
143
144 } // namespace
145
146 namespace forwarder2 {
147
148 Daemon::Daemon(const std::string& pid_file_path)
149 : pid_file_path_(pid_file_path) {
150 }
151
152 bool Daemon::Spawn(bool* is_daemon) {
153 switch (fork()) {
154 case -1:
155 *is_daemon = false;
156 PError("fork()");
157 return false;
158 case 0: { // Child.
159 *is_daemon = true;
160 scoped_ptr<PIDFile> pid_file = PIDFile::Create(pid_file_path_);
161 if (!pid_file)
162 return false;
163 base::AtExitManager::RegisterCallback(
164 &ReleaseDaemonResourcesAtExit, pid_file.release());
165 if (setsid() < 0) { // Detach the child process from its parent.
166 PError("setsid");
167 return false;
168 }
169 CloseFD(STDOUT_FILENO);
170 CloseFD(STDERR_FILENO);
171 InitLogging(kLogFilePath);
172 break;
173 }
174 default: // Parent.
175 *is_daemon = false;
176 signal(SIGCHLD, SigChildHandler);
177 }
178 return true;
179 }
180
181 bool Daemon::Kill() {
182 std::string pid_string;
183 const FilePath pid_file_path(pid_file_path_);
184 if (!file_util::ReadFileToString(pid_file_path, &pid_string)) {
185 int error = errno;
186 if (file_util::PathExists(pid_file_path)) {
187 LOG(ERROR) << "Could not read file " << pid_file_path_ << ": "
188 << safe_strerror(error);
189 return false;
190 }
191 // Reasonably assume that the daemon is not running.
192 return true;
193 }
194 CHECK(pid_string.length() > 1);
195 // Remove the trailing \n.
196 pid_string.resize(pid_string.length() - 1);
197 pid_t pid;
198 CHECK(base::StringToInt(pid_string, &pid));
199 CHECK_NE(pid, getpid());
200 CHECK_EQ(0, kill(pid, SIGTERM));
201 int pid_file_fd = HANDLE_EINTR(open(pid_file_path_.c_str(), O_WRONLY));
202 if (pid_file_fd < 0) {
203 LOG(ERROR) << "Could not open " << pid_file_path_ << " in write mode: "
204 << safe_strerror(errno);
205 return false;
206 }
207 const FileDescriptorAutoCloser fd_closer(pid_file_fd);
208 // Wait until the daemon exits. Rely on the fact that the daemon releases the
209 // lock on the PID file when it exits.
210 // TODO(pliard): Consider using a mutex + condition in shared memory to avoid
211 // polling.
212 const int kTries = 20;
213 const int kIdleTimeMS = 100;
214 for (int i = 0; i < kTries; ++i) {
215 struct flock lock_info = {};
216 lock_info.l_type = F_WRLCK;
217 lock_info.l_whence = SEEK_CUR;
218 const int ret = HANDLE_EINTR(fcntl(pid_file_fd, F_GETLK, &lock_info));
219 if (ret < 0)
220 PError("fcntl");
221 else if (lock_info.l_type == F_UNLCK)
222 return true;
223 else {
224 CHECK_EQ(F_WRLCK /* exclusive lock */, lock_info.l_type);
225 if (lock_info.l_pid != pid) {
226 LOG(WARNING) << "Daemon (pid=" << pid
227 << ") was successfully killed but a new daemon (pid="
228 << lock_info.l_pid << ") seems to be running now.";
229 return true;
230 }
231 }
232 usleep(kIdleTimeMS * 1000);
233 }
234 LOG(ERROR) << "Timed out while killing daemon. "
235 "It might still be tearing down.";
236 return false;
237 }
238
239 } // namespace forwarder2
OLDNEW
« no previous file with comments | « tools/android/forwarder2/daemon.h ('k') | tools/android/forwarder2/device_controller.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698