From d7cae12696b96500c05dd2d430f6238922c20c96 Mon Sep 17 00:00:00 2001 From: "initial.commit" Date: Sat, 26 Jul 2008 21:49:38 +0000 Subject: Add base to the repository. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8 0039d316-1c4b-4281-b951-d872f2087c98 --- base/lock.cc | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 base/lock.cc (limited to 'base/lock.cc') diff --git a/base/lock.cc b/base/lock.cc new file mode 100644 index 0000000..afa1a6f --- /dev/null +++ b/base/lock.cc @@ -0,0 +1,156 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Provide place to put profiling methods for the +// Lock class. +// The Lock class is used everywhere, and hence any changes +// to lock.h tend to require a complete rebuild. To facilitate +// profiler development, all the profiling methods are listed +// here. Note that they are only instantiated in a debug +// build, and the header provides all the trivial implementations +// in a production build. + +#include "base/lock.h" +#include "base/logging.h" + +Lock::Lock() + : lock_() + , recursion_count_shadow_(0) { +#ifndef NDEBUG + recursion_used_ = false; + acquisition_count_ = 0; + contention_count_ = 0; +#endif +} + +Lock::~Lock() { +#ifndef NDEBUG + // There should be no one to contend for the lock, + // ...but we need the memory barrier to get a good value. + lock_.Lock(); + int final_recursion_count = recursion_count_shadow_; + lock_.Unlock(); +#endif + + // Allow unit test exception only at end of method. +#ifndef NDEBUG + DCHECK(0 == final_recursion_count); +#endif +} + +void Lock::Acquire() { +#ifdef NDEBUG + lock_.Lock(); + recursion_count_shadow_++; +#else // NDEBUG + if (!lock_.Try()) { + // We have contention. + lock_.Lock(); + contention_count_++; + } + // ONLY access data after locking. + recursion_count_shadow_++; + if (1 == recursion_count_shadow_) + acquisition_count_++; + else if (2 == recursion_count_shadow_ && !recursion_used_) + // Usage Note: Set a break point to debug. + recursion_used_ = true; +#endif // NDEBUG +} + +void Lock::Release() { + --recursion_count_shadow_; // ONLY access while lock is still held. +#ifndef NDEBUG + DCHECK(0 <= recursion_count_shadow_); +#endif + lock_.Unlock(); +} + +bool Lock::Try() { + if (lock_.Try()) { + recursion_count_shadow_++; +#ifndef NDEBUG + if (1 == recursion_count_shadow_) + acquisition_count_++; + else if (2 == recursion_count_shadow_ && !recursion_used_) + // Usage Note: Set a break point to debug. + recursion_used_ = true; +#endif + return true; + } else { + return false; + } +} + +// GetCurrentThreadRecursionCount returns the number of nested Acquire() calls +// that have been made by the current thread holding this lock. The calling +// thread is ***REQUIRED*** to be *currently* holding the lock. If that +// calling requirement is violated, the return value is not well defined. +// Return results are guaranteed correct if the caller has acquired this lock. +// The return results might be incorrect otherwise. +// This method is designed to be fast in non-debug mode by co-opting +// synchronization using lock_ (no additional synchronization is used), but in +// debug mode it slowly and carefully validates the requirement (and fires a +// a DCHECK if it was called incorrectly). +int32 Lock::GetCurrentThreadRecursionCount() { +#ifndef NDEBUG + // If this DCHECK fails, then the most probable cause is: + // This method was called by class AutoUnlock during processing of a + // Wait() call made into the ConditonVariable class. That call to + // Wait() was made (incorrectly) without first Aquiring this Lock + // instance. + lock_.Lock(); + int temp = recursion_count_shadow_; + lock_.Unlock(); + // Unit tests catch an exception, so we need to be careful to test + // outside the critical section, since the Leave would be skipped!?! + DCHECK(temp >= 1); // Allow unit test exception only at end of method. +#endif // DEBUG + + // We hold lock, so this *is* correct value. + return recursion_count_shadow_; +} + + +AutoUnlock::AutoUnlock(Lock& lock) : lock_(&lock), release_count_(0) { + // We require our caller have the lock, so we can call for recursion count. + // CRITICALLY: Fetch value before we release the lock. + int32 count = lock_->GetCurrentThreadRecursionCount(); + DCHECK(count > 0); // Make sure we owned the lock. + while (count-- > 0) { + release_count_++; + lock_->Release(); + } +} + +AutoUnlock::~AutoUnlock() { + DCHECK(release_count_ >= 0); + while (release_count_-- > 0) + lock_->Acquire(); +} -- cgit v1.1