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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include <wtf/Lock.h>
28#include <wtf/Threading.h>
29#include <wtf/ThreadingPrimitives.h>
30#include <wtf/UniqueArray.h>
31#include <wtf/WordLock.h>
32
33namespace TestWebKitAPI {
34
35struct LockInspector {
36 template<typename LockType>
37 static bool isFullyReset(LockType& lock)
38 {
39 return lock.isFullyReset();
40 }
41};
42
43template<typename LockType>
44void runLockTest(unsigned numThreadGroups, unsigned numThreadsPerGroup, unsigned workPerCriticalSection, unsigned numIterations)
45{
46 std::unique_ptr<LockType[]> locks = makeUniqueWithoutFastMallocCheck<LockType[]>(numThreadGroups);
47 auto words = makeUniqueArray<double>(numThreadGroups);
48 std::unique_ptr<RefPtr<Thread>[]> threads = makeUniqueWithoutFastMallocCheck<RefPtr<Thread>[]>(numThreadGroups * numThreadsPerGroup);
49
50 for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
51 words[threadGroupIndex] = 0;
52
53 for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
54 threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = Thread::create(
55 "Lock test thread",
56 [threadGroupIndex, &locks, &words, numIterations, workPerCriticalSection] () {
57 for (unsigned i = numIterations; i--;) {
58 locks[threadGroupIndex].lock();
59 for (unsigned j = workPerCriticalSection; j--;)
60 words[threadGroupIndex]++;
61 locks[threadGroupIndex].unlock();
62 }
63 });
64 }
65 }
66
67 for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
68 threads[threadIndex]->waitForCompletion();
69
70 double expected = 0;
71 for (uint64_t i = static_cast<uint64_t>(numIterations) * workPerCriticalSection * numThreadsPerGroup; i--;)
72 expected++;
73
74 for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;)
75 EXPECT_EQ(expected, words[threadGroupIndex]);
76
77 // Now test that the locks correctly reset themselves. We expect that if a single thread locks
78 // each of the locks twice in a row, then the lock should be in a pristine state.
79 for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
80 for (unsigned i = 2; i--;) {
81 locks[threadGroupIndex].lock();
82 locks[threadGroupIndex].unlock();
83 }
84
85 EXPECT_EQ(true, LockInspector::isFullyReset(locks[threadGroupIndex]));
86 }
87}
88
89bool skipSlow()
90{
91#if PLATFORM(WIN) && !defined(NDEBUG)
92 return true;
93#else
94 return false;
95#endif
96}
97
98TEST(WTF_WordLock, UncontendedShortSection)
99{
100 runLockTest<WordLock>(1, 1, 1, 10000000);
101}
102
103TEST(WTF_WordLock, UncontendedLongSection)
104{
105 runLockTest<WordLock>(1, 1, 10000, 1000);
106}
107
108TEST(WTF_WordLock, ContendedShortSection)
109{
110 if (skipSlow())
111 return;
112 runLockTest<WordLock>(1, 10, 1, 5000000);
113}
114
115TEST(WTF_WordLock, ContendedLongSection)
116{
117 if (skipSlow())
118 return;
119 runLockTest<WordLock>(1, 10, 10000, 10000);
120}
121
122TEST(WTF_WordLock, ManyContendedShortSections)
123{
124 if (skipSlow())
125 return;
126 runLockTest<WordLock>(10, 10, 1, 500000);
127}
128
129TEST(WTF_WordLock, ManyContendedLongSections)
130{
131 if (skipSlow())
132 return;
133 runLockTest<WordLock>(10, 10, 10000, 500);
134}
135
136TEST(WTF_Lock, UncontendedShortSection)
137{
138 runLockTest<Lock>(1, 1, 1, 10000000);
139}
140
141TEST(WTF_Lock, UncontendedLongSection)
142{
143 runLockTest<Lock>(1, 1, 10000, 1000);
144}
145
146TEST(WTF_Lock, ContendedShortSection)
147{
148 if (skipSlow())
149 return;
150 runLockTest<Lock>(1, 10, 1, 10000000);
151}
152
153TEST(WTF_Lock, ContendedLongSection)
154{
155 if (skipSlow())
156 return;
157 runLockTest<Lock>(1, 10, 10000, 10000);
158}
159
160TEST(WTF_Lock, ManyContendedShortSections)
161{
162 if (skipSlow())
163 return;
164 runLockTest<Lock>(10, 10, 1, 500000);
165}
166
167TEST(WTF_Lock, ManyContendedLongSections)
168{
169 if (skipSlow())
170 return;
171 runLockTest<Lock>(10, 10, 10000, 1000);
172}
173
174TEST(WTF_Lock, ManyContendedLongerSections)
175{
176 if (skipSlow())
177 return;
178 runLockTest<Lock>(10, 10, 100000, 1);
179}
180
181TEST(WTF_Lock, SectionAddressCollision)
182{
183 if (skipSlow())
184 return;
185 runLockTest<Lock>(4, 2, 10000, 2000);
186}
187
188} // namespace TestWebKitAPI
189