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
28#include "Test.h"
29#include <wtf/Condition.h>
30#include <wtf/Lock.h>
31#include <wtf/Vector.h>
32#include <wtf/WorkQueue.h>
33#include <string>
34#include <thread>
35
36namespace TestWebKitAPI {
37
38using namespace std::literals::chrono_literals;
39
40static const char* simpleTestLabel = "simpleTest";
41static const char* longTestLabel = "longTest";
42static const char* thirdTestLabel = "thirdTest";
43static const char* dispatchAfterLabel = "dispatchAfter";
44
45TEST(WTF_WorkQueue, Simple)
46{
47 Lock m_lock;
48 Condition m_testCompleted;
49 Vector<std::string> m_functionCallOrder;
50
51 bool calledSimpleTest = false;
52 bool calledLongTest = false;
53 bool calledThirdTest = false;
54
55 static const char* simpleTestLabel = "simpleTest";
56 static const char* longTestLabel = "longTest";
57 static const char* thirdTestLabel = "thirdTest";
58
59 auto queue = WorkQueue::create("com.apple.WebKit.Test.simple");
60 int initialRefCount = queue->refCount();
61 EXPECT_EQ(1, initialRefCount);
62
63 LockHolder locker(m_lock);
64 queue->dispatch([&](void) {
65 m_functionCallOrder.append(simpleTestLabel);
66 calledSimpleTest = true;
67 });
68
69 queue->dispatch([&](void) {
70 m_functionCallOrder.append(longTestLabel);
71 std::this_thread::sleep_for(100ns);
72 calledLongTest = true;
73 });
74
75 queue->dispatch([&](void) {
76 LockHolder locker(m_lock);
77 m_functionCallOrder.append(thirdTestLabel);
78 calledThirdTest = true;
79
80 EXPECT_TRUE(calledSimpleTest);
81 EXPECT_TRUE(calledLongTest);
82 EXPECT_TRUE(calledThirdTest);
83
84 m_testCompleted.notifyOne();
85 });
86
87 EXPECT_GT(queue->refCount(), 1);
88
89 m_testCompleted.wait(m_lock);
90
91 EXPECT_TRUE(calledSimpleTest);
92 EXPECT_TRUE(calledLongTest);
93 EXPECT_TRUE(calledThirdTest);
94
95 EXPECT_EQ(static_cast<size_t>(3), m_functionCallOrder.size());
96 EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
97 EXPECT_STREQ(longTestLabel, m_functionCallOrder[1].c_str());
98 EXPECT_STREQ(thirdTestLabel, m_functionCallOrder[2].c_str());
99}
100
101TEST(WTF_WorkQueue, TwoQueues)
102{
103 Lock m_lock;
104 Condition m_testQueue1Completed, m_testQueue2Completed;
105 Vector<std::string> m_functionCallOrder;
106
107 bool calledSimpleTest = false;
108 bool calledLongTest = false;
109 bool calledThirdTest = false;
110
111 auto queue1 = WorkQueue::create("com.apple.WebKit.Test.twoQueues1");
112 auto queue2 = WorkQueue::create("com.apple.WebKit.Test.twoQueues2");
113
114 EXPECT_EQ(1, queue1->refCount());
115 EXPECT_EQ(1, queue2->refCount());
116
117 LockHolder locker(m_lock);
118
119 queue1->dispatch([&](void) {
120 m_functionCallOrder.append(simpleTestLabel);
121 calledSimpleTest = true;
122 });
123
124 queue2->dispatch([&](void) {
125 std::this_thread::sleep_for(50ms);
126
127 LockHolder locker(m_lock);
128
129 // Will fail if queue2 took the mutex before queue1.
130 EXPECT_TRUE(calledThirdTest);
131
132 m_functionCallOrder.append(longTestLabel);
133 calledLongTest = true;
134 m_testQueue2Completed.notifyOne();
135 });
136
137 queue1->dispatch([&](void) {
138 LockHolder locker(m_lock);
139 m_functionCallOrder.append(thirdTestLabel);
140 calledThirdTest = true;
141
142 m_testQueue1Completed.notifyOne();
143 });
144
145 m_testQueue1Completed.wait(m_lock);
146
147 EXPECT_TRUE(calledSimpleTest);
148 EXPECT_FALSE(calledLongTest);
149 EXPECT_TRUE(calledThirdTest);
150
151 m_testQueue2Completed.wait(m_lock);
152
153 EXPECT_TRUE(calledSimpleTest);
154 EXPECT_TRUE(calledLongTest);
155 EXPECT_TRUE(calledThirdTest);
156
157 EXPECT_EQ(static_cast<size_t>(3), m_functionCallOrder.size());
158 EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
159 EXPECT_STREQ(thirdTestLabel, m_functionCallOrder[1].c_str());
160 EXPECT_STREQ(longTestLabel, m_functionCallOrder[2].c_str());
161}
162
163TEST(WTF_WorkQueue, DispatchAfter)
164{
165 Lock m_lock;
166 Condition m_testCompleted, m_dispatchAfterTestCompleted;
167 Vector<std::string> m_functionCallOrder;
168
169 bool calledSimpleTest = false;
170 bool calledDispatchAfterTest = false;
171
172 auto queue = WorkQueue::create("com.apple.WebKit.Test.dispatchAfter");
173
174 LockHolder locker(m_lock);
175
176 queue->dispatch([&](void) {
177 LockHolder locker(m_lock);
178 m_functionCallOrder.append(simpleTestLabel);
179 calledSimpleTest = true;
180 m_testCompleted.notifyOne();
181 });
182
183 queue->dispatchAfter(500_ms, [&](void) {
184 LockHolder locker(m_lock);
185 m_functionCallOrder.append(dispatchAfterLabel);
186 calledDispatchAfterTest = true;
187 m_dispatchAfterTestCompleted.notifyOne();
188 });
189
190 m_testCompleted.wait(m_lock);
191
192 EXPECT_TRUE(calledSimpleTest);
193 EXPECT_FALSE(calledDispatchAfterTest);
194
195 m_dispatchAfterTestCompleted.wait(m_lock);
196
197 EXPECT_TRUE(calledSimpleTest);
198 EXPECT_TRUE(calledDispatchAfterTest);
199
200 EXPECT_EQ(static_cast<size_t>(2), m_functionCallOrder.size());
201 EXPECT_STREQ(simpleTestLabel, m_functionCallOrder[0].c_str());
202 EXPECT_STREQ(dispatchAfterLabel, m_functionCallOrder[1].c_str());
203}
204
205TEST(WTF_WorkQueue, DestroyOnSelf)
206{
207 Lock lock;
208 Condition dispatchAfterTestStarted;
209 Condition dispatchAfterTestCompleted;
210 bool started = false;
211 bool completed = false;
212
213 {
214 LockHolder locker(lock);
215 {
216 auto queue = WorkQueue::create("com.apple.WebKit.Test.dispatchAfter");
217 queue->dispatchAfter(500_ms, [&](void) {
218 LockHolder locker(lock);
219 dispatchAfterTestStarted.wait(lock, [&] {
220 return started;
221 });
222 completed = true;
223 dispatchAfterTestCompleted.notifyOne();
224 });
225 }
226 started = true;
227 dispatchAfterTestStarted.notifyOne();
228 }
229 {
230 LockHolder locker(lock);
231 dispatchAfterTestCompleted.wait(lock, [&] {
232 return completed;
233 });
234 WTF::sleep(100_ms);
235 }
236}
237
238} // namespace TestWebKitAPI
239