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/WordLock.h>
31
32namespace TestWebKitAPI {
33
34struct LockInspector {
35 template<typename LockType>
36 static bool isFullyReset(LockType& lock)
37 {
38 return lock.isFullyReset();
39 }
40};
41
42template<typename LockType>
43void runLockTest(unsigned numThreadGroups, unsigned numThreadsPerGroup, unsigned workPerCriticalSection, unsigned numIterations)
44{
45 std::unique_ptr<LockType[]> locks = std::make_unique<LockType[]>(numThreadGroups);
46 std::unique_ptr<double[]> words = std::make_unique<double[]>(numThreadGroups);
47 std::unique_ptr<RefPtr<Thread>[]> threads = std::make_unique<RefPtr<Thread>[]>(numThreadGroups * numThreadsPerGroup);
48
49 for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
50 words[threadGroupIndex] = 0;
51
52 for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
53 threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = Thread::create(
54 "Lock test thread",
55 [threadGroupIndex, &locks, &words, numIterations, workPerCriticalSection] () {
56 for (unsigned i = numIterations; i--;) {
57 locks[threadGroupIndex].lock();
58 for (unsigned j = workPerCriticalSection; j--;)
59 words[threadGroupIndex]++;
60 locks[threadGroupIndex].unlock();
61 }
62 });
63 }
64 }
65
66 for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
67 threads[threadIndex]->waitForCompletion();
68
69 double expected = 0;
70 for (uint64_t i = static_cast<uint64_t>(numIterations) * workPerCriticalSection * numThreadsPerGroup; i--;)
71 expected++;
72
73 for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;)
74 EXPECT_EQ(expected, words[threadGroupIndex]);
75
76 // Now test that the locks correctly reset themselves. We expect that if a single thread locks
77 // each of the locks twice in a row, then the lock should be in a pristine state.
78 for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
79 for (unsigned i = 2; i--;) {
80 locks[threadGroupIndex].lock();
81 locks[threadGroupIndex].unlock();
82 }
83
84 EXPECT_EQ(true, LockInspector::isFullyReset(locks[threadGroupIndex]));
85 }
86}
87
88bool skipSlow()
89{
90#if PLATFORM(WIN) && !defined(NDEBUG)
91 return true;
92#else
93 return false;
94#endif
95}
96
97TEST(WTF_WordLock, UncontendedShortSection)
98{
99 runLockTest<WordLock>(1, 1, 1, 10000000);
100}
101
102TEST(WTF_WordLock, UncontendedLongSection)
103{
104 runLockTest<WordLock>(1, 1, 10000, 1000);
105}
106
107TEST(WTF_WordLock, ContendedShortSection)
108{
109 if (skipSlow())
110 return;
111 runLockTest<WordLock>(1, 10, 1, 5000000);
112}
113
114TEST(WTF_WordLock, ContendedLongSection)
115{
116 if (skipSlow())
117 return;
118 runLockTest<WordLock>(1, 10, 10000, 10000);
119}
120
121TEST(WTF_WordLock, ManyContendedShortSections)
122{
123 if (skipSlow())
124 return;
125 runLockTest<WordLock>(10, 10, 1, 500000);
126}
127
128TEST(WTF_WordLock, ManyContendedLongSections)
129{
130 if (skipSlow())
131 return;
132 runLockTest<WordLock>(10, 10, 10000, 500);
133}
134
135TEST(WTF_Lock, UncontendedShortSection)
136{
137 runLockTest<Lock>(1, 1, 1, 10000000);
138}
139
140TEST(WTF_Lock, UncontendedLongSection)
141{
142 runLockTest<Lock>(1, 1, 10000, 1000);
143}
144
145TEST(WTF_Lock, ContendedShortSection)
146{
147 if (skipSlow())
148 return;
149 runLockTest<Lock>(1, 10, 1, 10000000);
150}
151
152TEST(WTF_Lock, ContendedLongSection)
153{
154 if (skipSlow())
155 return;
156 runLockTest<Lock>(1, 10, 10000, 10000);
157}
158
159TEST(WTF_Lock, ManyContendedShortSections)
160{
161 if (skipSlow())
162 return;
163 runLockTest<Lock>(10, 10, 1, 500000);
164}
165
166TEST(WTF_Lock, ManyContendedLongSections)
167{
168 if (skipSlow())
169 return;
170 runLockTest<Lock>(10, 10, 10000, 1000);
171}
172
173TEST(WTF_Lock, ManyContendedLongerSections)
174{
175 if (skipSlow())
176 return;
177 runLockTest<Lock>(10, 10, 100000, 1);
178}
179
180TEST(WTF_Lock, SectionAddressCollision)
181{
182 if (skipSlow())
183 return;
184 runLockTest<Lock>(4, 2, 10000, 2000);
185}
186
187} // namespace TestWebKitAPI
188