blob: 3878676a4470e9db0a6ed4e31058a1d3ed9a9c1f [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/asyncinvoker.h"
12#include "webrtc/base/asyncudpsocket.h"
13#include "webrtc/base/event.h"
14#include "webrtc/base/gunit.h"
15#include "webrtc/base/physicalsocketserver.h"
16#include "webrtc/base/socketaddress.h"
17#include "webrtc/base/thread.h"
henrike@webrtc.orgfded02c2014-09-19 13:10:10 +000018#include "webrtc/test/testsupport/gtest_disable.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019
20#if defined(WEBRTC_WIN)
21#include <comdef.h> // NOLINT
22#endif
23
24using namespace rtc;
25
26// Generates a sequence of numbers (collaboratively).
27class TestGenerator {
28 public:
29 TestGenerator() : last(0), count(0) {}
30
31 int Next(int prev) {
32 int result = prev + last;
33 last = result;
34 count += 1;
35 return result;
36 }
37
38 int last;
39 int count;
40};
41
42struct TestMessage : public MessageData {
43 explicit TestMessage(int v) : value(v) {}
44 virtual ~TestMessage() {}
45
46 int value;
47};
48
49// Receives on a socket and sends by posting messages.
50class SocketClient : public TestGenerator, public sigslot::has_slots<> {
51 public:
52 SocketClient(AsyncSocket* socket, const SocketAddress& addr,
53 Thread* post_thread, MessageHandler* phandler)
54 : socket_(AsyncUDPSocket::Create(socket, addr)),
55 post_thread_(post_thread),
56 post_handler_(phandler) {
57 socket_->SignalReadPacket.connect(this, &SocketClient::OnPacket);
58 }
59
60 ~SocketClient() {
61 delete socket_;
62 }
63
64 SocketAddress address() const { return socket_->GetLocalAddress(); }
65
66 void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
67 const SocketAddress& remote_addr,
68 const PacketTime& packet_time) {
Peter Boström0c4e06b2015-10-07 12:23:21 +020069 EXPECT_EQ(size, sizeof(uint32_t));
70 uint32_t prev = reinterpret_cast<const uint32_t*>(buf)[0];
71 uint32_t result = Next(prev);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000072
73 post_thread_->PostDelayed(200, post_handler_, 0, new TestMessage(result));
74 }
75
76 private:
77 AsyncUDPSocket* socket_;
78 Thread* post_thread_;
79 MessageHandler* post_handler_;
80};
81
82// Receives messages and sends on a socket.
83class MessageClient : public MessageHandler, public TestGenerator {
84 public:
85 MessageClient(Thread* pth, Socket* socket)
86 : socket_(socket) {
87 }
88
89 virtual ~MessageClient() {
90 delete socket_;
91 }
92
93 virtual void OnMessage(Message *pmsg) {
94 TestMessage* msg = static_cast<TestMessage*>(pmsg->pdata);
95 int result = Next(msg->value);
96 EXPECT_GE(socket_->Send(&result, sizeof(result)), 0);
97 delete msg;
98 }
99
100 private:
101 Socket* socket_;
102};
103
104class CustomThread : public rtc::Thread {
105 public:
106 CustomThread() {}
107 virtual ~CustomThread() { Stop(); }
108 bool Start() { return false; }
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000109
110 bool WrapCurrent() {
111 return Thread::WrapCurrent();
112 }
113 void UnwrapCurrent() {
114 Thread::UnwrapCurrent();
115 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116};
117
118
119// A thread that does nothing when it runs and signals an event
120// when it is destroyed.
121class SignalWhenDestroyedThread : public Thread {
122 public:
123 SignalWhenDestroyedThread(Event* event)
124 : event_(event) {
125 }
126
127 virtual ~SignalWhenDestroyedThread() {
128 Stop();
129 event_->Set();
130 }
131
132 virtual void Run() {
133 // Do nothing.
134 }
135
136 private:
137 Event* event_;
138};
139
nissed9b75be2015-11-16 00:54:07 -0800140// A bool wrapped in a mutex, to avoid data races. Using a volatile
141// bool should be sufficient for correct code ("eventual consistency"
142// between caches is sufficient), but we can't tell the compiler about
143// that, and then tsan complains about a data race.
144
145// See also discussion at
146// http://stackoverflow.com/questions/7223164/is-mutex-needed-to-synchronize-a-simple-flag-between-pthreads
147
148// Using std::atomic<bool> or std::atomic_flag in C++11 is probably
149// the right thing to do, but those features are not yet allowed. Or
150// rtc::AtomicInt, if/when that is added. Since the use isn't
151// performance critical, use a plain critical section for the time
152// being.
153
154class AtomicBool {
155 public:
156 explicit AtomicBool(bool value = false) : flag_(value) {}
157 AtomicBool& operator=(bool value) {
158 CritScope scoped_lock(&cs_);
159 flag_ = value;
160 return *this;
161 }
162 bool get() const {
163 CritScope scoped_lock(&cs_);
164 return flag_;
165 }
166
167 private:
168 mutable CriticalSection cs_;
169 bool flag_;
170};
171
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172// Function objects to test Thread::Invoke.
173struct FunctorA {
174 int operator()() { return 42; }
175};
176class FunctorB {
177 public:
nissed9b75be2015-11-16 00:54:07 -0800178 explicit FunctorB(AtomicBool* flag) : flag_(flag) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000179 void operator()() { if (flag_) *flag_ = true; }
180 private:
nissed9b75be2015-11-16 00:54:07 -0800181 AtomicBool* flag_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000182};
183struct FunctorC {
184 int operator()() {
185 Thread::Current()->ProcessMessages(50);
186 return 24;
187 }
188};
189
190// See: https://code.google.com/p/webrtc/issues/detail?id=2409
191TEST(ThreadTest, DISABLED_Main) {
192 const SocketAddress addr("127.0.0.1", 0);
193
194 // Create the messaging client on its own thread.
195 Thread th1;
196 Socket* socket = th1.socketserver()->CreateAsyncSocket(addr.family(),
197 SOCK_DGRAM);
198 MessageClient msg_client(&th1, socket);
199
200 // Create the socket client on its own thread.
201 Thread th2;
202 AsyncSocket* asocket =
203 th2.socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
204 SocketClient sock_client(asocket, addr, &th1, &msg_client);
205
206 socket->Connect(sock_client.address());
207
208 th1.Start();
209 th2.Start();
210
211 // Get the messages started.
212 th1.PostDelayed(100, &msg_client, 0, new TestMessage(1));
213
214 // Give the clients a little while to run.
215 // Messages will be processed at 100, 300, 500, 700, 900.
216 Thread* th_main = Thread::Current();
217 th_main->ProcessMessages(1000);
218
219 // Stop the sending client. Give the receiver a bit longer to run, in case
220 // it is running on a machine that is under load (e.g. the build machine).
221 th1.Stop();
222 th_main->ProcessMessages(200);
223 th2.Stop();
224
225 // Make sure the results were correct
226 EXPECT_EQ(5, msg_client.count);
227 EXPECT_EQ(34, msg_client.last);
228 EXPECT_EQ(5, sock_client.count);
229 EXPECT_EQ(55, sock_client.last);
230}
231
232// Test that setting thread names doesn't cause a malfunction.
233// There's no easy way to verify the name was set properly at this time.
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000234TEST(ThreadTest, Names) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235 // Default name
236 Thread *thread;
237 thread = new Thread();
238 EXPECT_TRUE(thread->Start());
239 thread->Stop();
240 delete thread;
241 thread = new Thread();
242 // Name with no object parameter
243 EXPECT_TRUE(thread->SetName("No object", NULL));
244 EXPECT_TRUE(thread->Start());
245 thread->Stop();
246 delete thread;
247 // Really long name
248 thread = new Thread();
249 EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this));
250 EXPECT_TRUE(thread->Start());
251 thread->Stop();
252 delete thread;
253}
254
255// Test that setting thread priorities doesn't cause a malfunction.
256// There's no easy way to verify the priority was set properly at this time.
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000257TEST(ThreadTest, Priorities) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000258 Thread *thread;
259 thread = new Thread();
260 EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH));
261 EXPECT_TRUE(thread->Start());
262 thread->Stop();
263 delete thread;
264 thread = new Thread();
265 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
266 EXPECT_TRUE(thread->Start());
267 thread->Stop();
268 delete thread;
269
270 thread = new Thread();
271 EXPECT_TRUE(thread->Start());
272#if defined(WEBRTC_WIN)
273 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
274#else
275 EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
276#endif
277 thread->Stop();
278 delete thread;
279
280}
281
henrike@webrtc.orge30dab72014-10-09 15:41:40 +0000282TEST(ThreadTest, Wrap) {
283 Thread* current_thread = Thread::Current();
284 current_thread->UnwrapCurrent();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000285 CustomThread* cthread = new CustomThread();
286 EXPECT_TRUE(cthread->WrapCurrent());
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000287 EXPECT_TRUE(cthread->RunningForTest());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000288 EXPECT_FALSE(cthread->IsOwned());
289 cthread->UnwrapCurrent();
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000290 EXPECT_FALSE(cthread->RunningForTest());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000291 delete cthread;
henrike@webrtc.orge30dab72014-10-09 15:41:40 +0000292 current_thread->WrapCurrent();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000293}
294
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000295TEST(ThreadTest, Invoke) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000296 // Create and start the thread.
297 Thread thread;
298 thread.Start();
299 // Try calling functors.
300 EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
nissed9b75be2015-11-16 00:54:07 -0800301 AtomicBool called;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302 FunctorB f2(&called);
303 thread.Invoke<void>(f2);
nissed9b75be2015-11-16 00:54:07 -0800304 EXPECT_TRUE(called.get());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000305 // Try calling bare functions.
306 struct LocalFuncs {
307 static int Func1() { return 999; }
308 static void Func2() {}
309 };
310 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
311 thread.Invoke<void>(&LocalFuncs::Func2);
312}
313
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000314// Verifies that two threads calling Invoke on each other at the same time does
315// not deadlock.
316TEST(ThreadTest, TwoThreadsInvokeNoDeadlock) {
317 AutoThread thread;
318 Thread* current_thread = Thread::Current();
319 ASSERT_TRUE(current_thread != NULL);
320
321 Thread other_thread;
322 other_thread.Start();
323
324 struct LocalFuncs {
325 static void Set(bool* out) { *out = true; }
326 static void InvokeSet(Thread* thread, bool* out) {
327 thread->Invoke<void>(Bind(&Set, out));
328 }
329 };
330
331 bool called = false;
332 other_thread.Invoke<void>(
333 Bind(&LocalFuncs::InvokeSet, current_thread, &called));
334
335 EXPECT_TRUE(called);
336}
337
338// Verifies that if thread A invokes a call on thread B and thread C is trying
339// to invoke A at the same time, thread A does not handle C's invoke while
340// invoking B.
341TEST(ThreadTest, ThreeThreadsInvoke) {
342 AutoThread thread;
343 Thread* thread_a = Thread::Current();
344 Thread thread_b, thread_c;
345 thread_b.Start();
346 thread_c.Start();
347
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000348 class LockedBool {
349 public:
350 explicit LockedBool(bool value) : value_(value) {}
351
352 void Set(bool value) {
353 CritScope lock(&crit_);
354 value_ = value;
355 }
356
357 bool Get() {
358 CritScope lock(&crit_);
359 return value_;
360 }
361
362 private:
363 CriticalSection crit_;
364 bool value_ GUARDED_BY(crit_);
365 };
366
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000367 struct LocalFuncs {
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000368 static void Set(LockedBool* out) { out->Set(true); }
369 static void InvokeSet(Thread* thread, LockedBool* out) {
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000370 thread->Invoke<void>(Bind(&Set, out));
371 }
372
373 // Set |out| true and call InvokeSet on |thread|.
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000374 static void SetAndInvokeSet(LockedBool* out,
375 Thread* thread,
376 LockedBool* out_inner) {
377 out->Set(true);
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000378 InvokeSet(thread, out_inner);
379 }
380
381 // Asynchronously invoke SetAndInvokeSet on |thread1| and wait until
382 // |thread1| starts the call.
383 static void AsyncInvokeSetAndWait(
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000384 Thread* thread1, Thread* thread2, LockedBool* out) {
385 CriticalSection crit;
386 LockedBool async_invoked(false);
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000387
388 AsyncInvoker invoker;
389 invoker.AsyncInvoke<void>(
390 thread1, Bind(&SetAndInvokeSet, &async_invoked, thread2, out));
391
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000392 EXPECT_TRUE_WAIT(async_invoked.Get(), 2000);
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000393 }
394 };
395
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000396 LockedBool thread_a_called(false);
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000397
398 // Start the sequence A --(invoke)--> B --(async invoke)--> C --(invoke)--> A.
399 // Thread B returns when C receives the call and C should be blocked until A
400 // starts to process messages.
401 thread_b.Invoke<void>(Bind(&LocalFuncs::AsyncInvokeSetAndWait,
402 &thread_c, thread_a, &thread_a_called));
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000403 EXPECT_FALSE(thread_a_called.Get());
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000404
pbos@webrtc.orge93cbd12014-10-15 14:54:56 +0000405 EXPECT_TRUE_WAIT(thread_a_called.Get(), 2000);
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000406}
407
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000408class AsyncInvokeTest : public testing::Test {
409 public:
410 void IntCallback(int value) {
411 EXPECT_EQ(expected_thread_, Thread::Current());
412 int_value_ = value;
413 }
414 void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
415 expected_thread_ = thread;
416 invoker->AsyncInvoke(thread, FunctorC(),
417 &AsyncInvokeTest::IntCallback,
418 static_cast<AsyncInvokeTest*>(this));
419 invoke_started_.Set();
420 }
421 void SetExpectedThreadForIntCallback(Thread* thread) {
422 expected_thread_ = thread;
423 }
424
425 protected:
426 enum { kWaitTimeout = 1000 };
427 AsyncInvokeTest()
428 : int_value_(0),
429 invoke_started_(true, false),
430 expected_thread_(NULL) {}
431
432 int int_value_;
433 Event invoke_started_;
434 Thread* expected_thread_;
435};
436
henrike@webrtc.orge30dab72014-10-09 15:41:40 +0000437TEST_F(AsyncInvokeTest, FireAndForget) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000438 AsyncInvoker invoker;
439 // Create and start the thread.
440 Thread thread;
441 thread.Start();
442 // Try calling functor.
nissed9b75be2015-11-16 00:54:07 -0800443 AtomicBool called;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000444 invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
nissed9b75be2015-11-16 00:54:07 -0800445 EXPECT_TRUE_WAIT(called.get(), kWaitTimeout);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000446}
447
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000448TEST_F(AsyncInvokeTest, WithCallback) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000449 AsyncInvoker invoker;
450 // Create and start the thread.
451 Thread thread;
452 thread.Start();
453 // Try calling functor.
454 SetExpectedThreadForIntCallback(Thread::Current());
455 invoker.AsyncInvoke(&thread, FunctorA(),
456 &AsyncInvokeTest::IntCallback,
457 static_cast<AsyncInvokeTest*>(this));
458 EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
459}
460
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000461TEST_F(AsyncInvokeTest, CancelInvoker) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000462 // Create and start the thread.
463 Thread thread;
464 thread.Start();
465 // Try destroying invoker during call.
466 {
467 AsyncInvoker invoker;
468 invoker.AsyncInvoke(&thread, FunctorC(),
469 &AsyncInvokeTest::IntCallback,
470 static_cast<AsyncInvokeTest*>(this));
471 }
472 // With invoker gone, callback should be cancelled.
473 Thread::Current()->ProcessMessages(kWaitTimeout);
474 EXPECT_EQ(0, int_value_);
475}
476
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000477TEST_F(AsyncInvokeTest, CancelCallingThread) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000478 AsyncInvoker invoker;
479 { // Create and start the thread.
480 Thread thread;
481 thread.Start();
482 // Try calling functor.
483 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
484 static_cast<AsyncInvokeTest*>(this),
485 &invoker, Thread::Current()));
486 // Wait for the call to begin.
487 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
488 }
489 // Calling thread is gone. Return message shouldn't happen.
490 Thread::Current()->ProcessMessages(kWaitTimeout);
491 EXPECT_EQ(0, int_value_);
492}
493
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000494TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000495 Thread thread;
496 thread.Start();
497 {
498 AsyncInvoker invoker;
499 // Try calling functor.
500 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
501 static_cast<AsyncInvokeTest*>(this),
502 &invoker, Thread::Current()));
503 // Wait for the call to begin.
504 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
505 }
506 // Invoker is destroyed. Function should not execute.
507 Thread::Current()->ProcessMessages(kWaitTimeout);
508 EXPECT_EQ(0, int_value_);
509}
510
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000511TEST_F(AsyncInvokeTest, Flush) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000512 AsyncInvoker invoker;
nissed9b75be2015-11-16 00:54:07 -0800513 AtomicBool flag1;
514 AtomicBool flag2;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000515 // Queue two async calls to the current thread.
516 invoker.AsyncInvoke<void>(Thread::Current(),
517 FunctorB(&flag1));
518 invoker.AsyncInvoke<void>(Thread::Current(),
519 FunctorB(&flag2));
520 // Because we haven't pumped messages, these should not have run yet.
nissed9b75be2015-11-16 00:54:07 -0800521 EXPECT_FALSE(flag1.get());
522 EXPECT_FALSE(flag2.get());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000523 // Force them to run now.
524 invoker.Flush(Thread::Current());
nissed9b75be2015-11-16 00:54:07 -0800525 EXPECT_TRUE(flag1.get());
526 EXPECT_TRUE(flag2.get());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000527}
528
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000529TEST_F(AsyncInvokeTest, FlushWithIds) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000530 AsyncInvoker invoker;
nissed9b75be2015-11-16 00:54:07 -0800531 AtomicBool flag1;
532 AtomicBool flag2;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000533 // Queue two async calls to the current thread, one with a message id.
534 invoker.AsyncInvoke<void>(Thread::Current(),
535 FunctorB(&flag1),
536 5);
537 invoker.AsyncInvoke<void>(Thread::Current(),
538 FunctorB(&flag2));
539 // Because we haven't pumped messages, these should not have run yet.
nissed9b75be2015-11-16 00:54:07 -0800540 EXPECT_FALSE(flag1.get());
541 EXPECT_FALSE(flag2.get());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000542 // Execute pending calls with id == 5.
543 invoker.Flush(Thread::Current(), 5);
nissed9b75be2015-11-16 00:54:07 -0800544 EXPECT_TRUE(flag1.get());
545 EXPECT_FALSE(flag2.get());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000546 flag1 = false;
547 // Execute all pending calls. The id == 5 call should not execute again.
548 invoker.Flush(Thread::Current());
nissed9b75be2015-11-16 00:54:07 -0800549 EXPECT_FALSE(flag1.get());
550 EXPECT_TRUE(flag2.get());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000551}
552
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200553class GuardedAsyncInvokeTest : public testing::Test {
554 public:
555 void IntCallback(int value) {
556 EXPECT_EQ(expected_thread_, Thread::Current());
557 int_value_ = value;
558 }
559 void AsyncInvokeIntCallback(GuardedAsyncInvoker* invoker, Thread* thread) {
560 expected_thread_ = thread;
561 invoker->AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback,
562 static_cast<GuardedAsyncInvokeTest*>(this));
563 invoke_started_.Set();
564 }
565 void SetExpectedThreadForIntCallback(Thread* thread) {
566 expected_thread_ = thread;
567 }
568
569 protected:
570 const static int kWaitTimeout = 1000;
571 GuardedAsyncInvokeTest()
572 : int_value_(0),
573 invoke_started_(true, false),
574 expected_thread_(nullptr) {}
575
576 int int_value_;
577 Event invoke_started_;
578 Thread* expected_thread_;
579};
580
581// Functor for creating an invoker.
582struct CreateInvoker {
583 CreateInvoker(scoped_ptr<GuardedAsyncInvoker>* invoker) : invoker_(invoker) {}
584 void operator()() { invoker_->reset(new GuardedAsyncInvoker()); }
585 scoped_ptr<GuardedAsyncInvoker>* invoker_;
586};
587
588// Test that we can call AsyncInvoke<void>() after the thread died.
589TEST_F(GuardedAsyncInvokeTest, KillThreadFireAndForget) {
590 // Create and start the thread.
591 scoped_ptr<Thread> thread(new Thread());
592 thread->Start();
593 scoped_ptr<GuardedAsyncInvoker> invoker;
594 // Create the invoker on |thread|.
595 thread->Invoke<void>(CreateInvoker(&invoker));
596 // Kill |thread|.
597 thread = nullptr;
598 // Try calling functor.
nissed9b75be2015-11-16 00:54:07 -0800599 AtomicBool called;
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200600 EXPECT_FALSE(invoker->AsyncInvoke<void>(FunctorB(&called)));
601 // With thread gone, nothing should happen.
nissed9b75be2015-11-16 00:54:07 -0800602 WAIT(called.get(), kWaitTimeout);
603 EXPECT_FALSE(called.get());
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200604}
605
606// Test that we can call AsyncInvoke with callback after the thread died.
607TEST_F(GuardedAsyncInvokeTest, KillThreadWithCallback) {
608 // Create and start the thread.
609 scoped_ptr<Thread> thread(new Thread());
610 thread->Start();
611 scoped_ptr<GuardedAsyncInvoker> invoker;
612 // Create the invoker on |thread|.
613 thread->Invoke<void>(CreateInvoker(&invoker));
614 // Kill |thread|.
615 thread = nullptr;
616 // Try calling functor.
617 EXPECT_FALSE(
618 invoker->AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback,
619 static_cast<GuardedAsyncInvokeTest*>(this)));
620 // With thread gone, callback should be cancelled.
621 Thread::Current()->ProcessMessages(kWaitTimeout);
622 EXPECT_EQ(0, int_value_);
623}
624
625// The remaining tests check that GuardedAsyncInvoker behaves as AsyncInvoker
626// when Thread is still alive.
627TEST_F(GuardedAsyncInvokeTest, FireAndForget) {
628 GuardedAsyncInvoker invoker;
629 // Try calling functor.
nissed9b75be2015-11-16 00:54:07 -0800630 AtomicBool called;
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200631 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&called)));
nissed9b75be2015-11-16 00:54:07 -0800632 EXPECT_TRUE_WAIT(called.get(), kWaitTimeout);
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200633}
634
635TEST_F(GuardedAsyncInvokeTest, WithCallback) {
636 GuardedAsyncInvoker invoker;
637 // Try calling functor.
638 SetExpectedThreadForIntCallback(Thread::Current());
639 EXPECT_TRUE(invoker.AsyncInvoke(FunctorA(),
640 &GuardedAsyncInvokeTest::IntCallback,
641 static_cast<GuardedAsyncInvokeTest*>(this)));
642 EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
643}
644
645TEST_F(GuardedAsyncInvokeTest, CancelInvoker) {
646 // Try destroying invoker during call.
647 {
648 GuardedAsyncInvoker invoker;
649 EXPECT_TRUE(
650 invoker.AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback,
651 static_cast<GuardedAsyncInvokeTest*>(this)));
652 }
653 // With invoker gone, callback should be cancelled.
654 Thread::Current()->ProcessMessages(kWaitTimeout);
655 EXPECT_EQ(0, int_value_);
656}
657
658TEST_F(GuardedAsyncInvokeTest, CancelCallingThread) {
659 GuardedAsyncInvoker invoker;
660 // Try destroying calling thread during call.
661 {
662 Thread thread;
663 thread.Start();
664 // Try calling functor.
665 thread.Invoke<void>(Bind(&GuardedAsyncInvokeTest::AsyncInvokeIntCallback,
666 static_cast<GuardedAsyncInvokeTest*>(this),
667 &invoker, Thread::Current()));
668 // Wait for the call to begin.
669 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
670 }
671 // Calling thread is gone. Return message shouldn't happen.
672 Thread::Current()->ProcessMessages(kWaitTimeout);
673 EXPECT_EQ(0, int_value_);
674}
675
676TEST_F(GuardedAsyncInvokeTest, KillInvokerBeforeExecute) {
677 Thread thread;
678 thread.Start();
679 {
680 GuardedAsyncInvoker invoker;
681 // Try calling functor.
682 thread.Invoke<void>(Bind(&GuardedAsyncInvokeTest::AsyncInvokeIntCallback,
683 static_cast<GuardedAsyncInvokeTest*>(this),
684 &invoker, Thread::Current()));
685 // Wait for the call to begin.
686 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
687 }
688 // Invoker is destroyed. Function should not execute.
689 Thread::Current()->ProcessMessages(kWaitTimeout);
690 EXPECT_EQ(0, int_value_);
691}
692
693TEST_F(GuardedAsyncInvokeTest, Flush) {
694 GuardedAsyncInvoker invoker;
nissed9b75be2015-11-16 00:54:07 -0800695 AtomicBool flag1;
696 AtomicBool flag2;
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200697 // Queue two async calls to the current thread.
698 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1)));
699 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2)));
700 // Because we haven't pumped messages, these should not have run yet.
nissed9b75be2015-11-16 00:54:07 -0800701 EXPECT_FALSE(flag1.get());
702 EXPECT_FALSE(flag2.get());
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200703 // Force them to run now.
704 EXPECT_TRUE(invoker.Flush());
nissed9b75be2015-11-16 00:54:07 -0800705 EXPECT_TRUE(flag1.get());
706 EXPECT_TRUE(flag2.get());
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200707}
708
709TEST_F(GuardedAsyncInvokeTest, FlushWithIds) {
710 GuardedAsyncInvoker invoker;
nissed9b75be2015-11-16 00:54:07 -0800711 AtomicBool flag1;
712 AtomicBool flag2;
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200713 // Queue two async calls to the current thread, one with a message id.
714 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1), 5));
715 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2)));
716 // Because we haven't pumped messages, these should not have run yet.
nissed9b75be2015-11-16 00:54:07 -0800717 EXPECT_FALSE(flag1.get());
718 EXPECT_FALSE(flag2.get());
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200719 // Execute pending calls with id == 5.
720 EXPECT_TRUE(invoker.Flush(5));
nissed9b75be2015-11-16 00:54:07 -0800721 EXPECT_TRUE(flag1.get());
722 EXPECT_FALSE(flag2.get());
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200723 flag1 = false;
724 // Execute all pending calls. The id == 5 call should not execute again.
725 EXPECT_TRUE(invoker.Flush());
nissed9b75be2015-11-16 00:54:07 -0800726 EXPECT_FALSE(flag1.get());
727 EXPECT_TRUE(flag2.get());
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200728}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000729
730#if defined(WEBRTC_WIN)
731class ComThreadTest : public testing::Test, public MessageHandler {
732 public:
733 ComThreadTest() : done_(false) {}
734 protected:
735 virtual void OnMessage(Message* message) {
736 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
737 // S_FALSE means the thread was already inited for a multithread apartment.
738 EXPECT_EQ(S_FALSE, hr);
739 if (SUCCEEDED(hr)) {
740 CoUninitialize();
741 }
742 done_ = true;
743 }
744 bool done_;
745};
746
747TEST_F(ComThreadTest, ComInited) {
748 Thread* thread = new ComThread();
749 EXPECT_TRUE(thread->Start());
750 thread->Post(this, 0);
751 EXPECT_TRUE_WAIT(done_, 1000);
752 delete thread;
753}
754#endif