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