#include "base/basictypes.h"
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/common/chrome_constants.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_thread.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"
using content::BrowserThread;
-const int ProcessSingleton::kTimeoutInSeconds;
-
namespace {
+// Timeout for the current browser process to respond. 20 seconds should be
+// enough.
+const int kTimeoutInSeconds = 20;
+// Number of retries to notify the browser. 20 retries over 20 seconds = 1 try
+// per second.
+const int kRetryAttempts = 20;
static bool g_disable_prompt;
const char kStartToken[] = "START";
const char kACKToken[] = "ACK";
return true;
}
-// Wait a socket for read for a certain timeout in seconds.
+struct timeval TimeDeltaToTimeVal(const base::TimeDelta& delta) {
+ struct timeval result;
+ result.tv_sec = delta.InSeconds();
+ result.tv_usec = delta.InMicroseconds() % base::Time::kMicrosecondsPerSecond;
+ return result;
+}
+
+// Wait a socket for read for a certain timeout.
// Returns -1 if error occurred, 0 if timeout reached, > 0 if the socket is
// ready for read.
-int WaitSocketForRead(int fd, int timeout) {
+int WaitSocketForRead(int fd, const base::TimeDelta& timeout) {
fd_set read_fds;
- struct timeval tv;
+ struct timeval tv = TimeDeltaToTimeVal(timeout);
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
return HANDLE_EINTR(select(fd + 1, &read_fds, NULL, NULL, &tv));
}
-// Read a message from a socket fd, with an optional timeout in seconds.
+// Read a message from a socket fd, with an optional timeout.
// If |timeout| <= 0 then read immediately.
// Return number of bytes actually read, or -1 on error.
-ssize_t ReadFromSocket(int fd, char *buf, size_t bufsize, int timeout) {
- if (timeout > 0) {
+ssize_t ReadFromSocket(int fd,
+ char* buf,
+ size_t bufsize,
+ const base::TimeDelta& timeout) {
+ if (timeout > base::TimeDelta()) {
int rv = WaitSocketForRead(fd, timeout);
if (rv <= 0)
return rv;
}
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
- return NotifyOtherProcessWithTimeout(*CommandLine::ForCurrentProcess(),
- kTimeoutInSeconds,
- true);
+ return NotifyOtherProcessWithTimeout(
+ *CommandLine::ForCurrentProcess(),
+ kRetryAttempts,
+ base::TimeDelta::FromSeconds(kTimeoutInSeconds),
+ true);
}
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
const CommandLine& cmd_line,
- int timeout_seconds,
+ int retry_attempts,
+ const base::TimeDelta& timeout,
bool kill_unresponsive) {
- DCHECK_GE(timeout_seconds, 0);
+ DCHECK_GE(retry_attempts, 0);
+ DCHECK_GE(timeout.InMicroseconds(), 0);
+
+ base::TimeDelta sleep_interval = timeout / retry_attempts;
ScopedSocket socket;
- for (int retries = 0; retries <= timeout_seconds; ++retries) {
+ for (int retries = 0; retries <= retry_attempts; ++retries) {
// Try to connect to the socket.
if (ConnectSocket(&socket, socket_path_, cookie_path_))
break;
// If we're in a race with another process, they may be in Create() and have
// created the lock but not attached to the socket. So we check if the
// process with the pid from the lockfile is currently running and is a
- // chrome browser. If so, we loop and try again for |timeout_seconds|.
+ // chrome browser. If so, we loop and try again for |timeout|.
std::string hostname;
int pid;
return PROCESS_NONE;
}
- if (retries == timeout_seconds) {
+ if (retries == retry_attempts) {
// Retries failed. Kill the unresponsive chrome process and continue.
if (!kill_unresponsive || !KillProcessByLockPath())
return PROFILE_IN_USE;
return PROCESS_NONE;
}
- base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+ base::PlatformThread::Sleep(sleep_interval);
}
- timeval timeout = {timeout_seconds, 0};
- setsockopt(socket.fd(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+ timeval socket_timeout = TimeDeltaToTimeVal(timeout);
+ setsockopt(socket.fd(),
+ SOL_SOCKET,
+ SO_SNDTIMEO,
+ &socket_timeout,
+ sizeof(socket_timeout));
// Found another process, prepare our command line
// format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
// Read ACK message from the other process. It might be blocked for a certain
// timeout, to make sure the other process has enough time to return ACK.
char buf[kMaxACKMessageLength + 1];
- ssize_t len =
- ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout_seconds);
+ ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout);
// Failed to read ACK, the other process might have been frozen.
if (len <= 0) {
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
return NotifyOtherProcessWithTimeoutOrCreate(
*CommandLine::ForCurrentProcess(),
- kTimeoutInSeconds);
+ kRetryAttempts,
+ base::TimeDelta::FromSeconds(kTimeoutInSeconds));
}
ProcessSingleton::NotifyResult
ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
const CommandLine& command_line,
- int timeout_seconds) {
- NotifyResult result = NotifyOtherProcessWithTimeout(command_line,
- timeout_seconds, true);
+ int retry_attempts,
+ const base::TimeDelta& timeout) {
+ NotifyResult result = NotifyOtherProcessWithTimeout(
+ command_line, retry_attempts, timeout, true);
if (result != PROCESS_NONE)
return result;
if (Create())
// we did.)
// This time, we don't want to kill anything if we aren't successful, since we
// aren't going to try to take over the lock ourselves.
- result = NotifyOtherProcessWithTimeout(command_line, timeout_seconds, false);
+ result = NotifyOtherProcessWithTimeout(
+ command_line, retry_attempts, timeout, false);
if (result != PROCESS_NONE)
return result;