13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 23f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Use of this source code is governed by a BSD-style license that can be 33f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// found in the LICENSE file. 43f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#ifndef BASE_SYNCHRONIZATION_LOCK_H_ 63f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#define BASE_SYNCHRONIZATION_LOCK_H_ 73f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#pragma once 83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/base_api.h" 103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/lock_impl.h" 113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h" 123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base { 143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// A convenient wrapper for an OS specific critical section. The only real 163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// intelligence in this class is in debug mode for the support for the 173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// AssertAcquired() method. 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass BASE_API Lock { 193f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen public: 203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if defined(NDEBUG) // Optimized wrapper implementation 213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Lock() : lock_() {} 223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ~Lock() {} 233f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void Acquire() { lock_.Lock(); } 243f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void Release() { lock_.Unlock(); } 253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // If the lock is not held, take it and return true. If the lock is already 273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // held by another thread, immediately return false. This must not be called 283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // by a thread already holding the lock (what happens is undefined and an 293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // assertion may fail). 303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen bool Try() { return lock_.Try(); } 313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Null implementation if not debug. 333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void AssertAcquired() const {} 343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#else 353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Lock(); 363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ~Lock() {} 373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 383f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // NOTE: Although windows critical sections support recursive locks, we do not 393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // allow this, and we will commonly fire a DCHECK() if a thread attempts to 403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // acquire the lock a second time (while already holding it). 413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void Acquire() { 423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.Lock(); 433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen CheckUnheldAndMark(); 443f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 453f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void Release() { 463f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen CheckHeldAndUnmark(); 473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.Unlock(); 483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen bool Try() { 513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen bool rv = lock_.Try(); 523f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (rv) { 533f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen CheckUnheldAndMark(); 543f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 553f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen return rv; 563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void AssertAcquired() const; 593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif // NDEBUG 603f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if defined(OS_POSIX) 623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // The posix implementation of ConditionVariable needs to be able 633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // to see our lock and tweak our debugging counters, as it releases 643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // and acquires locks inside of pthread_cond_{timed,}wait. 653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Windows doesn't need to do this as it calls the Lock::* methods. 663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen friend class ConditionVariable; 673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif 683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen private: 703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#if !defined(NDEBUG) 713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Members and routines taking care of locks assertions. 723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Note that this checks for recursive locks and allows them 733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // if the variable is set. This is allowed by the underlying implementation 743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // on windows but not on Posix, so we're doing unneeded checks on Posix. 753f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // It's worth it to share the code. 763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void CheckHeldAndUnmark(); 773f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen void CheckUnheldAndMark(); 783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // All private data is implicitly protected by lock_. 803f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Be VERY careful to only access members under that lock. 813f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Determines validity of owning_thread_id_. Needed as we don't have 833f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // a null owning_thread_id_ value. 843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen bool owned_by_thread_; 853f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen base::PlatformThreadId owning_thread_id_; 863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif // NDEBUG 873f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Platform specific underlying lock implementation. 893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen internal::LockImpl lock_; 903f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen DISALLOW_COPY_AND_ASSIGN(Lock); 923f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}; 933f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 943f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// A helper class that acquires the given Lock while the AutoLock is in scope. 953f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass AutoLock { 963f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen public: 973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen explicit AutoLock(Lock& lock) : lock_(lock) { 983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.Acquire(); 993f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1003f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ~AutoLock() { 1023f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.AssertAcquired(); 1033f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.Release(); 1043f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1053f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1063f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen private: 1073f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Lock& lock_; 1083f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen DISALLOW_COPY_AND_ASSIGN(AutoLock); 1093f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}; 1103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// AutoUnlock is a helper that will Release() the |lock| argument in the 1123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// constructor, and re-Acquire() it in the destructor. 1133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass AutoUnlock { 1143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen public: 1153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen explicit AutoUnlock(Lock& lock) : lock_(lock) { 1163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // We require our caller to have the lock. 1173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.AssertAcquired(); 1183f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.Release(); 1193f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ~AutoUnlock() { 1223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen lock_.Acquire(); 1233f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen } 1243f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen private: 1263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen Lock& lock_; 1273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen DISALLOW_COPY_AND_ASSIGN(AutoUnlock); 1283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}; 1293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} // namespace base 1313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#endif // BASE_SYNCHRONIZATION_LOCK_H_ 133