OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <memory> | |
12 #include <vector> | |
13 | |
14 #include "webrtc/base/bind.h" | |
15 #include "webrtc/base/event.h" | |
16 #include "webrtc/base/gunit.h" | |
17 #include "webrtc/base/task_queue.h" | |
18 #include "webrtc/base/timeutils.h" | |
19 | |
20 namespace rtc { | |
21 | |
22 namespace { | |
23 void CheckCurrent(const char* expected_queue, Event* signal, TaskQueue* queue) { | |
24 EXPECT_TRUE(TaskQueue::IsCurrent(expected_queue)); | |
25 EXPECT_TRUE(queue->IsCurrent()); | |
26 if (signal) | |
27 signal->Set(); | |
28 } | |
29 | |
30 } // namespace | |
31 | |
32 TEST(TaskQueueTest, Construct) { | |
33 static const char kQueueName[] = "Construct"; | |
34 TaskQueue queue(kQueueName); | |
35 EXPECT_FALSE(queue.IsCurrent()); | |
36 } | |
37 | |
38 TEST(TaskQueueTest, PostAndCheckCurrent) { | |
39 static const char kQueueName[] = "PostAndCheckCurrent"; | |
40 TaskQueue queue(kQueueName); | |
41 | |
42 // We're not running a task, so there shouldn't be a current queue. | |
43 EXPECT_FALSE(queue.IsCurrent()); | |
44 EXPECT_FALSE(TaskQueue::Current()); | |
45 | |
46 Event event(false, false); | |
47 queue.PostTask(Bind(&CheckCurrent, kQueueName, &event, &queue)); | |
48 EXPECT_TRUE(event.Wait(1000)); | |
49 } | |
50 | |
51 TEST(TaskQueueTest, PostCustomTask) { | |
52 static const char kQueueName[] = "PostCustomImplementation"; | |
53 TaskQueue queue(kQueueName); | |
54 | |
55 Event event(false, false); | |
56 | |
57 class CustomTask : public QueuedTask { | |
58 public: | |
59 explicit CustomTask(Event* event) : event_(event) {} | |
60 | |
61 private: | |
62 bool Run() override { | |
63 event_->Set(); | |
64 return false; // Never allows the task to be deleted by the queue. | |
65 } | |
66 | |
67 Event* const event_; | |
68 } my_task(&event); | |
69 | |
70 // Please don't do this in production code! :) | |
71 queue.PostTask(std::unique_ptr<QueuedTask>(&my_task)); | |
72 EXPECT_TRUE(event.Wait(1000)); | |
73 } | |
74 | |
75 TEST(TaskQueueTest, PostLambda) { | |
76 static const char kQueueName[] = "PostLambda"; | |
77 TaskQueue queue(kQueueName); | |
78 | |
79 Event event(false, false); | |
80 queue.PostTask([&event]() { event.Set(); }); | |
81 EXPECT_TRUE(event.Wait(1000)); | |
82 } | |
83 | |
84 TEST(TaskQueueTest, PostFromQueue) { | |
85 static const char kQueueName[] = "PostFromQueue"; | |
86 TaskQueue queue(kQueueName); | |
87 | |
88 Event event(false, false); | |
89 queue.PostTask( | |
90 [&event, &queue]() { queue.PostTask([&event]() { event.Set(); }); }); | |
91 EXPECT_TRUE(event.Wait(1000)); | |
92 } | |
93 | |
94 TEST(TaskQueueTest, PostDelayed) { | |
95 static const char kQueueName[] = "PostDelayed"; | |
96 TaskQueue queue(kQueueName); | |
97 | |
98 Event event(false, false); | |
99 uint32_t start = Time(); | |
100 queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100); | |
101 EXPECT_TRUE(event.Wait(1000)); | |
102 uint32_t end = Time(); | |
103 EXPECT_GE(end - start, 100u); | |
104 EXPECT_NEAR(end - start, 200u, 100u); // Accept 100-300. | |
105 } | |
106 | |
107 TEST(TaskQueueTest, PostMultipleDelayed) { | |
108 static const char kQueueName[] = "PostMultipleDelayed"; | |
109 TaskQueue queue(kQueueName); | |
110 | |
111 std::vector<std::unique_ptr<Event>> events; | |
112 for (int i = 0; i < 10; ++i) { | |
113 events.push_back(std::unique_ptr<Event>(new Event(false, false))); | |
114 queue.PostDelayedTask( | |
115 Bind(&CheckCurrent, kQueueName, events.back().get(), &queue), 10); | |
116 } | |
117 | |
118 for (const auto& e : events) | |
119 EXPECT_TRUE(e->Wait(100)); | |
120 } | |
121 | |
122 TEST(TaskQueueTest, PostDelayedAfterDestruct) { | |
123 static const char kQueueName[] = "PostDelayedAfterDestruct"; | |
124 Event event(false, false); | |
125 { | |
126 TaskQueue queue(kQueueName); | |
127 queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100); | |
128 } | |
129 EXPECT_FALSE(event.Wait(200)); // Task should not run. | |
130 } | |
131 | |
132 TEST(TaskQueueTest, PostAndReply) { | |
133 static const char kPostQueue[] = "PostQueue"; | |
134 static const char kReplyQueue[] = "ReplyQueue"; | |
135 TaskQueue post_queue(kPostQueue); | |
136 TaskQueue reply_queue(kReplyQueue); | |
137 | |
138 Event event(false, false); | |
139 post_queue.PostTaskAndReply( | |
140 Bind(&CheckCurrent, kPostQueue, nullptr, &post_queue), | |
141 Bind(&CheckCurrent, kReplyQueue, &event, &reply_queue), &reply_queue); | |
142 EXPECT_TRUE(event.Wait(1000)); | |
143 } | |
144 | |
145 TEST(TaskQueueTest, PostAndReuse) { | |
146 static const char kPostQueue[] = "PostQueue"; | |
147 static const char kReplyQueue[] = "ReplyQueue"; | |
148 TaskQueue post_queue(kPostQueue); | |
149 TaskQueue reply_queue(kReplyQueue); | |
150 | |
151 int call_count = 0; | |
152 | |
153 class ReusedTask : public QueuedTask { | |
154 public: | |
155 ReusedTask(int* counter, TaskQueue* reply_queue, Event* event) | |
156 : counter_(counter), reply_queue_(reply_queue), event_(event) { | |
157 EXPECT_EQ(0, *counter_); | |
158 } | |
159 | |
160 private: | |
161 bool Run() override { | |
162 if (++(*counter_) == 1) { | |
163 std::unique_ptr<QueuedTask> myself(this); | |
164 reply_queue_->PostTask(std::move(myself)); | |
165 // At this point, the object is owned by reply_queue_ and it's | |
166 // theoratically possible that the object has been deleted (e.g. if | |
167 // posting wasn't possible). So, don't touch any member variables here. | |
168 | |
169 // Indicate to the current queue that ownership has been transferred. | |
170 return false; | |
171 } else { | |
172 EXPECT_EQ(2, *counter_); | |
173 EXPECT_TRUE(reply_queue_->IsCurrent()); | |
174 event_->Set(); | |
175 return true; // Indicate that the object should be deleted. | |
176 } | |
177 } | |
178 | |
179 int* const counter_; | |
180 TaskQueue* const reply_queue_; | |
181 Event* const event_; | |
182 }; | |
183 | |
184 Event event(false, false); | |
185 std::unique_ptr<QueuedTask> task( | |
186 new ReusedTask(&call_count, &reply_queue, &event)); | |
187 | |
188 post_queue.PostTask(std::move(task)); | |
189 EXPECT_TRUE(event.Wait(1000)); | |
190 } | |
191 | |
192 TEST(TaskQueueTest, PostAndReplyLambda) { | |
193 static const char kPostQueue[] = "PostQueue"; | |
194 static const char kReplyQueue[] = "ReplyQueue"; | |
195 TaskQueue post_queue(kPostQueue); | |
196 TaskQueue reply_queue(kReplyQueue); | |
197 | |
198 Event event(false, false); | |
199 bool my_flag = false; | |
200 post_queue.PostTaskAndReply([&my_flag]() { my_flag = true; }, | |
201 [&event]() { event.Set(); }, &reply_queue); | |
202 EXPECT_TRUE(event.Wait(1000)); | |
203 EXPECT_TRUE(my_flag); | |
204 } | |
205 | |
206 void TestPostTaskAndReply(TaskQueue* work_queue, | |
207 const char* work_queue_name, | |
208 Event* event) { | |
209 ASSERT_FALSE(work_queue->IsCurrent()); | |
210 work_queue->PostTaskAndReply( | |
211 Bind(&CheckCurrent, work_queue_name, nullptr, work_queue), | |
212 NewClosure([event]() { event->Set(); })); | |
213 } | |
214 | |
215 // Does a PostTaskAndReply from within a task to post and reply to the current | |
216 // queue. All in all there will be 3 tasks posted and run. | |
217 TEST(TaskQueueTest, PostAndReply2) { | |
218 static const char kQueueName[] = "PostAndReply2"; | |
219 static const char kWorkQueueName[] = "PostAndReply2_Worker"; | |
220 TaskQueue queue(kQueueName); | |
221 TaskQueue work_queue(kWorkQueueName); | |
222 | |
223 Event event(false, false); | |
224 queue.PostTask( | |
225 Bind(&TestPostTaskAndReply, &work_queue, kWorkQueueName, &event)); | |
226 EXPECT_TRUE(event.Wait(1000)); | |
227 } | |
228 | |
229 // Tests posting more messages than a queue can queue up. | |
230 // In situations like that, tasks will get dropped. | |
231 TEST(TaskQueueTest, PostALot) { | |
232 // To destruct the event after the queue has gone out of scope. | |
233 Event event(false, false); | |
234 | |
235 int tasks_executed = 0; | |
236 int tasks_cleaned_up = 0; | |
237 static const int kTaskCount = 0xffff; | |
238 | |
239 { | |
240 static const char kQueueName[] = "PostALot"; | |
241 TaskQueue queue(kQueueName); | |
242 | |
243 // On linux, the limit of pending bytes in the pipe buffer is 0xffff. | |
244 // So here we post a total of 0xffff+1 messages, which triggers a failure | |
245 // case inside of the libevent queue implementation. | |
246 | |
247 queue.PostTask([&event]() { event.Wait(Event::kForever); }); | |
248 for (int i = 0; i < kTaskCount; ++i) | |
249 queue.PostTask(NewClosure([&tasks_executed]() { ++tasks_executed; }, | |
250 [&tasks_cleaned_up]() { ++tasks_cleaned_up; })); | |
251 event.Set(); // Unblock the first task. | |
252 } | |
253 | |
254 EXPECT_GE(tasks_cleaned_up, tasks_executed); | |
255 EXPECT_EQ(kTaskCount, tasks_cleaned_up); | |
256 | |
257 LOG(INFO) << "tasks executed: " << tasks_executed | |
258 << ", tasks cleaned up: " << tasks_cleaned_up; | |
259 } | |
260 | |
261 } // namespace rtc | |
OLD | NEW |