diff options
author | dmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-16 21:14:58 +0000 |
---|---|---|
committer | dmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-16 21:14:58 +0000 |
commit | 293fd7a9eb27dac7599a752e847c5b15f449519f (patch) | |
tree | acc6e4a4c1d5d2ea551a64b92e8223dc94bad728 /chrome/common/multi_process_lock_unittest.cc | |
parent | c18215ab75f2f05e1da3f901fd385393a5d8def6 (diff) | |
download | chromium_src-293fd7a9eb27dac7599a752e847c5b15f449519f.zip chromium_src-293fd7a9eb27dac7599a752e847c5b15f449519f.tar.gz chromium_src-293fd7a9eb27dac7599a752e847c5b15f449519f.tar.bz2 |
Add multi_process_lock to base
Platform abstraction for a shared lock between processes. The process
that owns the lock will release it on exit even if exit is due
to a crash.
For cloud-print and remoting we want to be able to have a singleton service-process that can run independently of the browser process. This service process will communicate with the browser process via the standard IAC channels, but we want to have a way of signaling to other processes that a) there is a service-process running and b) that it is in a state where it is ready to be communicated with. The multi_process_lock class is intended to work as a simple flag that can be queried from multiple processes. If the service-process should crash, we would like the flag to be cleared automatically so that there is never confusion about the state of the service-process.
Other approaches considered for some Unix/Mac:
- Standard unix domain sockets depend on the file system and don't clean up properly in the case of a crash.
- Shared memory on unix depend on the file system and don't clean up properly in the case of a crash.
- System V semaphores on unix again depend on the file system.
- named_mach_ports on Mac OS. Bootstrap_register_name has been deprecated on 10.6, so we are doing essentially the same thing using CFMessagePort.
On Windows it is implemented as an event.
On Mac it is implemented using a CFMessagePort name.
On Linux it is implement using an abstract name port socket.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/4721001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66323 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/multi_process_lock_unittest.cc')
-rw-r--r-- | chrome/common/multi_process_lock_unittest.cc | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/chrome/common/multi_process_lock_unittest.cc b/chrome/common/multi_process_lock_unittest.cc new file mode 100644 index 0000000..733eb2d --- /dev/null +++ b/chrome/common/multi_process_lock_unittest.cc @@ -0,0 +1,157 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "base/environment.h" +#include "base/logging.h" +#include "base/rand_util.h" +#include "base/scoped_ptr.h" +#include "base/stringprintf.h" +#include "base/test/multiprocess_test.h" +#include "base/time.h" +#include "chrome/common/multi_process_lock.h" +#include "testing/multiprocess_func_list.h" + +class MultiProcessLockTest : public base::MultiProcessTest { + public: + static const char kLockEnviromentVarName[]; + + class ScopedEnvironmentVariable { + public: + ScopedEnvironmentVariable(const std::string &name, + const std::string &value) + : name_(name), environment_(base::Environment::Create()) { + environment_->SetVar(name_.c_str(), value); + } + ~ScopedEnvironmentVariable() { + environment_->UnSetVar(name_.c_str()); + } + + private: + std::string name_; + scoped_ptr<base::Environment> environment_; + DISALLOW_COPY_AND_ASSIGN(ScopedEnvironmentVariable); + }; + + std::string GenerateLockName(); + void ExpectLockIsLocked(const std::string &name); + void ExpectLockIsUnlocked(const std::string &name); +}; + +const char MultiProcessLockTest::kLockEnviromentVarName[] + = "MULTI_PROCESS_TEST_LOCK_NAME"; + +std::string MultiProcessLockTest::GenerateLockName() { + base::Time now = base::Time::NowFromSystemTime(); + return base::StringPrintf("multi_process_test_lock %lf%lf", + now.ToDoubleT(), base::RandDouble()); +} + +void MultiProcessLockTest::ExpectLockIsLocked(const std::string &name) { + ScopedEnvironmentVariable var(kLockEnviromentVarName, name); + base::ProcessHandle handle = SpawnChild("MultiProcessLockTryFailMain", false); + ASSERT_TRUE(handle); + int exit_code = 0; + EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); + EXPECT_EQ(exit_code, 0); +} + +void MultiProcessLockTest::ExpectLockIsUnlocked( + const std::string &name) { + ScopedEnvironmentVariable var(kLockEnviromentVarName, name); + base::ProcessHandle handle = SpawnChild("MultiProcessLockTrySucceedMain", + false); + ASSERT_TRUE(handle); + int exit_code = 0; + EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); + EXPECT_EQ(exit_code, 0); +} + +TEST_F(MultiProcessLockTest, BasicCreationTest) { + // Test basic creation/destruction with no lock taken + std::string name = GenerateLockName(); + scoped_ptr<MultiProcessLock> scoped(MultiProcessLock::Create(name)); + ExpectLockIsUnlocked(name); + scoped.reset(NULL); +} + +TEST_F(MultiProcessLockTest, LongNameTest) { + // Linux has a max path name of 108 characters. + // http://lxr.linux.no/linux+v2.6.36/include/linux/un.h + // This is enforced on all platforms. + LOG(INFO) << "Following error log due to long name is expected"; + std::string name("This is a name that is longer than one hundred and eight " + "characters to make sure that we fail appropriately on linux when we " + "have a path that is to long for linux to handle"); + scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); + EXPECT_FALSE(test_lock->TryLock()); +} + +TEST_F(MultiProcessLockTest, SimpleLock) { + std::string name = GenerateLockName(); + scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); + EXPECT_TRUE(test_lock->TryLock()); + ExpectLockIsLocked(name); + test_lock->Unlock(); + ExpectLockIsUnlocked(name); +} + +TEST_F(MultiProcessLockTest, RecursiveLock) { + std::string name = GenerateLockName(); + scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); + EXPECT_TRUE(test_lock->TryLock()); + ExpectLockIsLocked(name); + LOG(INFO) << "Following error log " + << "'MultiProcessLock is already locked' is expected"; + EXPECT_TRUE(test_lock->TryLock()); + ExpectLockIsLocked(name); + test_lock->Unlock(); + ExpectLockIsUnlocked(name); + LOG(INFO) << "Following error log " + << "'Over-unlocked MultiProcessLock' is expected"; + test_lock->Unlock(); + ExpectLockIsUnlocked(name); + test_lock.reset(); +} + +TEST_F(MultiProcessLockTest, LockScope) { + // Check to see that lock is released when it goes out of scope. + std::string name = GenerateLockName(); + { + scoped_ptr<MultiProcessLock> test_lock(MultiProcessLock::Create(name)); + EXPECT_TRUE(test_lock->TryLock()); + ExpectLockIsLocked(name); + } + ExpectLockIsUnlocked(name); +} + +MULTIPROCESS_TEST_MAIN(MultiProcessLockTryFailMain) { + std::string name; + scoped_ptr<base::Environment> environment(base::Environment::Create()); + EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName, + &name)); +#if defined(OS_MACOSX) + // OS X sends out a log if a lock fails. + // Hopefully this will keep people from panicking about it when they + // are perusing thge build logs. + LOG(INFO) << "Following error log " + << "\"CFMessagePort: bootstrap_register(): failed 1100 (0x44c) " + << "'Permission denied'\" is expected"; +#endif // defined(OS_MACOSX) + scoped_ptr<MultiProcessLock> test_lock( + MultiProcessLock::Create(name)); + EXPECT_FALSE(test_lock->TryLock()); + return 0; +} + +MULTIPROCESS_TEST_MAIN(MultiProcessLockTrySucceedMain) { + std::string name; + scoped_ptr<base::Environment> environment(base::Environment::Create()); + EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnviromentVarName, + &name)); + scoped_ptr<MultiProcessLock> test_lock( + MultiProcessLock::Create(name)); + EXPECT_TRUE(test_lock->TryLock()); + return 0; +} |