blob: 8834ab57ef177ad100536fa587250a8be1b349ac [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 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 "webrtc/base/messagequeue.h"
12
Taylor Brandstetterfe7d0912016-09-15 17:47:42 -070013#include <functional>
14
15#include "webrtc/base/atomicops.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016#include "webrtc/base/bind.h"
Taylor Brandstetterfe7d0912016-09-15 17:47:42 -070017#include "webrtc/base/event.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018#include "webrtc/base/gunit.h"
19#include "webrtc/base/logging.h"
20#include "webrtc/base/thread.h"
21#include "webrtc/base/timeutils.h"
22#include "webrtc/base/nullsocketserver.h"
23
24using namespace rtc;
25
decurtis@webrtc.org2af30572015-02-21 01:59:50 +000026class MessageQueueTest: public testing::Test, public MessageQueue {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000027 public:
danilchapbebf54c2016-04-28 01:32:48 -070028 MessageQueueTest() : MessageQueue(SocketServer::CreateDefault(), true) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000029 bool IsLocked_Worker() {
30 if (!crit_.TryEnter()) {
31 return true;
32 }
33 crit_.Leave();
34 return false;
35 }
36 bool IsLocked() {
37 // We have to do this on a worker thread, or else the TryEnter will
38 // succeed, since our critical sections are reentrant.
39 Thread worker;
40 worker.Start();
41 return worker.Invoke<bool>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070042 RTC_FROM_HERE, rtc::Bind(&MessageQueueTest::IsLocked_Worker, this));
decurtis@webrtc.org2bffc3c2015-02-21 01:45:04 +000043 }
decurtis@webrtc.org2bffc3c2015-02-21 01:45:04 +000044};
45
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000046struct DeletedLockChecker {
decurtis@webrtc.org2af30572015-02-21 01:59:50 +000047 DeletedLockChecker(MessageQueueTest* test, bool* was_locked, bool* deleted)
48 : test(test), was_locked(was_locked), deleted(deleted) { }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049 ~DeletedLockChecker() {
50 *deleted = true;
decurtis@webrtc.org2af30572015-02-21 01:59:50 +000051 *was_locked = test->IsLocked();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000052 }
decurtis@webrtc.org2af30572015-02-21 01:59:50 +000053 MessageQueueTest* test;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000054 bool* was_locked;
55 bool* deleted;
56};
57
58static void DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(
59 MessageQueue* q) {
60 EXPECT_TRUE(q != NULL);
Honghai Zhang82d78622016-05-06 11:29:15 -070061 int64_t now = TimeMillis();
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070062 q->PostAt(RTC_FROM_HERE, now, NULL, 3);
63 q->PostAt(RTC_FROM_HERE, now - 2, NULL, 0);
64 q->PostAt(RTC_FROM_HERE, now - 1, NULL, 1);
65 q->PostAt(RTC_FROM_HERE, now, NULL, 4);
66 q->PostAt(RTC_FROM_HERE, now - 1, NULL, 2);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067
68 Message msg;
69 for (size_t i=0; i<5; ++i) {
70 memset(&msg, 0, sizeof(msg));
71 EXPECT_TRUE(q->Get(&msg, 0));
72 EXPECT_EQ(i, msg.message_id);
73 }
74
75 EXPECT_FALSE(q->Get(&msg, 0)); // No more messages
76}
77
78TEST_F(MessageQueueTest,
79 DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder) {
danilchapbebf54c2016-04-28 01:32:48 -070080 MessageQueue q(SocketServer::CreateDefault(), true);
decurtis@webrtc.org2af30572015-02-21 01:59:50 +000081 DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(&q);
danilchapbebf54c2016-04-28 01:32:48 -070082
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083 NullSocketServer nullss;
danilchapbebf54c2016-04-28 01:32:48 -070084 MessageQueue q_nullss(&nullss, true);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000085 DelayedPostsWithIdenticalTimesAreProcessedInFifoOrder(&q_nullss);
86}
87
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +000088TEST_F(MessageQueueTest, DisposeNotLocked) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000089 bool was_locked = true;
90 bool deleted = false;
decurtis@webrtc.org2af30572015-02-21 01:59:50 +000091 DeletedLockChecker* d = new DeletedLockChecker(this, &was_locked, &deleted);
92 Dispose(d);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093 Message msg;
decurtis@webrtc.org2af30572015-02-21 01:59:50 +000094 EXPECT_FALSE(Get(&msg, 0));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095 EXPECT_TRUE(deleted);
96 EXPECT_FALSE(was_locked);
97}
98
99class DeletedMessageHandler : public MessageHandler {
100 public:
101 explicit DeletedMessageHandler(bool* deleted) : deleted_(deleted) { }
102 ~DeletedMessageHandler() {
103 *deleted_ = true;
104 }
105 void OnMessage(Message* msg) { }
106 private:
107 bool* deleted_;
108};
109
decurtis@webrtc.org2af30572015-02-21 01:59:50 +0000110TEST_F(MessageQueueTest, DiposeHandlerWithPostedMessagePending) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 bool deleted = false;
112 DeletedMessageHandler *handler = new DeletedMessageHandler(&deleted);
113 // First, post a dispose.
decurtis@webrtc.org2af30572015-02-21 01:59:50 +0000114 Dispose(handler);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000115 // Now, post a message, which should *not* be returned by Get().
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700116 Post(RTC_FROM_HERE, handler, 1);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 Message msg;
decurtis@webrtc.org2af30572015-02-21 01:59:50 +0000118 EXPECT_FALSE(Get(&msg, 0));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000119 EXPECT_TRUE(deleted);
120}
121
122struct UnwrapMainThreadScope {
123 UnwrapMainThreadScope() : rewrap_(Thread::Current() != NULL) {
124 if (rewrap_) ThreadManager::Instance()->UnwrapCurrentThread();
125 }
126 ~UnwrapMainThreadScope() {
127 if (rewrap_) ThreadManager::Instance()->WrapCurrentThread();
128 }
129 private:
130 bool rewrap_;
131};
132
decurtis@webrtc.org2af30572015-02-21 01:59:50 +0000133TEST(MessageQueueManager, Clear) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000134 UnwrapMainThreadScope s;
135 if (MessageQueueManager::IsInitialized()) {
136 LOG(LS_INFO) << "Unable to run MessageQueueManager::Clear test, since the "
137 << "MessageQueueManager was already initialized by some "
138 << "other test in this run.";
139 return;
140 }
141 bool deleted = false;
142 DeletedMessageHandler* handler = new DeletedMessageHandler(&deleted);
143 delete handler;
144 EXPECT_TRUE(deleted);
145 EXPECT_FALSE(MessageQueueManager::IsInitialized());
146}
Taylor Brandstetterfe7d0912016-09-15 17:47:42 -0700147
148// Ensure that ProcessAllMessageQueues does its essential function; process
149// all messages (both delayed and non delayed) up until the current time, on
150// all registered message queues.
151TEST(MessageQueueManager, ProcessAllMessageQueues) {
152 Event entered_process_all_message_queues(true, false);
153 Thread a;
154 Thread b;
155 a.Start();
156 b.Start();
157
158 volatile int messages_processed = 0;
159 FunctorMessageHandler<void, std::function<void()>> incrementer(
160 [&messages_processed, &entered_process_all_message_queues] {
161 // Wait for event as a means to ensure Increment doesn't occur outside
162 // of ProcessAllMessageQueues. The event is set by a message posted to
163 // the main thread, which is guaranteed to be handled inside
164 // ProcessAllMessageQueues.
165 entered_process_all_message_queues.Wait(Event::kForever);
166 AtomicOps::Increment(&messages_processed);
167 });
168 FunctorMessageHandler<void, std::function<void()>> event_signaler(
169 [&entered_process_all_message_queues] {
170 entered_process_all_message_queues.Set();
171 });
172
173 // Post messages (both delayed and non delayed) to both threads.
174 a.Post(RTC_FROM_HERE, &incrementer);
175 b.Post(RTC_FROM_HERE, &incrementer);
176 a.PostDelayed(RTC_FROM_HERE, 0, &incrementer);
177 b.PostDelayed(RTC_FROM_HERE, 0, &incrementer);
178 rtc::Thread::Current()->Post(RTC_FROM_HERE, &event_signaler);
179
180 MessageQueueManager::ProcessAllMessageQueues();
181 EXPECT_EQ(4, AtomicOps::AcquireLoad(&messages_processed));
182}
183
184// Test that ProcessAllMessageQueues doesn't hang if a thread is quitting.
185TEST(MessageQueueManager, ProcessAllMessageQueuesWithQuittingThread) {
186 Thread t;
187 t.Start();
188 t.Quit();
189 MessageQueueManager::ProcessAllMessageQueues();
190}
191
192// Test that ProcessAllMessageQueues doesn't hang if a queue clears its
193// messages.
194TEST(MessageQueueManager, ProcessAllMessageQueuesWithClearedQueue) {
195 Event entered_process_all_message_queues(true, false);
196 Thread t;
197 t.Start();
198
199 FunctorMessageHandler<void, std::function<void()>> clearer(
200 [&entered_process_all_message_queues] {
201 // Wait for event as a means to ensure Clear doesn't occur outside of
202 // ProcessAllMessageQueues. The event is set by a message posted to the
203 // main thread, which is guaranteed to be handled inside
204 // ProcessAllMessageQueues.
205 entered_process_all_message_queues.Wait(Event::kForever);
206 rtc::Thread::Current()->Clear(nullptr);
207 });
208 FunctorMessageHandler<void, std::function<void()>> event_signaler(
209 [&entered_process_all_message_queues] {
210 entered_process_all_message_queues.Set();
211 });
212
213 // Post messages (both delayed and non delayed) to both threads.
214 t.Post(RTC_FROM_HERE, &clearer);
215 rtc::Thread::Current()->Post(RTC_FROM_HERE, &event_signaler);
216 MessageQueueManager::ProcessAllMessageQueues();
217}