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

Side by Side Diff: base/zygote_manager.cc

Issue 115773: Prototype implementation of zygotes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 6 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 | « base/zygote_manager.h ('k') | base/zygote_manager_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
(Empty)
1 // Copyright (c) 2006-2009 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 "base/zygote_manager.h"
6
7 #if defined(OS_LINUX)
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <poll.h>
12 #include <stdlib.h>
13 #include <sys/file.h> // for flock()
14 #include <sys/stat.h>
15 #include <sys/uio.h> // for struct iovec
16 #include <sys/wait.h>
17 #include <unistd.h> // for ssize_t
18
19 #include <string>
20
21 #include "base/eintr_wrapper.h"
22 #include "base/file_descriptor_shuffle.h"
23 #include "base/file_util.h"
24 #include "base/logging.h"
25 #include "base/process_util.h"
26 #include "base/reserved_file_descriptors.h"
27 #include "base/singleton.h"
28
29 using file_util::Delete;
30
31 // See comment below, where sigaction is called.
32 static void SIGCHLDHandler(int signal) {
33 }
34
35 namespace base {
36
37 const char ZygoteManager::kZMagic[] = "zygo";
38
39 ZygoteManager::~ZygoteManager() {
40 if (server_fd_ != -1) {
41 close(server_fd_);
42 server_fd_ = -1;
43 }
44 if (client_fd_ != -1) {
45 close(client_fd_);
46 client_fd_ = -1;
47 }
48 if (lockfd_ != -1) {
49 close(lockfd_);
50 lockfd_ = -1;
51 }
52 if (canary_fd_ != -1) {
53 // Wake up the poll() in ReadAndHandleMessage()
54 close(canary_fd_);
55 canary_fd_ = -1;
56 }
57 }
58
59 // Runs in client process
60 ZygoteManager* ZygoteManager::Get() {
61 static bool checked = false;
62 static bool enabled = false;
63 if (!checked) {
64 enabled = (getenv("ENABLE_ZYGOTE_MANAGER") != NULL);
65 // sanity check - make sure all the places that relaunch chrome
66 // have been zygotified.
67 if (enabled)
68 DCHECK(getenv("ZYGOTE_MANAGER_STARTED") == NULL)
69 << "fork/exec used instead of LongFork";
70 (void) setenv("ZYGOTE_MANAGER_STARTED", "1", 1);
71 checked = true;
72 }
73 if (!enabled)
74 return NULL;
75 return Singleton<ZygoteManager>::get();
76 }
77
78 // Runs in zygote manager process
79 int ZygoteManager::UnpickleHeader(const Pickle& reply, void** iter) {
80 std::string magic;
81 if (!reply.ReadString(iter, &magic) || magic != std::string(kZMagic)) {
82 LOG(ERROR) << "reply didn't start with " << kZMagic;
83 return ZMBAD;
84 }
85 pid_t clientpid = (pid_t) -1;
86 if (!reply.ReadInt(iter, &clientpid)) {
87 LOG(ERROR) << "Can't read client pid";
88 return ZMBAD;
89 }
90 if (clientpid != getpid()) {
91 LOG(ERROR) << "got client pid " << clientpid << ", expected " << getpid();
92 DCHECK(clientpid == getpid());
93 return ZMBAD;
94 }
95 int kind;
96 if (!reply.ReadInt(iter, &kind)) {
97 LOG(ERROR) << "can't read kind";
98 return ZMBAD;
99 }
100 return kind;
101 }
102
103 // Runs in client process (only used in unit test)
104 bool ZygoteManager::Ping(base::TimeDelta* delta) {
105 if (client_fd_ == -1)
106 return false;
107
108 Pickle pickle;
109 pickle.WriteString(kZMagic);
110 pickle.WriteInt(getpid());
111 pickle.WriteInt(ZMPING);
112
113 int bytes_sent;
114 int bytes_read = -1;
115
116 TimeTicks time_sent = TimeTicks::HighResNow();
117
118 // Lock fork server, send the pickle, wait for the reply, unlock
119 if (flock(lockfd_, LOCK_EX))
120 LOG(ERROR) << "flock failed, errno " << errno;
121 bytes_sent = HANDLE_EINTR(write(client_fd_,
122 const_cast<void *>(pickle.data()), pickle.size()));
123 if (bytes_sent > 0) {
124 bytes_read = HANDLE_EINTR(read(client_fd_, msg_buf_, kMAX_MSG_LEN));
125 }
126 if (flock(lockfd_, LOCK_UN))
127 LOG(ERROR) << "flock failed, errno " << errno;
128
129 TimeTicks time_received = TimeTicks::HighResNow();
130
131 if (bytes_sent < 1) {
132 LOG(ERROR) << "Can't send to zm, errno " << errno;
133 return false;
134 }
135 if (bytes_read < 1) {
136 LOG(ERROR) << "Can't get from zm, errno " << errno;
137 return false;
138 }
139
140 // Unpickle the reply
141 Pickle reply(msg_buf_, bytes_read);
142 void* iter = NULL;
143 int kind = UnpickleHeader(reply, &iter);
144 if (kind != ZMPINGED) {
145 LOG(ERROR) << "reply wrong kind " << kind;
146 return false;
147 }
148 *delta = TimeTicks::HighResNow() - time_sent;
149 LOG(INFO) << "Round trip time in microseconds: " << delta->InMicroseconds();
150 return true;
151 }
152
153 // Runs in zygote manager process
154 void ZygoteManager::PingHandler(const Pickle& request, void* iter,
155 Pickle* reply, std::vector<std::string>** newargv) {
156 reply->WriteInt(ZMPINGED);
157 }
158
159 // Runs in browser process, called only by base::ForkApp()
160 pid_t ZygoteManager::LongFork(const std::vector<std::string>& argv,
161 const file_handle_mapping_vector& fds_to_remap) {
162 if (client_fd_ == -1)
163 return -1;
164
165 Pickle pickle;
166
167 // Encode the arguments and the desired remote fd numbers in the pickle,
168 // and the fds in a separate buffer
169 pickle.WriteString(kZMagic);
170 pickle.WriteInt(getpid());
171 pickle.WriteInt(ZMFORK);
172 pickle.WriteInt(argv.size());
173 std::vector<std::string>::const_iterator argi;
174 for (argi = argv.begin(); argi != argv.end(); ++argi)
175 pickle.WriteString(*argi);
176 pickle.WriteInt(fds_to_remap.size());
177
178 // Wrap the pickle and the fds together in a msghdr
179 ::msghdr msg;
180 memset(&msg, 0, sizeof(msg));
181 struct iovec iov;
182 msg.msg_iov = &iov;
183 msg.msg_iovlen = 1;
184 msg.msg_control = cmsg_buf_;
185 msg.msg_controllen = CMSG_LEN(sizeof(int) * fds_to_remap.size());
186 struct cmsghdr* cmsg;
187 cmsg = CMSG_FIRSTHDR(&msg);
188 cmsg->cmsg_level = SOL_SOCKET;
189 cmsg->cmsg_type = SCM_RIGHTS;
190 cmsg->cmsg_len = msg.msg_controllen;
191 int* wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
192 for (size_t i = 0; i < fds_to_remap.size(); i++) {
193 pickle.WriteInt(fds_to_remap[i].second);
194 wire_fds[i] = fds_to_remap[i].first;
195 }
196 iov.iov_base = const_cast<void *>(pickle.data());
197 iov.iov_len = pickle.size();
198
199 int bytes_sent;
200 int bytes_read = -1;
201
202 // Lock fork server, send the pickle, wait for the reply, unlock
203 if (flock(lockfd_, LOCK_EX))
204 LOG(ERROR) << "flock failed, errno " << errno;
205 bytes_sent = HANDLE_EINTR(sendmsg(client_fd_, &msg, MSG_WAITALL));
206 if (bytes_sent > 0) {
207 bytes_read = HANDLE_EINTR(read(client_fd_, msg_buf_, kMAX_MSG_LEN));
208 }
209 if (flock(lockfd_, LOCK_UN))
210 LOG(ERROR) << "flock failed, errno " << errno;
211
212 if (bytes_sent < 1) {
213 LOG(ERROR) << "Can't send to zm, errno " << errno << ", fd " << client_fd_;
214 return (pid_t) -1;
215 }
216 if (bytes_read < 1) {
217 LOG(ERROR) << "Can't get from zm, errno " << errno;
218 return (pid_t) -1;
219 }
220
221 // Unpickle the reply
222 Pickle reply(msg_buf_, bytes_read);
223 void* iter = NULL;
224 int kind = UnpickleHeader(reply, &iter);
225 if (kind != ZMFORKED) {
226 LOG(ERROR) << "reply wrong kind " << kind;
227 return (pid_t) -1;
228 }
229 pid_t newpid = (pid_t) -1;
230 int pid_errno;
231 if (!reply.ReadInt(&iter, &newpid) || !reply.ReadInt(&iter, &pid_errno)) {
232 LOG(ERROR) << "fork failed, can't read pid/errno";
233 return (pid_t) -1;
234 }
235 if ((newpid == (pid_t) -1) || pid_errno != 0) {
236 LOG(ERROR) << "fork failed, pid " << newpid << ", errno " << pid_errno;
237 return (pid_t) -1;
238 }
239 return newpid;
240 }
241
242 // Runs in zygote manager process
243 bool ZygoteManager::LongForkHandler(const Pickle& request, void* iter,
244 Pickle* reply, std::vector<std::string>** newargv,
245 const int wire_fds[], int num_wire_fds) {
246 file_handle_mapping_vector fds_to_remap;
247 pid_t childpid;
248
249 reply->WriteInt(ZMFORKED);
250
251 // Unpickle commandline for new child
252 std::vector<std::string>* argv = new std::vector<std::string>;
253 int argc;
254 request.ReadInt(&iter, &argc);
255 for (int i = 0; i < argc; i++) {
256 std::string arg;
257 if (!request.ReadString(&iter, &arg)) {
258 LOG(ERROR) << "can't read arg?";
259 goto error_reply;
260 }
261 argv->push_back(arg);
262 }
263 // Unpickle file descriptor map for new child
264 int numfds;
265 request.ReadInt(&iter, &numfds);
266 DCHECK(numfds == num_wire_fds);
267 if (numfds != num_wire_fds) {
268 LOG(ERROR) << "numfds " << numfds << " != num_wire_fds " << num_wire_fds;
269 goto error_reply;
270 }
271 for (int i = 0; i < numfds; i++) {
272 int fd;
273 if (!request.ReadInt(&iter, &fd)) {
274 LOG(ERROR) << "can't read fd?";
275 goto error_reply;
276 }
277 fds_to_remap.push_back(std::pair<int, int>(wire_fds[i], fd));
278 }
279
280 // Mitosis!
281 childpid = fork();
282
283 if (childpid != 0) {
284 // parent
285 // first off, close our copy of the child's file descriptors
286 for (file_handle_mapping_vector::const_iterator
287 it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
288 close(it->first);
289 }
290
291 // Finish formatting the reply
292 reply->WriteInt(childpid);
293 if (childpid == (pid_t) -1) {
294 reply->WriteInt(errno);
295 return false;
296 } else {
297 reply->WriteInt(0);
298 }
299 } else {
300 // child
301 // Apply file descriptor map
302 InjectiveMultimap fd_shuffle;
303 for (file_handle_mapping_vector::const_iterator
304 it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
305 fd_shuffle.push_back(InjectionArc(it->first, it->second, false));
306 }
307
308 // Avoid closing descriptor children will need to contact fork server.
309 fd_shuffle.push_back(InjectionArc(client_fd_, client_fd_, false));
310 // Avoid closing log descriptor we're using
311 int logfd = logging::GetLoggingFileDescriptor();
312 if (logfd != -1)
313 fd_shuffle.push_back(InjectionArc(logfd, logfd, false));
314 // And of course avoid closing the cached fds.
315 std::map<std::string, int>::iterator i;
316 for (i = cached_fds_.begin(); i != cached_fds_.end(); ++i) {
317 fd_shuffle.push_back(InjectionArc(i->second, i->second, false));
318 }
319
320 // If there is any clash in the mapping, this function will DCHECK.
321 if (!ShuffleFileDescriptors(fd_shuffle))
322 exit(127);
323
324 // Open this after shuffle to avoid using reserved slots.
325 lockfd_ = open(lockfile_.c_str(), O_RDWR, 0);
326 if (lockfd_ == -1) {
327 // TODO(dkegel): real error handling
328 exit(126);
329 }
330 // Mark it as not to be closed.
331 fd_shuffle.push_back(InjectionArc(lockfd_, lockfd_, false));
332
333 // Also closes reserved fds.
334 CloseSuperfluousFds(fd_shuffle);
335
336 *newargv = argv;
337 // Because *newargv is set, we will return to main instead of looping
338 }
339 return true;
340
341 error_reply:
342 reply->WriteInt(-1);
343 reply->WriteInt(-1);
344 for (int i=0; i<num_wire_fds; i++)
345 close(wire_fds[i]);
346 return false;
347 }
348
349 // Runs in browser process, called by ProcessWatcher::EnsureProcessTerminated().
350 void ZygoteManager::EnsureProcessTerminated(pid_t childpid) {
351 if (client_fd_ == -1)
352 return;
353
354 Pickle pickle;
355
356 pickle.WriteString(kZMagic);
357 pickle.WriteInt(getpid());
358 pickle.WriteInt(ZMREAP);
359 pickle.WriteInt(childpid);
360
361 int bytes_sent = HANDLE_EINTR(
362 write(client_fd_, const_cast<void*>(pickle.data()), pickle.size()));
363
364 if (bytes_sent < 1) {
365 LOG(ERROR) << "Can't send to zm, errno " << errno << ", fd " << client_fd_;
366 }
367 }
368
369 // Runs in zygote manager process
370 void ZygoteManager::EnsureProcessTerminatedHandler(const Pickle& request,
371 void* iter) {
372 pid_t childpid;
373 request.ReadInt(&iter, &childpid);
374 NOTIMPLEMENTED();
375 // TODO(dkegel): put childpid on a watch list, and terminate it
376 // after a while as chrome/common/process_watcher does.
377 }
378
379 static bool ValidateFilename(const std::string& filename) {
380 // We only have to open one kind of file, but we don't know
381 // the directory it's in, so be as restrictive as we can within
382 // those bounds.
383
384 static const char* allowed_prefix = "/";
385 if (filename.compare(0, strlen(allowed_prefix), allowed_prefix) != 0) {
386 LOG(ERROR) << "filename did not start with " << allowed_prefix;
387 return false;
388 }
389 static const char* allowed_suffix = ".pak";
390 if ((filename.length() <= strlen(allowed_suffix)) ||
391 (filename.compare(filename.length() - strlen(allowed_suffix),
392 strlen(allowed_suffix), allowed_suffix) != 0)) {
393 LOG(ERROR) << "filename did not end in " << allowed_suffix;
394 return false;
395 }
396 if (filename.find("../") != std::string::npos) {
397 LOG(ERROR) << "filename contained relative component";
398 return false;
399 }
400 static const char* forbidden_prefixes[] = {
401 "/var/", "/tmp/", "/etc/", "/dev/", "/proc/", 0 };
402 for (const char** p = forbidden_prefixes;
403 *p; p++) {
404 if (filename.compare(0, strlen(*p), *p) == 0) {
405 LOG(ERROR) << "filename began with " << *p;
406 return false;
407 }
408 }
409 return true;
410 }
411
412 // Runs in browser process
413 int ZygoteManager::OpenFile(const std::string& filename) {
414 // For security reasons, we only support .pak files,
415 // and only in certain locations.
416 if (!ValidateFilename(filename)) {
417 LOG(INFO) << "ZygoteManager: filename " << filename << " disallowed.";
418 return -1;
419 }
420
421 std::map<std::string, int>::iterator mapiter = cached_fds_.find(filename);
422 if (mapiter != cached_fds_.end())
423 return mapiter->second;
424
425 if (client_fd_ == -1)
426 return -1;
427
428 Pickle pickle;
429
430 pickle.WriteString(kZMagic);
431 pickle.WriteInt(getpid());
432 pickle.WriteInt(ZMOPEN);
433 pickle.WriteString(filename);
434
435 // Get ready to receive fds
436 ::msghdr msg = {0};
437 struct iovec iov = {msg_buf_, kMAX_MSG_LEN};
438 msg.msg_iov = &iov;
439 msg.msg_iovlen = 1;
440 msg.msg_control = cmsg_buf_;
441 msg.msg_controllen = kMAX_CMSG_LEN;
442
443 ssize_t bytes_sent;
444 ssize_t bytes_read = 0;
445
446 if (flock(lockfd_, LOCK_EX))
447 LOG(ERROR) << "flock failed, errno " << errno;
448 bytes_sent = HANDLE_EINTR(
449 write(client_fd_, const_cast<void *>(pickle.data()), pickle.size()));
450 if (bytes_sent > 0) {
451 bytes_read = HANDLE_EINTR(recvmsg(client_fd_, &msg, MSG_WAITALL));
452 }
453 if (flock(lockfd_, LOCK_UN))
454 LOG(ERROR) << "flock failed, errno " << errno;
455
456 if (bytes_sent < 1) {
457 LOG(ERROR) << "Can't send to zm, errno " << errno << ", fd " << client_fd_;
458 return -1;
459 }
460 if (bytes_read < 1) {
461 LOG(ERROR) << "Can't get from zm, errno " << errno;
462 return -1;
463 }
464
465 // Locate the sole block of sent file descriptors within the list of
466 // control messages
467 const int* wire_fds = NULL;
468 unsigned num_wire_fds = 0;
469 if (msg.msg_controllen > 0) {
470 struct cmsghdr* cmsg;
471 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
472 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
473 if (cmsg->cmsg_level == SOL_SOCKET &&
474 cmsg->cmsg_type == SCM_RIGHTS) {
475 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
476 assert(payload_len % sizeof(int) == 0);
477 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
478 num_wire_fds = payload_len / sizeof(int);
479 break;
480 }
481 }
482 }
483 DCHECK(!(msg.msg_flags & MSG_CTRUNC));
484
485 // Unpickle the reply
486 Pickle reply(msg_buf_, bytes_read);
487 void* iter = NULL;
488 int kind = UnpickleHeader(reply, &iter);
489 if (kind != ZMOPENED) {
490 LOG(ERROR) << "reply wrong kind " << kind;
491 goto error_close;
492 }
493 int newfd_errno;
494 if (!reply.ReadInt(&iter, &newfd_errno)) {
495 LOG(ERROR) << "open failed, can't read errno";
496 goto error_close;
497 }
498 if (newfd_errno != 0) {
499 LOG(ERROR) << "open failed, errno " << newfd_errno;
500 goto error_close;
501 }
502 if (num_wire_fds != 1) {
503 LOG(ERROR) << "open failed, reply wrong number fds " << num_wire_fds;
504 goto error_close;
505 }
506 if (wire_fds[0] == -1) {
507 LOG(ERROR) << "open failed, fd -1";
508 NOTREACHED();
509 return -1;
510 }
511 return wire_fds[0];
512
513 error_close:
514 for (unsigned i=0; i<num_wire_fds; i++)
515 close(wire_fds[i]);
516 return -1;
517 }
518
519 // Runs in zygote manager process
520 bool ZygoteManager::OpenFileHandler(const Pickle& request, void* iter,
521 Pickle* reply, ::msghdr* msg) {
522 reply->WriteInt(ZMOPENED);
523
524 std::string filename;
525 if (!request.ReadString(&iter, &filename)) {
526 LOG(ERROR) << "no filename?";
527 return false;
528 }
529 if (!ValidateFilename(filename)) {
530 // Fake a unix error code
531 reply->WriteInt(EPERM);
532 return false;
533 }
534
535 std::map<std::string, int>::iterator i;
536 int newfd;
537 std::map<std::string, int>::iterator mapiter = cached_fds_.find(filename);
538 if (mapiter == cached_fds_.end()) {
539 // Verify that file is a plain file
540 struct stat statbuf;
541 if (lstat(filename.c_str(), &statbuf) != 0) {
542 LOG(ERROR) << "can't stat " << filename << ", errno " << errno;
543 return false;
544 }
545 if (!S_ISREG(statbuf.st_mode)) {
546 LOG(ERROR) << "not regular file " << filename;
547 // Fake a unix error code
548 reply->WriteInt(EISDIR);
549 return false;
550 }
551 newfd = open(filename.c_str(), O_RDONLY, 0);
552 if (newfd != -1) {
553 cached_fds_[filename] = newfd;
554 } else {
555 LOG(ERROR) << "can't open " << filename << ", errno " << errno;
556 }
557 } else {
558 newfd = mapiter->second;
559 }
560 if (newfd == -1) {
561 reply->WriteInt(errno);
562 } else {
563 reply->WriteInt(0);
564 msg->msg_control = cmsg_buf_;
565 msg->msg_controllen = CMSG_LEN(sizeof(int));
566 struct cmsghdr* cmsg;
567 cmsg = CMSG_FIRSTHDR(msg);
568 cmsg->cmsg_level = SOL_SOCKET;
569 cmsg->cmsg_type = SCM_RIGHTS;
570 cmsg->cmsg_len = msg->msg_controllen;
571 int* wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
572 wire_fds[0] = newfd;
573 }
574
575 return true;
576 }
577
578 // Runs in zygote manager process
579 bool ZygoteManager::ReadAndHandleMessage(std::vector<std::string>** newargv) {
580 // Wait for activity either on canary fd or main fd.
581 struct pollfd watcher[2];
582 memset(watcher, 0, sizeof(watcher));
583 watcher[0].fd = canary_fd_;
584 watcher[0].events = POLLIN|POLLHUP;
585 watcher[1].fd = server_fd_;
586 watcher[1].events = POLLIN;
587 // Wait at most one minute. This lets us detect case where
588 // canary socket is closed abruptly because the main client aborted.
589 // Also lets us reap dead children once a minute even if we don't get SIGCHLD.
590 // We'd like to wait less time, but that's hard on battery life.
591 // Note: handle EINTR manually here, not with wrapper, as we need
592 // to return when we're interrupted so caller can reap promptly.
593 int nactive = poll(watcher, 2, 60*1000);
594
595 if (nactive == -1) {
596 if (errno == EINTR) {
597 LOG(INFO) << "poll interrupted";
598 // Probably SIGCHLD. Return to main loop so it can reap.
599 return true;
600 }
601 LOG(ERROR) << "poll failed, errno " << errno << ", aborting";
602 return false;
603 }
604
605 // If it was the canary, exit
606 if (watcher[0].revents != 0) {
607 LOG(INFO) << "notified of peer destruction, exiting";
608 return false;
609 }
610 if ((watcher[1].revents & POLLIN) != POLLIN) {
611 // spurious wakeup?
612 return true;
613 }
614
615 ssize_t bytes_read = 0;
616 struct msghdr msg = {0};
617 struct iovec iov = {msg_buf_, kMAX_MSG_LEN};
618 msg.msg_iov = &iov;
619 msg.msg_iovlen = 1;
620 msg.msg_control = cmsg_buf_;
621 msg.msg_controllen = kMAX_CMSG_LEN;
622 bytes_read = HANDLE_EINTR(recvmsg(server_fd_, &msg, MSG_WAITALL));
623 if (bytes_read == 0) {
624 LOG(ERROR) << "got EOF, aborting";
625 return false;
626 }
627 if (bytes_read == -1) {
628 LOG(ERROR) << "got errno " << errno << ", aborting";
629 return false;
630 }
631
632 // Locate the sole block of sent file descriptors within the list of
633 // control messages
634 const int* wire_fds = NULL;
635 unsigned num_wire_fds = 0;
636 if (msg.msg_controllen > 0) {
637 struct cmsghdr* cmsg;
638 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
639 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
640 if (cmsg->cmsg_level == SOL_SOCKET &&
641 cmsg->cmsg_type == SCM_RIGHTS) {
642 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
643 assert(payload_len % sizeof(int) == 0);
644 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
645 num_wire_fds = payload_len / sizeof(int);
646 break;
647 }
648 }
649 }
650 DCHECK(!(msg.msg_flags & MSG_CTRUNC));
651
652 // Unpickle/parse message
653 Pickle pickle(msg_buf_, bytes_read);
654 void* iter = NULL;
655 std::string magic;
656 if (!pickle.ReadString(&iter, &magic) || magic != std::string(kZMagic)) {
657 LOG(ERROR) << "msg didn't start with " << kZMagic << ", got " << magic;
658 for (unsigned i=0; i<num_wire_fds; i++)
659 close(wire_fds[i]);
660 return true;
661 }
662 pid_t clientpid = (pid_t) -1;
663 pickle.ReadInt(&iter, &clientpid);
664 int kind;
665 pickle.ReadInt(&iter, &kind);
666
667 Pickle reply;
668 reply.WriteString(kZMagic);
669 reply.WriteInt(clientpid);
670
671 struct msghdr replymsg = {0};
672 memset(&replymsg, 0, sizeof(replymsg));
673
674 switch (kind) {
675 case ZMPING:
676 DCHECK_EQ(0U, num_wire_fds);
677 PingHandler(pickle, iter, &reply, newargv);
678 break;
679 case ZMFORK:
680 // TODO(dkegel): real error handling
681 (void) LongForkHandler(pickle, iter, &reply, newargv, wire_fds,
682 num_wire_fds);
683 if (*newargv != NULL) {
684 // Child. Just return to caller, who will return from SetLongFork.
685 return true;
686 }
687 break;
688 case ZMREAP:
689 DCHECK_EQ(0U, num_wire_fds);
690 EnsureProcessTerminatedHandler(pickle, iter);
691 // no reply to this message
692 return true;
693 case ZMOPEN:
694 DCHECK_EQ(0U, num_wire_fds);
695 // TODO(dkegel): real error handling
696 (void) OpenFileHandler(pickle, iter, &reply, &replymsg);
697 break;
698 default:
699 // TODO(dkegel): real error handling
700 LOG(ERROR) << "Unknown message kind " << kind;
701 DCHECK_EQ(0U, num_wire_fds);
702 break;
703 }
704
705 struct iovec riov = {const_cast<void *>(reply.data()), reply.size()};
706 replymsg.msg_iov = &riov;
707 replymsg.msg_iovlen = 1;
708
709 int bytes_sent;
710 bytes_sent = HANDLE_EINTR(sendmsg(server_fd_, &replymsg, MSG_WAITALL));
711 if (bytes_sent != static_cast<int>(riov.iov_len)) {
712 // TODO(dkegel): real error handling
713 LOG(ERROR) << "Can't send reply.";
714 return false;
715 }
716 return true;
717 }
718
719 // Called only by ChromeMain(), forks the zygote manager process.
720 std::vector<std::string>* ZygoteManager::Start() {
721 DCHECK(lockfd_ == -1);
722 DCHECK(canary_fd_ == -1);
723 DCHECK(server_fd_ == -1);
724 DCHECK(client_fd_ == -1);
725
726 int pipe_fds[2];
727
728 // Avoid using the reserved fd slots.
729 int reserved_fds[kReservedFds];
730 for (int i=0; i < kReservedFds; i++)
731 reserved_fds[i] = open("/dev/null", O_RDONLY, 0);
732
733 // Create the main communications pipe.
734 int err = HANDLE_EINTR(socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fds));
735 if (err != 0) {
736 // TODO(dkegel): real error handling
737 exit(99);
738 }
739 server_fd_ = pipe_fds[1];
740 client_fd_ = pipe_fds[0];
741
742 // Create the pipe used only to relay destruction event server.
743 // Must be SOCK_STREAM so close() is sensed by poll().
744 err = HANDLE_EINTR(socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds));
745 if (err != 0) {
746 // TODO(dkegel): real error handling
747 exit(99);
748 }
749
750 // Create lock file.
751 // TODO(dkegel): get rid of this
752 char lockfile[256];
753 strcpy(lockfile, "/tmp/zygote_manager_lock.XXXXXX");
754 lockfd_ = mkstemp(lockfile);
755 if (lockfd_ == -1) {
756 // TODO(dkegel): real error handling
757 exit(99);
758 }
759 lockfile_.assign(lockfile);
760
761 // Fork a fork server.
762 pid_t childpid = fork();
763
764 if (childpid) {
765 for (int i=0; i < kReservedFds; i++)
766 close(reserved_fds[i]);
767
768 // Original parent. Continues on with the main program
769 // and becomes the first client.
770 close(server_fd_);
771 server_fd_ = -1;
772
773 close(pipe_fds[1]);
774 canary_fd_ = pipe_fds[0];
775
776 // Return now to indicate this is the original process.
777 return NULL;
778 } else {
779 close(lockfd_);
780
781 close(pipe_fds[0]);
782 canary_fd_ = pipe_fds[1];
783
784 // We need to accept SIGCHLD, even though our handler is a no-op because
785 // otherwise we cannot wait on children. (According to POSIX 2001.)
786 // (And otherwise poll() might not wake up on SIGCHLD.)
787 struct sigaction action;
788 memset(&action, 0, sizeof(action));
789 action.sa_handler = SIGCHLDHandler;
790 CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
791
792 // Original child. Acts as the server.
793 while (true) {
794 std::vector<std::string>* newargv = NULL;
795 if (!ReadAndHandleMessage(&newargv))
796 break;
797 if (newargv) {
798 // Return new commandline to show caller this is a new child process.
799 return newargv;
800 }
801 // Server process continues around loop.
802
803 // Reap children.
804 while (true) {
805 int status = -1;
806 pid_t reaped = waitpid(-1, &status, WNOHANG);
807 if (reaped != -1 && reaped != 0) {
808 LOG(INFO) << "Reaped pid " << reaped;
809 continue;
810 }
811 break;
812 }
813 }
814 // Server cleanup after EOF or error reading from the socket.
815 // Chrome doesn't seem to get here in practice.
816 Delete(FilePath(lockfile_), false);
817 // TODO(dkegel): real error handling
818 LOG(INFO) << "exiting. " << cached_fds_.size() << " cached fds.";
819 std::map<std::string, int>::iterator i;
820 for (i = cached_fds_.begin(); i != cached_fds_.end(); ++i) {
821 LOG(INFO) << "Closing fd " << i->second << " filename " << i->first;
822 close(i->second);
823 }
824 exit(-1);
825 }
826 }
827 }
828 #endif // defined(OS_LINUX)
OLDNEW
« no previous file with comments | « base/zygote_manager.h ('k') | base/zygote_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698