YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/gutil/spinlock.h
Line
Count
Source
1
/* Copyright (c) 2006, Google Inc.
2
 * All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions are
6
 * met:
7
 *
8
 *     * Redistributions of source code must retain the above copyright
9
 * notice, this list of conditions and the following disclaimer.
10
 *     * Redistributions in binary form must reproduce the above
11
 * copyright notice, this list of conditions and the following disclaimer
12
 * in the documentation and/or other materials provided with the
13
 * distribution.
14
 *     * Neither the name of Google Inc. nor the names of its
15
 * contributors may be used to endorse or promote products derived from
16
 * this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
 *
30
 * The following only applies to changes made to this file as part of YugaByte development.
31
 *
32
 * Portions Copyright (c) YugaByte, Inc.
33
 *
34
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
35
 * in compliance with the License.  You may obtain a copy of the License at
36
 *
37
 * http://www.apache.org/licenses/LICENSE-2.0
38
 *
39
 * Unless required by applicable law or agreed to in writing, software distributed under the License
40
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
41
 * or implied.  See the License for the specific language governing permissions and limitations
42
 * under the License.
43
 *
44
 *
45
 * ---
46
 * Author: Sanjay Ghemawat
47
 */
48
49
// SpinLock is async signal safe.
50
// If used within a signal handler, all lock holders
51
// should block the signal even outside the signal handler.
52
53
#ifndef YB_GUTIL_SPINLOCK_H
54
#define YB_GUTIL_SPINLOCK_H
55
56
#include "yb/gutil/atomicops.h"
57
#include "yb/gutil/dynamic_annotations.h"
58
#include "yb/gutil/macros.h"
59
#include "yb/gutil/thread_annotations.h"
60
61
// This isn't originally in the base:: namespace in tcmalloc,
62
// but tcmalloc inadvertently exports these symbols. So, if we
63
// don't namespace it differently, we conflict.
64
namespace base {
65
66
class CAPABILITY("mutex") SpinLock {
67
 public:
68
166M
  SpinLock() : lockword_(kSpinLockFree) { }
69
70
  // Special constructor for use with static SpinLock objects.  E.g.,
71
  //
72
  //    static SpinLock lock(base::LINKER_INITIALIZED);
73
  //
74
  // When intialized using this constructor, we depend on the fact
75
  // that the linker has already initialized the memory appropriately.
76
  // A SpinLock constructed like this can be freely used from global
77
  // initializers without worrying about the order in which global
78
  // initializers run.
79
  explicit SpinLock(base::LinkerInitialized /*x*/)
80
36.4k
      : lockword_(kSpinLockFree) {
81
36.4k
  }
82
83
  // Acquire this SpinLock.
84
  // TODO(csilvers): uncomment the annotation when we figure out how to
85
  //                 support this macro with 0 args (see thread_annotations.h)
86
1.32G
  inline void Lock() ACQUIRE() {
87
1.32G
    if (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
88
13.5M
                                             kSpinLockHeld) != kSpinLockFree) {
89
13.5M
      SlowLock();
90
13.5M
    }
91
1.32G
    ANNOTATE_RWLOCK_ACQUIRED(this, 1);
92
1.32G
#ifdef __aarch64__
93
1.32G
    __asm__ __volatile__ ("dmb ish" ::: "memory");
94
1.32G
#endif
95
1.32G
  }
96
97
  // Try to acquire this SpinLock without blocking and return true if the
98
  // acquisition was successful.  If the lock was not acquired, false is
99
  // returned.  If this SpinLock is free at the time of the call, TryLock
100
  // will return true with high probability.
101
629
  inline bool TryLock() TRY_ACQUIRE(true) {
102
629
    bool res =
103
629
        (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
104
629
                                              kSpinLockHeld) == kSpinLockFree);
105
629
    if (res) {
106
629
      ANNOTATE_RWLOCK_ACQUIRED(this, 1);
107
629
    }
108
629
#ifdef __aarch64__
109
629
    __asm__ __volatile__ ("dmb ish" ::: "memory");
110
629
#endif
111
629
    return res;
112
629
  }
113
114
  // Release this SpinLock, which must be held by the calling thread.
115
  // TODO(csilvers): uncomment the annotation when we figure out how to
116
  //                 support this macro with 0 args (see thread_annotations.h)
117
1.32G
  inline void Unlock() RELEASE() {
118
1.32G
    ANNOTATE_RWLOCK_RELEASED(this, 1);
119
1.32G
    uint64 wait_cycles = static_cast<uint64>(
120
1.32G
        base::subtle::Release_AtomicExchange(&lockword_, kSpinLockFree));
121
1.32G
    if (wait_cycles != kSpinLockHeld) {
122
      // Collect contentionz profile info, and speed the wakeup of any waiter.
123
      // The wait_cycles value indicates how long this thread spent waiting
124
      // for the lock.
125
18.1M
      SlowUnlock(wait_cycles);
126
18.1M
    }
127
1.32G
#ifdef __aarch64__
128
1.32G
    __asm__ __volatile__ ("dmb ish" ::: "memory");
129
1.32G
#endif
130
1.32G
  }
131
132
  // Determine if the lock is held.  When the lock is held by the invoking
133
  // thread, true will always be returned. Intended to be used as
134
  // CHECK(lock.IsHeld()).
135
105M
  inline bool IsHeld() const {
136
105M
    return base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree;
137
105M
  }
138
139
  static const base::LinkerInitialized LINKER_INITIALIZED;  // backwards compat
140
 private:
141
  enum { kSpinLockFree = 0 };
142
  enum { kSpinLockHeld = 1 };
143
  enum { kSpinLockSleeper = 2 };
144
145
  volatile Atomic32 lockword_;
146
147
  void SlowLock();
148
  void SlowUnlock(uint64 wait_cycles);
149
  Atomic32 SpinLoop(int64 initial_wait_timestamp, Atomic32* wait_cycles);
150
  inline int32 CalculateWaitCycles(int64 wait_start_time);
151
152
  DISALLOW_COPY_AND_ASSIGN(SpinLock);
153
};
154
155
// Corresponding locker object that arranges to acquire a spinlock for
156
// the duration of a C++ scope.
157
class SCOPED_CAPABILITY SpinLockHolder {
158
 private:
159
  SpinLock* lock_;
160
 public:
161
  inline explicit SpinLockHolder(SpinLock* l) ACQUIRE(l)
162
621k
      : lock_(l) {
163
621k
    l->Lock();
164
621k
  }
165
166
621k
  inline ~SpinLockHolder() RELEASE() { lock_->Unlock(); }
167
};
168
// Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock);
169
#define SpinLockHolder(x) COMPILE_ASSERT(0, spin_lock_decl_missing_var_name)
170
171
} // namespace base
172
173
#endif  // YB_GUTIL_SPINLOCK_H