spinlock.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. /* Copyright (c) 2006, Google Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Google Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * ---
  32. * Author: Sanjay Ghemawat
  33. */
  34. // SpinLock is async signal safe.
  35. // If used within a signal handler, all lock holders
  36. // should block the signal even outside the signal handler.
  37. #ifndef BASE_SPINLOCK_H_
  38. #define BASE_SPINLOCK_H_
  39. #include <config.h>
  40. #include "base/atomicops.h"
  41. #include "base/basictypes.h"
  42. #include "base/dynamic_annotations.h"
  43. #include "base/thread_annotations.h"
  44. class LOCKABLE SpinLock {
  45. public:
  46. SpinLock() : lockword_(kSpinLockFree) { }
  47. // Special constructor for use with static SpinLock objects. E.g.,
  48. //
  49. // static SpinLock lock(base::LINKER_INITIALIZED);
  50. //
  51. // When intialized using this constructor, we depend on the fact
  52. // that the linker has already initialized the memory appropriately.
  53. // A SpinLock constructed like this can be freely used from global
  54. // initializers without worrying about the order in which global
  55. // initializers run.
  56. explicit SpinLock(base::LinkerInitialized /*x*/) {
  57. // Does nothing; lockword_ is already initialized
  58. }
  59. // Acquire this SpinLock.
  60. // TODO(csilvers): uncomment the annotation when we figure out how to
  61. // support this macro with 0 args (see thread_annotations.h)
  62. inline void Lock() /*EXCLUSIVE_LOCK_FUNCTION()*/ {
  63. if (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
  64. kSpinLockHeld) != kSpinLockFree) {
  65. SlowLock();
  66. }
  67. ANNOTATE_RWLOCK_ACQUIRED(this, 1);
  68. }
  69. // Try to acquire this SpinLock without blocking and return true if the
  70. // acquisition was successful. If the lock was not acquired, false is
  71. // returned. If this SpinLock is free at the time of the call, TryLock
  72. // will return true with high probability.
  73. inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
  74. bool res =
  75. (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
  76. kSpinLockHeld) == kSpinLockFree);
  77. if (res) {
  78. ANNOTATE_RWLOCK_ACQUIRED(this, 1);
  79. }
  80. return res;
  81. }
  82. // Release this SpinLock, which must be held by the calling thread.
  83. // TODO(csilvers): uncomment the annotation when we figure out how to
  84. // support this macro with 0 args (see thread_annotations.h)
  85. inline void Unlock() /*UNLOCK_FUNCTION()*/ {
  86. ANNOTATE_RWLOCK_RELEASED(this, 1);
  87. uint64 prev_value = static_cast<uint64>(
  88. base::subtle::Release_AtomicExchange(&lockword_, kSpinLockFree));
  89. if (prev_value != kSpinLockHeld) {
  90. // Speed the wakeup of any waiter.
  91. SlowUnlock();
  92. }
  93. }
  94. // Determine if the lock is held. When the lock is held by the invoking
  95. // thread, true will always be returned. Intended to be used as
  96. // CHECK(lock.IsHeld()).
  97. inline bool IsHeld() const {
  98. return base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree;
  99. }
  100. static const base::LinkerInitialized LINKER_INITIALIZED; // backwards compat
  101. private:
  102. enum { kSpinLockFree = 0 };
  103. enum { kSpinLockHeld = 1 };
  104. enum { kSpinLockSleeper = 2 };
  105. volatile Atomic32 lockword_;
  106. void SlowLock();
  107. void SlowUnlock();
  108. Atomic32 SpinLoop();
  109. DISALLOW_COPY_AND_ASSIGN(SpinLock);
  110. };
  111. // Corresponding locker object that arranges to acquire a spinlock for
  112. // the duration of a C++ scope.
  113. class SCOPED_LOCKABLE SpinLockHolder {
  114. private:
  115. SpinLock* lock_;
  116. public:
  117. inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l)
  118. : lock_(l) {
  119. l->Lock();
  120. }
  121. // TODO(csilvers): uncomment the annotation when we figure out how to
  122. // support this macro with 0 args (see thread_annotations.h)
  123. inline ~SpinLockHolder() /*UNLOCK_FUNCTION()*/ { lock_->Unlock(); }
  124. };
  125. // Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock);
  126. #define SpinLockHolder(x) COMPILE_ASSERT(0, spin_lock_decl_missing_var_name)
  127. #endif // BASE_SPINLOCK_H_