Commit b401fd2a authored by Elly Fong-Jones's avatar Elly Fong-Jones Committed by Commit Bot

core: spruce up TakeNamedLock and friends

TakeNamedLock has a "waiting" mode that works like this:

  for (int i = 0; i < 10; i++)
    if (TryLock())
      break;
    usleep(i * 100);

which means that in "waiting" mode, if the lock is unavailable
for the duration, this function will block the calling thread
(with the message loop not spinning) for up to 4.5 seconds. However,
there are two problems with this design:

* The caller has no way to know whether "waiting" is appropriate or not
* The caller has to handle failure to acquire the lock either way

If retries are needed to deal with external conditions changing that might
have freed the lock up (another process exiting, e.g.) those retries should
be done at higher levels with more context.

More concretely, the only actual production use of this function is in
CloudPrintServiceProcessMain:

    std::unique_ptr<ServiceProcessState> state(new ServiceProcessState);
    if (!state->Initialize())
      return 0;

This change has TakeNamedLock make a single non-blocking attempt to
take the lock, and moves the retry logic up into
CloudPrintServiceProcessMain.

Since I was here anyway, I converted the API to use unique_ptr, since it
returns ownership of the lock if it succeeds.

Bug: 1052430
Change-Id: Ib87b23cc821fe59e69b76ffb3875917027bfdc4e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2057530Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Commit-Queue: Elly Fong-Jones <ellyjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#744283}
parent fa34f142
...@@ -108,8 +108,7 @@ MockLaunchd::~MockLaunchd() {} ...@@ -108,8 +108,7 @@ MockLaunchd::~MockLaunchd() {}
bool MockLaunchd::GetJobInfo(const std::string& label, bool MockLaunchd::GetJobInfo(const std::string& label,
mac::services::JobInfo* info) { mac::services::JobInfo* info) {
if (!as_service_) { if (!as_service_) {
std::unique_ptr<MultiProcessLock> running_lock( std::unique_ptr<MultiProcessLock> running_lock = TakeNamedLock(pipe_name_);
TakeNamedLock(pipe_name_, false));
if (running_lock.get()) if (running_lock.get())
return false; return false;
} }
...@@ -164,5 +163,5 @@ bool MockLaunchd::DeletePlist(Domain domain, Type type, CFStringRef name) { ...@@ -164,5 +163,5 @@ bool MockLaunchd::DeletePlist(Domain domain, Type type, CFStringRef name) {
void MockLaunchd::SignalReady() { void MockLaunchd::SignalReady() {
ASSERT_TRUE(as_service_); ASSERT_TRUE(as_service_);
running_lock_.reset(TakeNamedLock(pipe_name_, true)); running_lock_ = TakeNamedLock(pipe_name_);
} }
...@@ -21,14 +21,6 @@ ...@@ -21,14 +21,6 @@
class MultiProcessLock; class MultiProcessLock;
#if defined(OS_MACOSX)
#ifdef __OBJC__
@class NSString;
#else
class NSString;
#endif
#endif
namespace base { namespace base {
class CommandLine; class CommandLine;
} }
...@@ -47,10 +39,9 @@ std::string GetServiceProcessScopedVersionedName(const std::string& append_str); ...@@ -47,10 +39,9 @@ std::string GetServiceProcessScopedVersionedName(const std::string& append_str);
#endif // !OS_MACOSX #endif // !OS_MACOSX
#if defined(OS_POSIX) #if defined(OS_POSIX)
// Attempts to take a lock named |name|. If |waiting| is true then this will // Attempts to take a session-wide lock named name. Returns a non-null lock if
// make multiple attempts to acquire the lock. // successful.
// Caller is responsible for ownership of the MultiProcessLock. std::unique_ptr<MultiProcessLock> TakeNamedLock(const std::string& name);
MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting);
#endif #endif
// The following method is used in a process that acts as a client to the // The following method is used in a process that acts as a client to the
......
...@@ -20,12 +20,6 @@ ...@@ -20,12 +20,6 @@
namespace { namespace {
MultiProcessLock* TakeServiceInitializingLock(bool waiting) {
std::string lock_name =
GetServiceProcessScopedName("_service_initializing");
return TakeNamedLock(lock_name, waiting);
}
std::string GetBaseDesktopName() { std::string GetBaseDesktopName() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING) #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
return "google-chrome-service.desktop"; return "google-chrome-service.desktop";
...@@ -35,10 +29,10 @@ std::string GetBaseDesktopName() { ...@@ -35,10 +29,10 @@ std::string GetBaseDesktopName() {
} }
} // namespace } // namespace
MultiProcessLock* TakeServiceRunningLock(bool waiting) { std::unique_ptr<MultiProcessLock> TakeServiceRunningLock() {
std::string lock_name = std::string lock_name =
GetServiceProcessScopedName("_service_running"); GetServiceProcessScopedName("_service_running");
return TakeNamedLock(lock_name, waiting); return TakeNamedLock(lock_name);
} }
bool ForceServiceProcessShutdown(const std::string& version, bool ForceServiceProcessShutdown(const std::string& version,
...@@ -60,12 +54,13 @@ mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName() { ...@@ -60,12 +54,13 @@ mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName() {
} }
bool CheckServiceProcessReady() { bool CheckServiceProcessReady() {
std::unique_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false)); std::unique_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock());
return running_lock.get() == NULL; return !running_lock.get();
} }
bool ServiceProcessState::TakeSingletonLock() { bool ServiceProcessState::TakeSingletonLock() {
state_->initializing_lock.reset(TakeServiceInitializingLock(true)); state_->initializing_lock =
TakeNamedLock(GetServiceProcessScopedName("_service_initializing"));
return state_->initializing_lock.get(); return state_->initializing_lock.get();
} }
......
...@@ -172,25 +172,13 @@ bool ServiceProcessState::DeleteServiceProcessDataRegion() { ...@@ -172,25 +172,13 @@ bool ServiceProcessState::DeleteServiceProcessDataRegion() {
#endif // !defined(OS_MACOSX) #endif // !defined(OS_MACOSX)
// Attempts to take a lock named |name|. If |waiting| is true then this will // Attempts to take a lock named |name|. Returns the lock if successful, or
// make multiple attempts to acquire the lock. // nullptr if not.
// Caller is responsible for ownership of the MultiProcessLock. std::unique_ptr<MultiProcessLock> TakeNamedLock(const std::string& name) {
MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
std::unique_ptr<MultiProcessLock> lock = MultiProcessLock::Create(name); std::unique_ptr<MultiProcessLock> lock = MultiProcessLock::Create(name);
if (lock == NULL) return NULL; if (!lock->TryLock())
bool got_lock = false;
for (int i = 0; i < 10; ++i) {
if (lock->TryLock()) {
got_lock = true;
break;
}
if (!waiting) break;
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
}
if (!got_lock) {
lock.reset(); lock.reset();
} return lock;
return lock.release();
} }
ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor( ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
...@@ -324,8 +312,8 @@ bool ServiceProcessState::SignalReady( ...@@ -324,8 +312,8 @@ bool ServiceProcessState::SignalReady(
DCHECK(state_); DCHECK(state_);
#if !defined(OS_MACOSX) #if !defined(OS_MACOSX)
state_->running_lock.reset(TakeServiceRunningLock(true)); state_->running_lock = TakeServiceRunningLock();
if (state_->running_lock.get() == NULL) { if (!state_->running_lock.get()) {
return false; return false;
} }
#endif #endif
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#if defined(OS_POSIX) && !defined(OS_MACOSX) #if defined(OS_POSIX) && !defined(OS_MACOSX)
#include "chrome/common/multi_process_lock.h" #include "chrome/common/multi_process_lock.h"
MultiProcessLock* TakeServiceRunningLock(bool waiting); std::unique_ptr<MultiProcessLock> TakeServiceRunningLock();
#endif #endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
......
...@@ -38,9 +38,21 @@ int CloudPrintServiceProcessMain( ...@@ -38,9 +38,21 @@ int CloudPrintServiceProcessMain(
VLOG(1) << "Service process launched: " VLOG(1) << "Service process launched: "
<< parameters.command_line.GetCommandLineString(); << parameters.command_line.GetCommandLineString();
// If there is already a service process running, quit now. auto initialize_service = [](ServiceProcessState* service) {
std::unique_ptr<ServiceProcessState> state(new ServiceProcessState); for (int i = 0; i < 10; ++i) {
if (!state->Initialize()) if (service->Initialize())
return true;
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(i * 100));
}
return false;
};
// If there is already a service process running, quit now. Retry a few times
// in case the running service is busy exiting.
// TODO(ellyjones): Are these retries actually necessary / can this case
// happen in practice?
auto state = std::make_unique<ServiceProcessState>();
if (!initialize_service(state.get()))
return 0; return 0;
base::RunLoop run_loop; base::RunLoop run_loop;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment