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

Side by Side Diff: chrome/browser/process_singleton_posix.cc

Issue 517933002: Speed up and re-enable ProcessSingletonPosixTest tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rename timeout_interval to timeout Created 6 years, 3 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
« no previous file with comments | « chrome/browser/process_singleton.h ('k') | chrome/browser/process_singleton_posix_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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 // On Linux, when the user tries to launch a second copy of chrome, we check 5 // On Linux, when the user tries to launch a second copy of chrome, we check
6 // for a socket in the user's profile directory. If the socket file is open we 6 // for a socket in the user's profile directory. If the socket file is open we
7 // send a message to the first chrome browser process with the current 7 // send a message to the first chrome browser process with the current
8 // directory and second process command line flags. The second process then 8 // directory and second process command line flags. The second process then
9 // exits. 9 // exits.
10 // 10 //
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 #if defined(OS_LINUX) 85 #if defined(OS_LINUX)
86 #include "chrome/browser/ui/process_singleton_dialog_linux.h" 86 #include "chrome/browser/ui/process_singleton_dialog_linux.h"
87 #endif 87 #endif
88 88
89 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS) 89 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
90 #include "ui/views/linux_ui/linux_ui.h" 90 #include "ui/views/linux_ui/linux_ui.h"
91 #endif 91 #endif
92 92
93 using content::BrowserThread; 93 using content::BrowserThread;
94 94
95 const int ProcessSingleton::kTimeoutInSeconds;
96
97 namespace { 95 namespace {
98 96
97 // Timeout for the current browser process to respond. 20 seconds should be
98 // enough.
99 const int kTimeoutInSeconds = 20;
100 // Number of retries to notify the browser. 20 retries over 20 seconds = 1 try
101 // per second.
102 const int kRetryAttempts = 20;
99 static bool g_disable_prompt; 103 static bool g_disable_prompt;
100 const char kStartToken[] = "START"; 104 const char kStartToken[] = "START";
101 const char kACKToken[] = "ACK"; 105 const char kACKToken[] = "ACK";
102 const char kShutdownToken[] = "SHUTDOWN"; 106 const char kShutdownToken[] = "SHUTDOWN";
103 const char kTokenDelimiter = '\0'; 107 const char kTokenDelimiter = '\0';
104 const int kMaxMessageLength = 32 * 1024; 108 const int kMaxMessageLength = 32 * 1024;
105 const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1; 109 const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1;
106 110
107 const char kLockDelimiter = '-'; 111 const char kLockDelimiter = '-';
108 112
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 } 155 }
152 PLOG(ERROR) << "write() failed"; 156 PLOG(ERROR) << "write() failed";
153 return false; 157 return false;
154 } 158 }
155 bytes_written += rv; 159 bytes_written += rv;
156 } while (bytes_written < length); 160 } while (bytes_written < length);
157 161
158 return true; 162 return true;
159 } 163 }
160 164
161 // Wait a socket for read for a certain timeout in seconds. 165 struct timeval TimeDeltaToTimeVal(const base::TimeDelta& delta) {
166 struct timeval result;
167 result.tv_sec = delta.InSeconds();
168 result.tv_usec = delta.InMicroseconds() % base::Time::kMicrosecondsPerSecond;
169 return result;
170 }
171
172 // Wait a socket for read for a certain timeout.
162 // Returns -1 if error occurred, 0 if timeout reached, > 0 if the socket is 173 // Returns -1 if error occurred, 0 if timeout reached, > 0 if the socket is
163 // ready for read. 174 // ready for read.
164 int WaitSocketForRead(int fd, int timeout) { 175 int WaitSocketForRead(int fd, const base::TimeDelta& timeout) {
165 fd_set read_fds; 176 fd_set read_fds;
166 struct timeval tv; 177 struct timeval tv = TimeDeltaToTimeVal(timeout);
167 178
168 FD_ZERO(&read_fds); 179 FD_ZERO(&read_fds);
169 FD_SET(fd, &read_fds); 180 FD_SET(fd, &read_fds);
170 tv.tv_sec = timeout;
171 tv.tv_usec = 0;
172 181
173 return HANDLE_EINTR(select(fd + 1, &read_fds, NULL, NULL, &tv)); 182 return HANDLE_EINTR(select(fd + 1, &read_fds, NULL, NULL, &tv));
174 } 183 }
175 184
176 // Read a message from a socket fd, with an optional timeout in seconds. 185 // Read a message from a socket fd, with an optional timeout.
177 // If |timeout| <= 0 then read immediately. 186 // If |timeout| <= 0 then read immediately.
178 // Return number of bytes actually read, or -1 on error. 187 // Return number of bytes actually read, or -1 on error.
179 ssize_t ReadFromSocket(int fd, char *buf, size_t bufsize, int timeout) { 188 ssize_t ReadFromSocket(int fd,
180 if (timeout > 0) { 189 char* buf,
190 size_t bufsize,
191 const base::TimeDelta& timeout) {
192 if (timeout > base::TimeDelta()) {
181 int rv = WaitSocketForRead(fd, timeout); 193 int rv = WaitSocketForRead(fd, timeout);
182 if (rv <= 0) 194 if (rv <= 0)
183 return rv; 195 return rv;
184 } 196 }
185 197
186 size_t bytes_read = 0; 198 size_t bytes_read = 0;
187 do { 199 do {
188 ssize_t rv = HANDLE_EINTR(read(fd, buf + bytes_read, bufsize - bytes_read)); 200 ssize_t rv = HANDLE_EINTR(read(fd, buf + bytes_read, bufsize - bytes_read));
189 if (rv < 0) { 201 if (rv < 0) {
190 if (errno != EAGAIN && errno != EWOULDBLOCK) { 202 if (errno != EAGAIN && errno != EWOULDBLOCK) {
(...skipping 546 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename); 749 cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename);
738 750
739 kill_callback_ = base::Bind(&ProcessSingleton::KillProcess, 751 kill_callback_ = base::Bind(&ProcessSingleton::KillProcess,
740 base::Unretained(this)); 752 base::Unretained(this));
741 } 753 }
742 754
743 ProcessSingleton::~ProcessSingleton() { 755 ProcessSingleton::~ProcessSingleton() {
744 } 756 }
745 757
746 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { 758 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
747 return NotifyOtherProcessWithTimeout(*CommandLine::ForCurrentProcess(), 759 return NotifyOtherProcessWithTimeout(
748 kTimeoutInSeconds, 760 *CommandLine::ForCurrentProcess(),
749 true); 761 kRetryAttempts,
762 base::TimeDelta::FromSeconds(kTimeoutInSeconds),
763 true);
750 } 764 }
751 765
752 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( 766 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
753 const CommandLine& cmd_line, 767 const CommandLine& cmd_line,
754 int timeout_seconds, 768 int retry_attempts,
769 const base::TimeDelta& timeout,
755 bool kill_unresponsive) { 770 bool kill_unresponsive) {
756 DCHECK_GE(timeout_seconds, 0); 771 DCHECK_GE(retry_attempts, 0);
772 DCHECK_GE(timeout.InMicroseconds(), 0);
773
774 base::TimeDelta sleep_interval = timeout / retry_attempts;
757 775
758 ScopedSocket socket; 776 ScopedSocket socket;
759 for (int retries = 0; retries <= timeout_seconds; ++retries) { 777 for (int retries = 0; retries <= retry_attempts; ++retries) {
760 // Try to connect to the socket. 778 // Try to connect to the socket.
761 if (ConnectSocket(&socket, socket_path_, cookie_path_)) 779 if (ConnectSocket(&socket, socket_path_, cookie_path_))
762 break; 780 break;
763 781
764 // If we're in a race with another process, they may be in Create() and have 782 // If we're in a race with another process, they may be in Create() and have
765 // created the lock but not attached to the socket. So we check if the 783 // created the lock but not attached to the socket. So we check if the
766 // process with the pid from the lockfile is currently running and is a 784 // process with the pid from the lockfile is currently running and is a
767 // chrome browser. If so, we loop and try again for |timeout_seconds|. 785 // chrome browser. If so, we loop and try again for |timeout|.
768 786
769 std::string hostname; 787 std::string hostname;
770 int pid; 788 int pid;
771 if (!ParseLockPath(lock_path_, &hostname, &pid)) { 789 if (!ParseLockPath(lock_path_, &hostname, &pid)) {
772 // No lockfile exists. 790 // No lockfile exists.
773 return PROCESS_NONE; 791 return PROCESS_NONE;
774 } 792 }
775 793
776 if (hostname.empty()) { 794 if (hostname.empty()) {
777 // Invalid lockfile. 795 // Invalid lockfile.
(...skipping 17 matching lines...) Expand all
795 return PROCESS_NONE; 813 return PROCESS_NONE;
796 } 814 }
797 815
798 if (IsSameChromeInstance(pid)) { 816 if (IsSameChromeInstance(pid)) {
799 // Orphaned lockfile (pid is part of same chrome instance we are, even 817 // Orphaned lockfile (pid is part of same chrome instance we are, even
800 // though we haven't tried to create a lockfile yet). 818 // though we haven't tried to create a lockfile yet).
801 UnlinkPath(lock_path_); 819 UnlinkPath(lock_path_);
802 return PROCESS_NONE; 820 return PROCESS_NONE;
803 } 821 }
804 822
805 if (retries == timeout_seconds) { 823 if (retries == retry_attempts) {
806 // Retries failed. Kill the unresponsive chrome process and continue. 824 // Retries failed. Kill the unresponsive chrome process and continue.
807 if (!kill_unresponsive || !KillProcessByLockPath()) 825 if (!kill_unresponsive || !KillProcessByLockPath())
808 return PROFILE_IN_USE; 826 return PROFILE_IN_USE;
809 return PROCESS_NONE; 827 return PROCESS_NONE;
810 } 828 }
811 829
812 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); 830 base::PlatformThread::Sleep(sleep_interval);
813 } 831 }
814 832
815 timeval timeout = {timeout_seconds, 0}; 833 timeval socket_timeout = TimeDeltaToTimeVal(timeout);
816 setsockopt(socket.fd(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 834 setsockopt(socket.fd(),
835 SOL_SOCKET,
836 SO_SNDTIMEO,
837 &socket_timeout,
838 sizeof(socket_timeout));
817 839
818 // Found another process, prepare our command line 840 // Found another process, prepare our command line
819 // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>". 841 // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
820 std::string to_send(kStartToken); 842 std::string to_send(kStartToken);
821 to_send.push_back(kTokenDelimiter); 843 to_send.push_back(kTokenDelimiter);
822 844
823 base::FilePath current_dir; 845 base::FilePath current_dir;
824 if (!PathService::Get(base::DIR_CURRENT, &current_dir)) 846 if (!PathService::Get(base::DIR_CURRENT, &current_dir))
825 return PROCESS_NONE; 847 return PROCESS_NONE;
826 to_send.append(current_dir.value()); 848 to_send.append(current_dir.value());
(...skipping 12 matching lines...) Expand all
839 return PROFILE_IN_USE; 861 return PROFILE_IN_USE;
840 return PROCESS_NONE; 862 return PROCESS_NONE;
841 } 863 }
842 864
843 if (shutdown(socket.fd(), SHUT_WR) < 0) 865 if (shutdown(socket.fd(), SHUT_WR) < 0)
844 PLOG(ERROR) << "shutdown() failed"; 866 PLOG(ERROR) << "shutdown() failed";
845 867
846 // Read ACK message from the other process. It might be blocked for a certain 868 // Read ACK message from the other process. It might be blocked for a certain
847 // timeout, to make sure the other process has enough time to return ACK. 869 // timeout, to make sure the other process has enough time to return ACK.
848 char buf[kMaxACKMessageLength + 1]; 870 char buf[kMaxACKMessageLength + 1];
849 ssize_t len = 871 ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout);
850 ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout_seconds);
851 872
852 // Failed to read ACK, the other process might have been frozen. 873 // Failed to read ACK, the other process might have been frozen.
853 if (len <= 0) { 874 if (len <= 0) {
854 if (!kill_unresponsive || !KillProcessByLockPath()) 875 if (!kill_unresponsive || !KillProcessByLockPath())
855 return PROFILE_IN_USE; 876 return PROFILE_IN_USE;
856 return PROCESS_NONE; 877 return PROCESS_NONE;
857 } 878 }
858 879
859 buf[len] = '\0'; 880 buf[len] = '\0';
860 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) { 881 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) {
(...skipping 11 matching lines...) Expand all
872 return PROCESS_NOTIFIED; 893 return PROCESS_NOTIFIED;
873 } 894 }
874 895
875 NOTREACHED() << "The other process returned unknown message: " << buf; 896 NOTREACHED() << "The other process returned unknown message: " << buf;
876 return PROCESS_NOTIFIED; 897 return PROCESS_NOTIFIED;
877 } 898 }
878 899
879 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { 900 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
880 return NotifyOtherProcessWithTimeoutOrCreate( 901 return NotifyOtherProcessWithTimeoutOrCreate(
881 *CommandLine::ForCurrentProcess(), 902 *CommandLine::ForCurrentProcess(),
882 kTimeoutInSeconds); 903 kRetryAttempts,
904 base::TimeDelta::FromSeconds(kTimeoutInSeconds));
883 } 905 }
884 906
885 ProcessSingleton::NotifyResult 907 ProcessSingleton::NotifyResult
886 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( 908 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
887 const CommandLine& command_line, 909 const CommandLine& command_line,
888 int timeout_seconds) { 910 int retry_attempts,
889 NotifyResult result = NotifyOtherProcessWithTimeout(command_line, 911 const base::TimeDelta& timeout) {
890 timeout_seconds, true); 912 NotifyResult result = NotifyOtherProcessWithTimeout(
913 command_line, retry_attempts, timeout, true);
891 if (result != PROCESS_NONE) 914 if (result != PROCESS_NONE)
892 return result; 915 return result;
893 if (Create()) 916 if (Create())
894 return PROCESS_NONE; 917 return PROCESS_NONE;
895 // If the Create() failed, try again to notify. (It could be that another 918 // If the Create() failed, try again to notify. (It could be that another
896 // instance was starting at the same time and managed to grab the lock before 919 // instance was starting at the same time and managed to grab the lock before
897 // we did.) 920 // we did.)
898 // This time, we don't want to kill anything if we aren't successful, since we 921 // This time, we don't want to kill anything if we aren't successful, since we
899 // aren't going to try to take over the lock ourselves. 922 // aren't going to try to take over the lock ourselves.
900 result = NotifyOtherProcessWithTimeout(command_line, timeout_seconds, false); 923 result = NotifyOtherProcessWithTimeout(
924 command_line, retry_attempts, timeout, false);
901 if (result != PROCESS_NONE) 925 if (result != PROCESS_NONE)
902 return result; 926 return result;
903 927
904 return LOCK_ERROR; 928 return LOCK_ERROR;
905 } 929 }
906 930
907 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) { 931 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) {
908 current_pid_ = pid; 932 current_pid_ = pid;
909 } 933 }
910 934
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1045 } 1069 }
1046 1070
1047 void ProcessSingleton::KillProcess(int pid) { 1071 void ProcessSingleton::KillProcess(int pid) {
1048 // TODO(james.su@gmail.com): Is SIGKILL ok? 1072 // TODO(james.su@gmail.com): Is SIGKILL ok?
1049 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); 1073 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
1050 // ESRCH = No Such Process (can happen if the other process is already in 1074 // ESRCH = No Such Process (can happen if the other process is already in
1051 // progress of shutting down and finishes before we try to kill it). 1075 // progress of shutting down and finishes before we try to kill it).
1052 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " 1076 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
1053 << safe_strerror(errno); 1077 << safe_strerror(errno);
1054 } 1078 }
OLDNEW
« no previous file with comments | « chrome/browser/process_singleton.h ('k') | chrome/browser/process_singleton_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698