1// Copyright (c) 2005, 2006, Google Inc.
2// Copyright (c) 2010, Patrick Gansterer <paroga@paroga.com>
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 <opensource@google.com>
33
34#ifndef TCMALLOC_INTERNAL_SPINLOCK_H__
35#define TCMALLOC_INTERNAL_SPINLOCK_H__
36
37#include <wtf/Atomics.h>
38#if OS(UNIX)
39#include <sched.h>
40#endif
41
42#if ENABLE(COMPARE_AND_SWAP)
43
44static void TCMalloc_SlowLock(unsigned* lockword);
45
46// The following is a struct so that it can be initialized at compile time
47struct TCMalloc_SpinLock {
48    void Lock() {
49      if (!WTF::weakCompareAndSwap(&lockword_, 0, 1))
50        TCMalloc_SlowLock(&lockword_);
51      WTF::memoryBarrierAfterLock();
52    }
53
54    void Unlock() {
55      WTF::memoryBarrierBeforeUnlock();
56      lockword_ = 0;
57    }
58
59    // Report if we think the lock can be held by this thread.
60    // When the lock is truly held by the invoking thread
61    // we will always return true.
62    // Indended to be used as CHECK(lock.IsHeld());
63    bool IsHeld() const {
64        return lockword_ != 0;
65    }
66
67    void Init() { lockword_ = 0; }
68    void Finalize() { }
69
70    unsigned lockword_;
71};
72
73#define SPINLOCK_INITIALIZER { 0 }
74
75static void TCMalloc_SlowLock(unsigned* lockword) {
76  do {
77#if OS(WINDOWS)
78    Sleep(0);
79#else
80    sched_yield();
81#endif
82  } while (!WTF::weakCompareAndSwap(lockword, 0, 1));
83}
84
85#else
86
87#include <pthread.h>
88
89// Portable version
90struct TCMalloc_SpinLock {
91  pthread_mutex_t private_lock_;
92
93  inline void Init() {
94    if (pthread_mutex_init(&private_lock_, NULL) != 0) CRASH();
95  }
96  inline void Finalize() {
97    if (pthread_mutex_destroy(&private_lock_) != 0) CRASH();
98  }
99  inline void Lock() {
100    if (pthread_mutex_lock(&private_lock_) != 0) CRASH();
101  }
102  inline void Unlock() {
103    if (pthread_mutex_unlock(&private_lock_) != 0) CRASH();
104  }
105  bool IsHeld() {
106    if (pthread_mutex_trylock(&private_lock_))
107      return true;
108
109    Unlock();
110    return false;
111  }
112};
113
114#define SPINLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
115
116#endif
117
118// Corresponding locker object that arranges to acquire a spinlock for
119// the duration of a C++ scope.
120class TCMalloc_SpinLockHolder {
121 private:
122  TCMalloc_SpinLock* lock_;
123 public:
124  inline explicit TCMalloc_SpinLockHolder(TCMalloc_SpinLock* l)
125    : lock_(l) { l->Lock(); }
126  inline ~TCMalloc_SpinLockHolder() { lock_->Unlock(); }
127};
128
129// Short-hands for convenient use by tcmalloc.cc
130typedef TCMalloc_SpinLock SpinLock;
131typedef TCMalloc_SpinLockHolder SpinLockHolder;
132
133#endif  // TCMALLOC_INTERNAL_SPINLOCK_H__
134