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

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: lower test timeout a little more 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
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_interval,
755 bool kill_unresponsive) { 770 bool kill_unresponsive) {
756 DCHECK_GE(timeout_seconds, 0); 771 DCHECK_GE(retry_attempts, 0);
772 DCHECK_GE(timeout_interval.InMicroseconds(), 0);
773
774 base::TimeDelta sleep_interval = timeout_interval / 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_interval|.
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 timeout = TimeDeltaToTimeVal(timeout_interval);
816 setsockopt(socket.fd(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 834 setsockopt(socket.fd(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
817 835
818 // Found another process, prepare our command line 836 // Found another process, prepare our command line
819 // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>". 837 // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
820 std::string to_send(kStartToken); 838 std::string to_send(kStartToken);
821 to_send.push_back(kTokenDelimiter); 839 to_send.push_back(kTokenDelimiter);
822 840
823 base::FilePath current_dir; 841 base::FilePath current_dir;
824 if (!PathService::Get(base::DIR_CURRENT, &current_dir)) 842 if (!PathService::Get(base::DIR_CURRENT, &current_dir))
825 return PROCESS_NONE; 843 return PROCESS_NONE;
(...skipping 14 matching lines...) Expand all
840 return PROCESS_NONE; 858 return PROCESS_NONE;
841 } 859 }
842 860
843 if (shutdown(socket.fd(), SHUT_WR) < 0) 861 if (shutdown(socket.fd(), SHUT_WR) < 0)
844 PLOG(ERROR) << "shutdown() failed"; 862 PLOG(ERROR) << "shutdown() failed";
845 863
846 // Read ACK message from the other process. It might be blocked for a certain 864 // 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. 865 // timeout, to make sure the other process has enough time to return ACK.
848 char buf[kMaxACKMessageLength + 1]; 866 char buf[kMaxACKMessageLength + 1];
849 ssize_t len = 867 ssize_t len =
850 ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout_seconds); 868 ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout_interval);
851 869
852 // Failed to read ACK, the other process might have been frozen. 870 // Failed to read ACK, the other process might have been frozen.
853 if (len <= 0) { 871 if (len <= 0) {
854 if (!kill_unresponsive || !KillProcessByLockPath()) 872 if (!kill_unresponsive || !KillProcessByLockPath())
855 return PROFILE_IN_USE; 873 return PROFILE_IN_USE;
856 return PROCESS_NONE; 874 return PROCESS_NONE;
857 } 875 }
858 876
859 buf[len] = '\0'; 877 buf[len] = '\0';
860 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) { 878 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) {
(...skipping 11 matching lines...) Expand all
872 return PROCESS_NOTIFIED; 890 return PROCESS_NOTIFIED;
873 } 891 }
874 892
875 NOTREACHED() << "The other process returned unknown message: " << buf; 893 NOTREACHED() << "The other process returned unknown message: " << buf;
876 return PROCESS_NOTIFIED; 894 return PROCESS_NOTIFIED;
877 } 895 }
878 896
879 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { 897 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
880 return NotifyOtherProcessWithTimeoutOrCreate( 898 return NotifyOtherProcessWithTimeoutOrCreate(
881 *CommandLine::ForCurrentProcess(), 899 *CommandLine::ForCurrentProcess(),
882 kTimeoutInSeconds); 900 kRetryAttempts,
901 base::TimeDelta::FromSeconds(kTimeoutInSeconds));
883 } 902 }
884 903
885 ProcessSingleton::NotifyResult 904 ProcessSingleton::NotifyResult
886 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( 905 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
887 const CommandLine& command_line, 906 const CommandLine& command_line,
888 int timeout_seconds) { 907 int retry_attempts,
889 NotifyResult result = NotifyOtherProcessWithTimeout(command_line, 908 const base::TimeDelta& timeout_interval) {
890 timeout_seconds, true); 909 NotifyResult result = NotifyOtherProcessWithTimeout(
910 command_line, retry_attempts, timeout_interval, true);
891 if (result != PROCESS_NONE) 911 if (result != PROCESS_NONE)
892 return result; 912 return result;
893 if (Create()) 913 if (Create())
894 return PROCESS_NONE; 914 return PROCESS_NONE;
895 // If the Create() failed, try again to notify. (It could be that another 915 // 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 916 // instance was starting at the same time and managed to grab the lock before
897 // we did.) 917 // we did.)
898 // This time, we don't want to kill anything if we aren't successful, since we 918 // 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. 919 // aren't going to try to take over the lock ourselves.
900 result = NotifyOtherProcessWithTimeout(command_line, timeout_seconds, false); 920 result = NotifyOtherProcessWithTimeout(
921 command_line, retry_attempts, timeout_interval, false);
901 if (result != PROCESS_NONE) 922 if (result != PROCESS_NONE)
902 return result; 923 return result;
903 924
904 return LOCK_ERROR; 925 return LOCK_ERROR;
905 } 926 }
906 927
907 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) { 928 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) {
908 current_pid_ = pid; 929 current_pid_ = pid;
909 } 930 }
910 931
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1045 } 1066 }
1046 1067
1047 void ProcessSingleton::KillProcess(int pid) { 1068 void ProcessSingleton::KillProcess(int pid) {
1048 // TODO(james.su@gmail.com): Is SIGKILL ok? 1069 // TODO(james.su@gmail.com): Is SIGKILL ok?
1049 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); 1070 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
1050 // ESRCH = No Such Process (can happen if the other process is already in 1071 // 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). 1072 // progress of shutting down and finishes before we try to kill it).
1052 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " 1073 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
1053 << safe_strerror(errno); 1074 << safe_strerror(errno);
1054 } 1075 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698