7f86c4ef39c39f3ee287e2bdd8b28ca5c819fa9d
[WebKit-https.git] / Source / WTF / wtf / Lock.h
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
34 namespace TestWebKitAPI {
35 struct LockInspector;
36 };
37
38 namespace 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 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 Mutex (if a lock cannot
43 // 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 either SpinLock or 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.
48 struct 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
96 protected:
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
114 class Lock : public LockBase {
115     WTF_MAKE_NONCOPYABLE(Lock);
116 public:
117     Lock()
118     {
119         m_byte.store(0, std::memory_order_relaxed);
120     }
121 };
122
123 typedef LockBase StaticLock;
124 typedef Locker<LockBase> LockHolder;
125
126 } // namespace WTF
127
128 using WTF::Lock;
129 using WTF::LockHolder;
130 using WTF::StaticLock;
131
132 #endif // WTF_Lock_h
133