| OLD | NEW |
| 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 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 | 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 "base/zygote_manager.h" | 5 #include "base/zygote_manager.h" |
| 6 | 6 |
| 7 #if defined(OS_LINUX) | 7 #if defined(OS_LINUX) |
| 8 | 8 |
| 9 #include <errno.h> | 9 #include <errno.h> |
| 10 #include <fcntl.h> | 10 #include <fcntl.h> |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 } | 47 } |
| 48 if (lockfd_ != -1) { | 48 if (lockfd_ != -1) { |
| 49 close(lockfd_); | 49 close(lockfd_); |
| 50 lockfd_ = -1; | 50 lockfd_ = -1; |
| 51 } | 51 } |
| 52 if (canary_fd_ != -1) { | 52 if (canary_fd_ != -1) { |
| 53 // Wake up the poll() in ReadAndHandleMessage() | 53 // Wake up the poll() in ReadAndHandleMessage() |
| 54 close(canary_fd_); | 54 close(canary_fd_); |
| 55 canary_fd_ = -1; | 55 canary_fd_ = -1; |
| 56 } | 56 } |
| 57 #ifndef OFFICIAL_BUILD |
| 58 // Closing the canary kills the server, |
| 59 // so after this it's ok for e.g. unit tests |
| 60 // to start a new zygote server. |
| 61 (void) unsetenv("ZYGOTE_MANAGER_STARTED"); |
| 62 #endif |
| 57 } | 63 } |
| 58 | 64 |
| 59 // Runs in client process | 65 // Runs in client process |
| 60 ZygoteManager* ZygoteManager::Get() { | 66 ZygoteManager* ZygoteManager::Get() { |
| 61 static bool checked = false; | 67 static bool checked = false; |
| 62 static bool enabled = false; | 68 static bool enabled = false; |
| 63 if (!checked) { | 69 if (!checked) { |
| 64 enabled = (getenv("ENABLE_ZYGOTE_MANAGER") != NULL); | 70 enabled = (getenv("DISABLE_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; | 71 checked = true; |
| 72 } | 72 } |
| 73 if (!enabled) | 73 if (!enabled) |
| 74 return NULL; | 74 return NULL; |
| 75 return Singleton<ZygoteManager>::get(); | 75 return Singleton<ZygoteManager>::get(); |
| 76 } | 76 } |
| 77 | 77 |
| 78 // Runs in zygote manager process | 78 // Runs in zygote manager process |
| 79 int ZygoteManager::UnpickleHeader(const Pickle& reply, void** iter) { | 79 int ZygoteManager::UnpickleHeader(const Pickle& reply, void** iter) { |
| 80 std::string magic; | 80 std::string magic; |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 // Wait at most one minute. This lets us detect case where | 587 // Wait at most one minute. This lets us detect case where |
| 588 // canary socket is closed abruptly because the main client aborted. | 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. | 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. | 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 | 591 // Note: handle EINTR manually here, not with wrapper, as we need |
| 592 // to return when we're interrupted so caller can reap promptly. | 592 // to return when we're interrupted so caller can reap promptly. |
| 593 int nactive = poll(watcher, 2, 60*1000); | 593 int nactive = poll(watcher, 2, 60*1000); |
| 594 | 594 |
| 595 if (nactive == -1) { | 595 if (nactive == -1) { |
| 596 if (errno == EINTR) { | 596 if (errno == EINTR) { |
| 597 LOG(INFO) << "poll interrupted"; | |
| 598 // Probably SIGCHLD. Return to main loop so it can reap. | 597 // Probably SIGCHLD. Return to main loop so it can reap. |
| 599 return true; | 598 return true; |
| 600 } | 599 } |
| 601 LOG(ERROR) << "poll failed, errno " << errno << ", aborting"; | 600 LOG(ERROR) << "poll failed, errno " << errno << ", aborting"; |
| 602 return false; | 601 return false; |
| 603 } | 602 } |
| 604 | 603 |
| 605 // If it was the canary, exit | 604 // If it was the canary, exit |
| 606 if (watcher[0].revents != 0) { | 605 if (watcher[0].revents != 0) { |
| 607 LOG(INFO) << "notified of peer destruction, exiting"; | 606 LOG(INFO) << "notified of peer destruction, exiting"; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 return true; | 715 return true; |
| 717 } | 716 } |
| 718 | 717 |
| 719 // Called only by ChromeMain(), forks the zygote manager process. | 718 // Called only by ChromeMain(), forks the zygote manager process. |
| 720 std::vector<std::string>* ZygoteManager::Start() { | 719 std::vector<std::string>* ZygoteManager::Start() { |
| 721 DCHECK(lockfd_ == -1); | 720 DCHECK(lockfd_ == -1); |
| 722 DCHECK(canary_fd_ == -1); | 721 DCHECK(canary_fd_ == -1); |
| 723 DCHECK(server_fd_ == -1); | 722 DCHECK(server_fd_ == -1); |
| 724 DCHECK(client_fd_ == -1); | 723 DCHECK(client_fd_ == -1); |
| 725 | 724 |
| 725 #ifndef OFFICIAL_BUILD |
| 726 // Disallow nested ZygoteManager servers |
| 727 CHECK(getenv("ZYGOTE_MANAGER_STARTED") == NULL) << "already started?!"; |
| 728 (void) setenv("ZYGOTE_MANAGER_STARTED", "1", 1); |
| 729 #endif |
| 730 |
| 726 int pipe_fds[2]; | 731 int pipe_fds[2]; |
| 727 | 732 |
| 728 // Avoid using the reserved fd slots. | 733 // Avoid using the reserved fd slots. |
| 729 int reserved_fds[kReservedFds]; | 734 int reserved_fds[kReservedFds]; |
| 730 for (int i=0; i < kReservedFds; i++) | 735 for (int i=0; i < kReservedFds; i++) |
| 731 reserved_fds[i] = open("/dev/null", O_RDONLY, 0); | 736 reserved_fds[i] = open("/dev/null", O_RDONLY, 0); |
| 732 | 737 |
| 733 // Create the main communications pipe. | 738 // Create the main communications pipe. |
| 734 int err = HANDLE_EINTR(socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fds)); | 739 int err = HANDLE_EINTR(socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fds)); |
| 735 if (err != 0) { | 740 if (err != 0) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 754 lockfd_ = mkstemp(lockfile); | 759 lockfd_ = mkstemp(lockfile); |
| 755 if (lockfd_ == -1) { | 760 if (lockfd_ == -1) { |
| 756 // TODO(dkegel): real error handling | 761 // TODO(dkegel): real error handling |
| 757 exit(99); | 762 exit(99); |
| 758 } | 763 } |
| 759 lockfile_.assign(lockfile); | 764 lockfile_.assign(lockfile); |
| 760 | 765 |
| 761 // Fork a fork server. | 766 // Fork a fork server. |
| 762 pid_t childpid = fork(); | 767 pid_t childpid = fork(); |
| 763 | 768 |
| 764 if (childpid) { | 769 if (!childpid) { |
| 765 for (int i=0; i < kReservedFds; i++) | 770 for (int i=0; i < kReservedFds; i++) |
| 766 close(reserved_fds[i]); | 771 close(reserved_fds[i]); |
| 767 | 772 |
| 768 // Original parent. Continues on with the main program | 773 // Original child. Continues on with the main program |
| 769 // and becomes the first client. | 774 // and becomes the first client. |
| 770 close(server_fd_); | 775 close(server_fd_); |
| 771 server_fd_ = -1; | 776 server_fd_ = -1; |
| 772 | 777 |
| 773 close(pipe_fds[1]); | 778 close(pipe_fds[1]); |
| 774 canary_fd_ = pipe_fds[0]; | 779 canary_fd_ = pipe_fds[0]; |
| 775 | 780 |
| 776 // Return now to indicate this is the original process. | 781 // Return now to indicate this is the original process. |
| 777 return NULL; | 782 return NULL; |
| 778 } else { | 783 } else { |
| 779 close(lockfd_); | 784 close(lockfd_); |
| 780 | 785 |
| 781 close(pipe_fds[0]); | 786 close(pipe_fds[0]); |
| 782 canary_fd_ = pipe_fds[1]; | 787 canary_fd_ = pipe_fds[1]; |
| 783 | 788 |
| 784 // We need to accept SIGCHLD, even though our handler is a no-op because | 789 // 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.) | 790 // otherwise we cannot wait on children. (According to POSIX 2001.) |
| 786 // (And otherwise poll() might not wake up on SIGCHLD.) | 791 // (And otherwise poll() might not wake up on SIGCHLD.) |
| 787 struct sigaction action; | 792 struct sigaction action; |
| 788 memset(&action, 0, sizeof(action)); | 793 memset(&action, 0, sizeof(action)); |
| 789 action.sa_handler = SIGCHLDHandler; | 794 action.sa_handler = SIGCHLDHandler; |
| 790 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); | 795 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); |
| 791 | 796 |
| 792 // Original child. Acts as the server. | 797 // Original process. Acts as the server. |
| 793 while (true) { | 798 while (true) { |
| 794 std::vector<std::string>* newargv = NULL; | 799 std::vector<std::string>* newargv = NULL; |
| 795 if (!ReadAndHandleMessage(&newargv)) | 800 if (!ReadAndHandleMessage(&newargv)) |
| 796 break; | 801 break; |
| 797 if (newargv) { | 802 if (newargv) { |
| 798 // Return new commandline to show caller this is a new child process. | 803 // Return new commandline to show caller this is a new child process. |
| 799 return newargv; | 804 return newargv; |
| 800 } | 805 } |
| 801 // Server process continues around loop. | 806 // Server process continues around loop. |
| 802 | 807 |
| 803 // Reap children. | 808 // Reap children. |
| 804 while (true) { | 809 while (true) { |
| 805 int status = -1; | 810 int status = -1; |
| 806 pid_t reaped = waitpid(-1, &status, WNOHANG); | 811 pid_t reaped = waitpid(-1, &status, WNOHANG); |
| 807 if (reaped != -1 && reaped != 0) { | 812 if (reaped != -1 && reaped != 0) { |
| 808 LOG(INFO) << "Reaped pid " << reaped; | 813 LOG(INFO) << "Reaped pid " << reaped; |
| 809 continue; | 814 continue; |
| 810 } | 815 } |
| 811 break; | 816 break; |
| 812 } | 817 } |
| 813 } | 818 } |
| 814 // Server cleanup after EOF or error reading from the socket. | 819 // 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); | 820 Delete(FilePath(lockfile_), false); |
| 817 // TODO(dkegel): real error handling | 821 // TODO(dkegel): real error handling |
| 818 LOG(INFO) << "exiting. " << cached_fds_.size() << " cached fds."; | 822 LOG(INFO) << "exiting. " << cached_fds_.size() << " cached fds."; |
| 819 std::map<std::string, int>::iterator i; | 823 std::map<std::string, int>::iterator i; |
| 820 for (i = cached_fds_.begin(); i != cached_fds_.end(); ++i) { | 824 for (i = cached_fds_.begin(); i != cached_fds_.end(); ++i) { |
| 821 LOG(INFO) << "Closing fd " << i->second << " filename " << i->first; | 825 LOG(INFO) << "Closing fd " << i->second << " filename " << i->first; |
| 822 close(i->second); | 826 close(i->second); |
| 823 } | 827 } |
| 824 exit(-1); | 828 exit(0); |
| 825 } | 829 } |
| 826 } | 830 } |
| 827 } | 831 } |
| 828 #endif // defined(OS_LINUX) | 832 #endif // defined(OS_LINUX) |
| OLD | NEW |