1/*
2 * Copyright (C) 2015 Apple Inc. 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef WTF_Lock_h
27#define WTF_Lock_h
28
29#include <wtf/Atomics.h>
30#include <wtf/Compiler.h>
31#include <wtf/Locker.h>
32#include <wtf/Noncopyable.h>
33
34namespace TestWebKitAPI {
35struct LockInspector;
36};
37
38namespace WTF {
39
40// This is a fully adaptive mutex that only requires 1 byte of storage. It has fast paths that are
41// competetive to a spinlock (uncontended locking is inlined and is just a CAS, microcontention is
42// handled by spinning and yielding), and a slow path that is competetive to std::mutex (if a lock
43// cannot be acquired in a short period of time, the thread is put to sleep until the lock is available
44// again). It uses less memory than a std::mutex.
45
46// This is a struct without a constructor or destructor so that it can be statically initialized.
47// Use Lock in instance variables.
48struct LockBase {
49 void lock()
50 {
51 if (LIKELY(m_byte.compareExchangeWeak(0, isHeldBit, std::memory_order_acquire))) {
52 // Lock acquired!
53 return;
54 }
55
56 lockSlow();
57 }
58
59 bool tryLock()
60 {
61 for (;;) {
62 uint8_t currentByteValue = m_byte.load();
63 if (currentByteValue & isHeldBit)
64 return false;
65 if (m_byte.compareExchangeWeak(currentByteValue, currentByteValue | isHeldBit))
66 return true;
67 }
68 }
69
70 // Need this version for std::unique_lock.
71 bool try_lock()
72 {
73 return tryLock();
74 }
75
76 void unlock()
77 {
78 if (LIKELY(m_byte.compareExchangeWeak(isHeldBit, 0, std::memory_order_release))) {
79 // Lock released and nobody was waiting!
80 return;
81 }
82
83 unlockSlow();
84 }
85
86 bool isHeld() const
87 {
88 return m_byte.load(std::memory_order_acquire) & isHeldBit;
89 }
90
91 bool isLocked() const
92 {
93 return isHeld();
94 }
95
96protected:
97 friend struct TestWebKitAPI::LockInspector;
98
99 static const uint8_t isHeldBit = 1;
100 static const uint8_t hasParkedBit = 2;
101
102 WTF_EXPORT_PRIVATE void lockSlow();
103 WTF_EXPORT_PRIVATE void unlockSlow();
104
105 // Method used for testing only.
106 bool isFullyReset() const
107 {
108 return !m_byte.load();
109 }
110
111 Atomic<uint8_t> m_byte;
112};
113
114class Lock : public LockBase {
115 WTF_MAKE_NONCOPYABLE(Lock);
116 WTF_MAKE_FAST_ALLOCATED;
117public:
118 Lock()
119 {
120 m_byte.store(0, std::memory_order_relaxed);
121 }
122};
123
124typedef LockBase StaticLock;
125typedef Locker<LockBase> LockHolder;
126
127} // namespace WTF
128
129using WTF::Lock;
130using WTF::LockHolder;
131using WTF::StaticLock;
132
133#endif // WTF_Lock_h
134
135