Bug 1883861 - Part 1: Move visitMemoryBarrier into the common CodeGenerator file...
[gecko.git] / xpcom / tests / gtest / TestThreadUtils.cpp
blob96b134288597154b9a1b39ce6da4bcb5b0ab6b5d
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http:mozilla.org/MPL/2.0/. */
5 #include <type_traits>
7 #include "nsComponentManagerUtils.h"
8 #include "nsIThread.h"
9 #include "nsThreadUtils.h"
10 #include "mozilla/IdleTaskRunner.h"
11 #include "mozilla/RefCounted.h"
12 #include "mozilla/SpinEventLoopUntil.h"
13 #include "mozilla/UniquePtr.h"
15 #include "gtest/gtest.h"
17 using namespace mozilla;
19 enum {
20 TEST_CALL_VOID_ARG_VOID_RETURN,
21 TEST_CALL_VOID_ARG_VOID_RETURN_CONST,
22 TEST_CALL_VOID_ARG_NONVOID_RETURN,
23 TEST_CALL_NONVOID_ARG_VOID_RETURN,
24 TEST_CALL_NONVOID_ARG_NONVOID_RETURN,
25 TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT,
26 TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
27 #ifdef HAVE_STDCALL
28 TEST_STDCALL_VOID_ARG_VOID_RETURN,
29 TEST_STDCALL_VOID_ARG_NONVOID_RETURN,
30 TEST_STDCALL_NONVOID_ARG_VOID_RETURN,
31 TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN,
32 TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
33 #endif
34 TEST_CALL_NEWTHREAD_SUICIDAL,
35 MAX_TESTS
38 bool gRunnableExecuted[MAX_TESTS];
40 class nsFoo : public nsISupports {
41 NS_DECL_ISUPPORTS
42 nsresult DoFoo(bool* aBool) {
43 *aBool = true;
44 return NS_OK;
47 private:
48 virtual ~nsFoo() = default;
51 NS_IMPL_ISUPPORTS0(nsFoo)
53 class TestSuicide : public mozilla::Runnable {
54 public:
55 TestSuicide() : mozilla::Runnable("TestSuicide") {}
56 NS_IMETHOD Run() override {
57 // Runs first time on thread "Suicide", then dies on MainThread
58 if (!NS_IsMainThread()) {
59 mThread = do_GetCurrentThread();
60 NS_DispatchToMainThread(this);
61 return NS_OK;
63 MOZ_RELEASE_ASSERT(mThread);
64 mThread->Shutdown();
65 gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true;
66 return NS_OK;
69 private:
70 nsCOMPtr<nsIThread> mThread;
73 class nsBar : public nsISupports {
74 virtual ~nsBar() = default;
76 public:
77 NS_DECL_ISUPPORTS
78 void DoBar1(void) {
79 gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true;
81 void DoBar1Const(void) const {
82 gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN_CONST] = true;
84 nsresult DoBar2(void) {
85 gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true;
86 return NS_OK;
88 void DoBar3(nsFoo* aFoo) {
89 aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN]);
91 nsresult DoBar4(nsFoo* aFoo) {
92 return aFoo->DoFoo(
93 &gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN]);
95 void DoBar5(nsFoo* aFoo) {
96 if (aFoo)
97 gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
99 nsresult DoBar6(char* aFoo) {
100 if (strlen(aFoo))
101 gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT] = true;
102 return NS_OK;
104 #ifdef HAVE_STDCALL
105 void __stdcall DoBar1std(void) {
106 gRunnableExecuted[TEST_STDCALL_VOID_ARG_VOID_RETURN] = true;
108 nsresult __stdcall DoBar2std(void) {
109 gRunnableExecuted[TEST_STDCALL_VOID_ARG_NONVOID_RETURN] = true;
110 return NS_OK;
112 void __stdcall DoBar3std(nsFoo* aFoo) {
113 aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN]);
115 nsresult __stdcall DoBar4std(nsFoo* aFoo) {
116 return aFoo->DoFoo(
117 &gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN]);
119 void __stdcall DoBar5std(nsFoo* aFoo) {
120 if (aFoo)
121 gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
123 nsresult __stdcall DoBar6std(char* aFoo) {
124 if (strlen(aFoo))
125 gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
126 return NS_OK;
128 #endif
131 NS_IMPL_ISUPPORTS0(nsBar)
133 struct TestCopyWithNoMove {
134 explicit TestCopyWithNoMove(int* aCopyCounter) : mCopyCounter(aCopyCounter) {}
135 TestCopyWithNoMove(const TestCopyWithNoMove& a)
136 : mCopyCounter(a.mCopyCounter) {
137 *mCopyCounter += 1;
139 // No 'move' declaration, allows passing object by rvalue copy.
140 // Destructor nulls member variable...
141 ~TestCopyWithNoMove() { mCopyCounter = nullptr; }
142 // ... so we can check that the object is called when still alive.
143 void operator()() { MOZ_RELEASE_ASSERT(mCopyCounter); }
144 int* mCopyCounter;
146 struct TestCopyWithDeletedMove {
147 explicit TestCopyWithDeletedMove(int* aCopyCounter)
148 : mCopyCounter(aCopyCounter) {}
149 TestCopyWithDeletedMove(const TestCopyWithDeletedMove& a)
150 : mCopyCounter(a.mCopyCounter) {
151 *mCopyCounter += 1;
153 // Deleted move prevents passing by rvalue (even if copy would work)
154 TestCopyWithDeletedMove(TestCopyWithDeletedMove&&) = delete;
155 ~TestCopyWithDeletedMove() { mCopyCounter = nullptr; }
156 void operator()() { MOZ_RELEASE_ASSERT(mCopyCounter); }
157 int* mCopyCounter;
159 struct TestMove {
160 explicit TestMove(int* aMoveCounter) : mMoveCounter(aMoveCounter) {}
161 TestMove(const TestMove&) = delete;
162 TestMove(TestMove&& a) : mMoveCounter(a.mMoveCounter) {
163 a.mMoveCounter = nullptr;
164 *mMoveCounter += 1;
166 ~TestMove() { mMoveCounter = nullptr; }
167 void operator()() { MOZ_RELEASE_ASSERT(mMoveCounter); }
168 int* mMoveCounter;
170 struct TestCopyMove {
171 TestCopyMove(int* aCopyCounter, int* aMoveCounter)
172 : mCopyCounter(aCopyCounter), mMoveCounter(aMoveCounter) {}
173 TestCopyMove(const TestCopyMove& a)
174 : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) {
175 *mCopyCounter += 1;
177 TestCopyMove(TestCopyMove&& a)
178 : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) {
179 a.mMoveCounter = nullptr;
180 *mMoveCounter += 1;
182 ~TestCopyMove() {
183 mCopyCounter = nullptr;
184 mMoveCounter = nullptr;
186 void operator()() {
187 MOZ_RELEASE_ASSERT(mCopyCounter);
188 MOZ_RELEASE_ASSERT(mMoveCounter);
190 int* mCopyCounter;
191 int* mMoveCounter;
194 struct TestRefCounted : RefCounted<TestRefCounted> {
195 MOZ_DECLARE_REFCOUNTED_TYPENAME(TestRefCounted);
198 static void Expect(const char* aContext, int aCounter, int aMaxExpected) {
199 EXPECT_LE(aCounter, aMaxExpected) << aContext;
202 static void ExpectRunnableName(Runnable* aRunnable, const char* aExpectedName) {
203 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
204 nsAutoCString name;
205 EXPECT_TRUE(NS_SUCCEEDED(aRunnable->GetName(name))) << "Runnable::GetName()";
206 EXPECT_TRUE(name.EqualsASCII(aExpectedName)) << "Verify Runnable name";
207 #endif
210 struct BasicRunnableFactory {
211 static constexpr bool SupportsCopyWithDeletedMove = true;
213 template <typename Function>
214 static auto Create(const char* aName, Function&& aFunc) {
215 return NS_NewRunnableFunction(aName, std::forward<Function>(aFunc));
219 struct CancelableRunnableFactory {
220 static constexpr bool SupportsCopyWithDeletedMove = false;
222 template <typename Function>
223 static auto Create(const char* aName, Function&& aFunc) {
224 return NS_NewCancelableRunnableFunction(aName,
225 std::forward<Function>(aFunc));
229 template <typename RunnableFactory>
230 static void TestRunnableFactory(bool aNamed) {
231 // Test RunnableFactory with copyable-only function object.
233 int copyCounter = 0;
235 nsCOMPtr<nsIRunnable> trackedRunnable;
237 TestCopyWithNoMove tracker(&copyCounter);
238 trackedRunnable = aNamed ? RunnableFactory::Create("unused", tracker)
239 : RunnableFactory::Create(
240 "TestNewRunnableFunction", tracker);
241 // Original 'tracker' is destroyed here.
243 // Verify that the runnable contains a non-destroyed function object.
244 trackedRunnable->Run();
246 Expect(
247 "RunnableFactory with copyable-only (and no move) function, "
248 "copies",
249 copyCounter, 1);
252 int copyCounter = 0;
254 nsCOMPtr<nsIRunnable> trackedRunnable;
256 // Passing as rvalue, but using copy.
257 // (TestCopyWithDeletedMove wouldn't allow this.)
258 trackedRunnable =
259 aNamed ? RunnableFactory::Create("unused",
260 TestCopyWithNoMove(&copyCounter))
261 : RunnableFactory::Create("TestNewRunnableFunction",
262 TestCopyWithNoMove(&copyCounter));
264 trackedRunnable->Run();
266 Expect(
267 "RunnableFactory with copyable-only (and no move) function "
268 "rvalue, copies",
269 copyCounter, 1);
271 if constexpr (RunnableFactory::SupportsCopyWithDeletedMove) {
272 int copyCounter = 0;
274 nsCOMPtr<nsIRunnable> trackedRunnable;
276 TestCopyWithDeletedMove tracker(&copyCounter);
277 trackedRunnable = aNamed ? RunnableFactory::Create("unused", tracker)
278 : RunnableFactory::Create(
279 "TestNewRunnableFunction", tracker);
281 trackedRunnable->Run();
283 Expect(
284 "RunnableFactory with copyable-only (and deleted move) "
285 "function, copies",
286 copyCounter, 1);
289 // Test RunnableFactory with movable-only function object.
291 int moveCounter = 0;
293 nsCOMPtr<nsIRunnable> trackedRunnable;
295 TestMove tracker(&moveCounter);
296 trackedRunnable =
297 aNamed ? RunnableFactory::Create("unused", std::move(tracker))
298 : RunnableFactory::Create("TestNewRunnableFunction",
299 std::move(tracker));
301 trackedRunnable->Run();
303 Expect("RunnableFactory with movable-only function, moves", moveCounter, 1);
306 int moveCounter = 0;
308 nsCOMPtr<nsIRunnable> trackedRunnable;
310 trackedRunnable =
311 aNamed ? RunnableFactory::Create("unused", TestMove(&moveCounter))
312 : RunnableFactory::Create("TestNewRunnableFunction",
313 TestMove(&moveCounter));
315 trackedRunnable->Run();
317 Expect("RunnableFactory with movable-only function rvalue, moves",
318 moveCounter, 1);
321 // Test RunnableFactory with copyable&movable function object.
323 int copyCounter = 0;
324 int moveCounter = 0;
326 nsCOMPtr<nsIRunnable> trackedRunnable;
328 TestCopyMove tracker(&copyCounter, &moveCounter);
329 trackedRunnable =
330 aNamed ? RunnableFactory::Create("unused", std::move(tracker))
331 : RunnableFactory::Create("TestNewRunnableFunction",
332 std::move(tracker));
334 trackedRunnable->Run();
336 Expect("RunnableFactory with copyable&movable function, copies",
337 copyCounter, 0);
338 Expect("RunnableFactory with copyable&movable function, moves", moveCounter,
342 int copyCounter = 0;
343 int moveCounter = 0;
345 nsCOMPtr<nsIRunnable> trackedRunnable;
347 trackedRunnable =
348 aNamed ? RunnableFactory::Create(
349 "unused", TestCopyMove(&copyCounter, &moveCounter))
350 : RunnableFactory::Create(
351 "TestNewRunnableFunction",
352 TestCopyMove(&copyCounter, &moveCounter));
354 trackedRunnable->Run();
356 Expect("RunnableFactory with copyable&movable function rvalue, copies",
357 copyCounter, 0);
358 Expect("RunnableFactory with copyable&movable function rvalue, moves",
359 moveCounter, 1);
362 // Test RunnableFactory with copyable-only lambda capture.
364 int copyCounter = 0;
366 nsCOMPtr<nsIRunnable> trackedRunnable;
368 TestCopyWithNoMove tracker(&copyCounter);
369 // Expect 2 copies (here -> local lambda -> runnable lambda).
370 trackedRunnable =
371 aNamed
372 ? RunnableFactory::Create("unused",
373 [tracker]() mutable { tracker(); })
374 : RunnableFactory::Create("TestNewRunnableFunction",
375 [tracker]() mutable { tracker(); });
377 trackedRunnable->Run();
379 Expect(
380 "RunnableFactory with copyable-only (and no move) capture, "
381 "copies",
382 copyCounter, 2);
385 int copyCounter = 0;
387 nsCOMPtr<nsIRunnable> trackedRunnable;
389 TestCopyWithDeletedMove tracker(&copyCounter);
390 // Expect 2 copies (here -> local lambda -> runnable lambda).
391 trackedRunnable =
392 aNamed
393 ? RunnableFactory::Create("unused",
394 [tracker]() mutable { tracker(); })
395 : RunnableFactory::Create("TestNewRunnableFunction",
396 [tracker]() mutable { tracker(); });
398 trackedRunnable->Run();
400 Expect(
401 "RunnableFactory with copyable-only (and deleted move) capture, "
402 "copies",
403 copyCounter, 2);
406 // Note: Not possible to use move-only captures.
407 // (Until we can use C++14 generalized lambda captures)
409 // Test RunnableFactory with copyable&movable lambda capture.
411 int copyCounter = 0;
412 int moveCounter = 0;
414 nsCOMPtr<nsIRunnable> trackedRunnable;
416 TestCopyMove tracker(&copyCounter, &moveCounter);
417 trackedRunnable =
418 aNamed
419 ? RunnableFactory::Create("unused",
420 [tracker]() mutable { tracker(); })
421 : RunnableFactory::Create("TestNewRunnableFunction",
422 [tracker]() mutable { tracker(); });
423 // Expect 1 copy (here -> local lambda) and 1 move (local -> runnable
424 // lambda).
426 trackedRunnable->Run();
428 Expect("RunnableFactory with copyable&movable capture, copies", copyCounter,
430 Expect("RunnableFactory with copyable&movable capture, moves", moveCounter,
435 TEST(ThreadUtils, NewRunnableFunction)
436 { TestRunnableFactory<BasicRunnableFactory>(/*aNamed*/ false); }
438 TEST(ThreadUtils, NewNamedRunnableFunction)
440 // The named overload shall behave identical to the non-named counterpart.
441 TestRunnableFactory<BasicRunnableFactory>(/*aNamed*/ true);
443 // Test naming.
445 const char* expectedName = "NamedRunnable";
446 RefPtr<Runnable> NamedRunnable =
447 NS_NewRunnableFunction(expectedName, [] {});
448 ExpectRunnableName(NamedRunnable, expectedName);
452 TEST(ThreadUtils, NewCancelableRunnableFunction)
453 { TestRunnableFactory<CancelableRunnableFactory>(/*aNamed*/ false); }
455 TEST(ThreadUtils, NewNamedCancelableRunnableFunction)
457 // The named overload shall behave identical to the non-named counterpart.
458 TestRunnableFactory<CancelableRunnableFactory>(/*aNamed*/ true);
460 // Test naming.
462 const char* expectedName = "NamedRunnable";
463 RefPtr<Runnable> NamedRunnable =
464 NS_NewCancelableRunnableFunction(expectedName, [] {});
465 ExpectRunnableName(NamedRunnable, expectedName);
468 // Test release on cancelation.
470 auto foo = MakeRefPtr<TestRefCounted>();
471 bool ran = false;
473 RefPtr<CancelableRunnable> func =
474 NS_NewCancelableRunnableFunction("unused", [foo, &ran] { ran = true; });
476 EXPECT_EQ(foo->refCount(), 2u);
477 func->Cancel();
479 EXPECT_EQ(foo->refCount(), 1u);
480 EXPECT_FALSE(ran);
483 // Test no-op after cancelation.
485 auto foo = MakeRefPtr<TestRefCounted>();
486 bool ran = false;
488 RefPtr<CancelableRunnable> func =
489 NS_NewCancelableRunnableFunction("unused", [foo, &ran] { ran = true; });
491 EXPECT_EQ(foo->refCount(), 2u);
492 func->Cancel();
493 func->Run();
495 EXPECT_FALSE(ran);
499 static void TestNewRunnableMethod(bool aNamed) {
500 memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool));
501 // Scope the smart ptrs so that the runnables need to hold on to whatever they
502 // need
504 RefPtr<nsFoo> foo = new nsFoo();
505 RefPtr<nsBar> bar = new nsBar();
506 RefPtr<const nsBar> constBar = bar;
508 // This pointer will be freed at the end of the block
509 // Do not dereference this pointer in the runnable method!
510 RefPtr<nsFoo> rawFoo = new nsFoo();
512 // Read only string. Dereferencing in runnable method to check this works.
513 char* message = (char*)"Test message";
516 auto bar = MakeRefPtr<nsBar>();
518 NS_DispatchToMainThread(
519 aNamed ? NewRunnableMethod("unused", std::move(bar), &nsBar::DoBar1)
520 : NewRunnableMethod("nsBar::DoBar1", std::move(bar),
521 &nsBar::DoBar1));
524 NS_DispatchToMainThread(
525 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1)
526 : NewRunnableMethod("nsBar::DoBar1", bar, &nsBar::DoBar1));
527 NS_DispatchToMainThread(
528 aNamed ? NewRunnableMethod("unused", constBar, &nsBar::DoBar1Const)
529 : NewRunnableMethod("nsBar::DoBar1Const", constBar,
530 &nsBar::DoBar1Const));
531 NS_DispatchToMainThread(
532 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2)
533 : NewRunnableMethod("nsBar::DoBar2", bar, &nsBar::DoBar2));
534 NS_DispatchToMainThread(
535 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar3,
536 foo)
537 : NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar3", bar,
538 &nsBar::DoBar3, foo));
539 NS_DispatchToMainThread(
540 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar4,
541 foo)
542 : NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar4", bar,
543 &nsBar::DoBar4, foo));
544 NS_DispatchToMainThread(
545 aNamed
546 ? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5, rawFoo)
547 : NewRunnableMethod<nsFoo*>("nsBar::DoBar5", bar, &nsBar::DoBar5,
548 rawFoo));
549 NS_DispatchToMainThread(
550 aNamed
551 ? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6, message)
552 : NewRunnableMethod<char*>("nsBar::DoBar6", bar, &nsBar::DoBar6,
553 message));
554 #ifdef HAVE_STDCALL
555 NS_DispatchToMainThread(
556 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1std)
557 : NewRunnableMethod(bar, &nsBar::DoBar1std));
558 NS_DispatchToMainThread(
559 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2std)
560 : NewRunnableMethod(bar, &nsBar::DoBar2std));
561 NS_DispatchToMainThread(
562 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
563 &nsBar::DoBar3std, foo)
564 : NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar3std, foo));
565 NS_DispatchToMainThread(
566 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
567 &nsBar::DoBar4std, foo)
568 : NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar4std, foo));
569 NS_DispatchToMainThread(
570 aNamed ? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5std,
571 rawFoo)
572 : NewRunnableMethod<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo));
573 NS_DispatchToMainThread(
574 aNamed ? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6std,
575 message)
576 : NewRunnableMethod<char*>(bar, &nsBar::DoBar6std, message));
577 #endif
580 // Spin the event loop
581 NS_ProcessPendingEvents(nullptr);
583 // Now test a suicidal event in NS_New(Named)Thread
584 nsCOMPtr<nsIThread> thread;
585 NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide());
586 ASSERT_TRUE(thread);
588 while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) {
589 NS_ProcessPendingEvents(nullptr);
592 for (uint32_t i = 0; i < MAX_TESTS; i++) {
593 EXPECT_TRUE(gRunnableExecuted[i]) << "Error in test " << i;
597 TEST(ThreadUtils, RunnableMethod)
598 { TestNewRunnableMethod(/* aNamed */ false); }
600 TEST(ThreadUtils, NamedRunnableMethod)
602 // The named overloads shall behave identical to the non-named counterparts.
603 TestNewRunnableMethod(/* aNamed */ true);
605 // Test naming.
607 RefPtr<nsFoo> foo = new nsFoo();
608 const char* expectedName = "NamedRunnable";
609 bool unused;
610 RefPtr<Runnable> NamedRunnable =
611 NewRunnableMethod<bool*>(expectedName, foo, &nsFoo::DoFoo, &unused);
612 ExpectRunnableName(NamedRunnable, expectedName);
616 class IdleObjectWithoutSetDeadline final {
617 public:
618 NS_INLINE_DECL_REFCOUNTING(IdleObjectWithoutSetDeadline)
619 IdleObjectWithoutSetDeadline() : mRunnableExecuted(false) {}
620 void Method() { mRunnableExecuted = true; }
621 bool mRunnableExecuted;
623 private:
624 ~IdleObjectWithoutSetDeadline() = default;
627 class IdleObjectParentWithSetDeadline {
628 public:
629 IdleObjectParentWithSetDeadline() : mSetDeadlineCalled(false) {}
630 void SetDeadline(TimeStamp aDeadline) { mSetDeadlineCalled = true; }
631 bool mSetDeadlineCalled;
634 class IdleObjectInheritedSetDeadline final
635 : public IdleObjectParentWithSetDeadline {
636 public:
637 NS_INLINE_DECL_REFCOUNTING(IdleObjectInheritedSetDeadline)
638 IdleObjectInheritedSetDeadline() : mRunnableExecuted(false) {}
639 void Method() { mRunnableExecuted = true; }
640 bool mRunnableExecuted;
642 private:
643 ~IdleObjectInheritedSetDeadline() = default;
646 class IdleObject final {
647 public:
648 NS_INLINE_DECL_REFCOUNTING(IdleObject)
649 IdleObject() {
650 for (uint32_t index = 0; index < ArrayLength(mRunnableExecuted); ++index) {
651 mRunnableExecuted[index] = false;
652 mSetIdleDeadlineCalled = false;
655 void SetDeadline(TimeStamp aTimeStamp) { mSetIdleDeadlineCalled = true; }
657 void CheckExecutedMethods(const char* aKey, uint32_t aNumExecuted) {
658 uint32_t index;
659 for (index = 0; index < aNumExecuted; ++index) {
660 ASSERT_TRUE(mRunnableExecuted[index])
661 << aKey << ": Method" << index << " should've executed";
664 for (; index < ArrayLength(mRunnableExecuted); ++index) {
665 ASSERT_FALSE(mRunnableExecuted[index])
666 << aKey << ": Method" << index << " shouldn't have executed";
670 void Method0() {
671 CheckExecutedMethods("Method0", 0);
672 mRunnableExecuted[0] = true;
673 mSetIdleDeadlineCalled = false;
676 void Method1() {
677 CheckExecutedMethods("Method1", 1);
678 ASSERT_TRUE(mSetIdleDeadlineCalled);
679 mRunnableExecuted[1] = true;
680 mSetIdleDeadlineCalled = false;
683 void Method2() {
684 CheckExecutedMethods("Method2", 2);
685 ASSERT_TRUE(mSetIdleDeadlineCalled);
686 mRunnableExecuted[2] = true;
687 mSetIdleDeadlineCalled = false;
688 NS_DispatchToCurrentThread(
689 NewRunnableMethod("IdleObject::Method3", this, &IdleObject::Method3));
692 void Method3() {
693 CheckExecutedMethods("Method3", 3);
695 NS_NewTimerWithFuncCallback(getter_AddRefs(mTimer), Method4, this, 10,
696 nsITimer::TYPE_ONE_SHOT, "IdleObject::Method3");
697 NS_DispatchToCurrentThreadQueue(
698 NewIdleRunnableMethodWithTimer("IdleObject::Method5", this,
699 &IdleObject::Method5),
700 50, EventQueuePriority::Idle);
701 NS_DispatchToCurrentThreadQueue(
702 NewRunnableMethod("IdleObject::Method6", this, &IdleObject::Method6),
703 100, EventQueuePriority::Idle);
705 PR_Sleep(PR_MillisecondsToInterval(200));
706 mRunnableExecuted[3] = true;
707 mSetIdleDeadlineCalled = false;
710 static void Method4(nsITimer* aTimer, void* aClosure) {
711 RefPtr<IdleObject> self = static_cast<IdleObject*>(aClosure);
712 self->CheckExecutedMethods("Method4", 4);
713 self->mRunnableExecuted[4] = true;
714 self->mSetIdleDeadlineCalled = false;
717 void Method5() {
718 CheckExecutedMethods("Method5", 5);
719 ASSERT_TRUE(mSetIdleDeadlineCalled);
720 mRunnableExecuted[5] = true;
721 mSetIdleDeadlineCalled = false;
724 void Method6() {
725 CheckExecutedMethods("Method6", 6);
726 mRunnableExecuted[6] = true;
727 mSetIdleDeadlineCalled = false;
730 void Method7() {
731 CheckExecutedMethods("Method7", 7);
732 ASSERT_TRUE(mSetIdleDeadlineCalled);
733 mRunnableExecuted[7] = true;
734 mSetIdleDeadlineCalled = false;
737 private:
738 nsCOMPtr<nsITimer> mTimer;
739 bool mRunnableExecuted[8];
740 bool mSetIdleDeadlineCalled;
741 ~IdleObject() = default;
744 // Disable test due to frequent failures
745 #if 0
746 // because test fails on multiple platforms
747 TEST(ThreadUtils, IdleRunnableMethod)
750 RefPtr<IdleObject> idle = new IdleObject();
751 RefPtr<IdleObjectWithoutSetDeadline> idleNoSetDeadline =
752 new IdleObjectWithoutSetDeadline();
753 RefPtr<IdleObjectInheritedSetDeadline> idleInheritedSetDeadline =
754 new IdleObjectInheritedSetDeadline();
756 NS_DispatchToCurrentThread(
757 NewRunnableMethod("IdleObject::Method0", idle, &IdleObject::Method0));
758 NS_DispatchToCurrentThreadQueue(
759 NewIdleRunnableMethod("IdleObject::Method1", idle,
760 &IdleObject::Method1),
761 EventQueuePriority::Idle);
762 NS_DispatchToCurrentThreadQueue(
763 NewIdleRunnableMethodWithTimer("IdleObject::Method2", idle,
764 &IdleObject::Method2),
765 60000, EventQueuePriority::Idle);
766 NS_DispatchToCurrentThreadQueue(
767 NewIdleRunnableMethod("IdleObject::Method7", idle,
768 &IdleObject::Method7),
769 EventQueuePriority::Idle);
770 NS_DispatchToCurrentThreadQueue(
771 NewIdleRunnableMethod<const char*, uint32_t>(
772 "IdleObject::CheckExecutedMethods", idle,
773 &IdleObject::CheckExecutedMethods, "final", 8),
774 EventQueuePriority::Idle);
775 NS_DispatchToCurrentThreadQueue(
776 NewIdleRunnableMethod("IdleObjectWithoutSetDeadline::Method",
777 idleNoSetDeadline,
778 &IdleObjectWithoutSetDeadline::Method),
779 EventQueuePriority::Idle);
780 NS_DispatchToCurrentThreadQueue(
781 NewIdleRunnableMethod("IdleObjectInheritedSetDeadline::Method",
782 idleInheritedSetDeadline,
783 &IdleObjectInheritedSetDeadline::Method),
784 EventQueuePriority::Idle);
786 NS_ProcessPendingEvents(nullptr);
788 ASSERT_TRUE(idleNoSetDeadline->mRunnableExecuted);
789 ASSERT_TRUE(idleInheritedSetDeadline->mRunnableExecuted);
790 ASSERT_TRUE(idleInheritedSetDeadline->mSetDeadlineCalled);
793 #endif
795 TEST(ThreadUtils, IdleTaskRunner)
797 using namespace mozilla;
799 // Repeating.
800 int cnt1 = 0;
801 RefPtr<IdleTaskRunner> runner1 = IdleTaskRunner::Create(
802 [&cnt1](TimeStamp) {
803 cnt1++;
804 return true;
806 "runner1", 0, TimeDuration::FromMilliseconds(10),
807 TimeDuration::FromMilliseconds(3), true, nullptr);
809 // Non-repeating but callback always return false so it's still repeating.
810 int cnt2 = 0;
811 RefPtr<IdleTaskRunner> runner2 = IdleTaskRunner::Create(
812 [&cnt2](TimeStamp) {
813 cnt2++;
814 return false;
816 "runner2", 0, TimeDuration::FromMilliseconds(10),
817 TimeDuration::FromMilliseconds(3), false, nullptr);
819 // Repeating until cnt3 >= 2 by returning 'true' in MayStopProcessing
820 // callback. The strategy is to stop repeating as early as possible so that we
821 // are more probable to catch the bug if it didn't stop as expected.
822 int cnt3 = 0;
823 RefPtr<IdleTaskRunner> runner3 = IdleTaskRunner::Create(
824 [&cnt3](TimeStamp) {
825 cnt3++;
826 return true;
828 "runner3", 0, TimeDuration::FromMilliseconds(10),
829 TimeDuration::FromMilliseconds(3), true, [&cnt3] { return cnt3 >= 2; });
831 // Non-repeating can callback return true so the callback will
832 // be only run once.
833 int cnt4 = 0;
834 RefPtr<IdleTaskRunner> runner4 = IdleTaskRunner::Create(
835 [&cnt4](TimeStamp) {
836 cnt4++;
837 return true;
839 "runner4", 0, TimeDuration::FromMilliseconds(10),
840 TimeDuration::FromMilliseconds(3), false, nullptr);
842 // Firstly we wait until the two repeating tasks reach their limits.
843 MOZ_ALWAYS_TRUE(
844 SpinEventLoopUntil("xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt1"_ns,
845 [&]() { return cnt1 >= 100; }));
846 MOZ_ALWAYS_TRUE(
847 SpinEventLoopUntil("xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt2"_ns,
848 [&]() { return cnt2 >= 100; }));
850 // At any point ==> 0 <= cnt3 <= 2 since MayStopProcessing() would return
851 // true when cnt3 >= 2.
852 MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
853 "xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt3"_ns, [&]() {
854 if (cnt3 > 2) {
855 EXPECT_TRUE(false) << "MaybeContinueProcess() doesn't work.";
856 return true; // Stop on failure.
858 return cnt3 == 2; // Stop finish if we have reached its max value.
859 }));
861 // At any point ==> 0 <= cnt4 <= 1 since this is a non-repeating
862 // idle runner.
863 MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
864 "xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt4"_ns, [&]() {
865 // At any point: 0 <= cnt4 <= 1
866 if (cnt4 > 1) {
867 EXPECT_TRUE(false) << "The 'mRepeating' flag doesn't work.";
868 return true; // Stop on failure.
870 return cnt4 == 1;
871 }));
873 // The repeating timers require an explicit Cancel() call.
874 runner1->Cancel();
875 runner2->Cancel();
878 // {9e70a320-be02-11d1-8031-006008159b5a}
879 #define NS_IFOO_IID \
881 0x9e70a320, 0xbe02, 0x11d1, { \
882 0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a \
886 TEST(ThreadUtils, TypeTraits)
888 static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>>,
889 "RemoveSmartPointer<int> should be int");
890 static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>>,
891 "RemoveSmartPointer<int*> should be int*");
892 static_assert(std::is_same_v<UniquePtr<int>,
893 mozilla::RemoveSmartPointer<UniquePtr<int>>>,
894 "RemoveSmartPointer<UniquePtr<int>> should be UniquePtr<int>");
895 static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>>,
896 "RemoveSmartPointer<RefPtr<int>> should be int");
897 static_assert(
898 std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>>,
899 "RemoveSmartPointer<const RefPtr<int>> should be int");
900 static_assert(
901 std::is_same_v<int, mozilla::RemoveSmartPointer<volatile RefPtr<int>>>,
902 "RemoveSmartPointer<volatile RefPtr<int>> should be int");
903 static_assert(
904 std::is_same_v<int,
905 mozilla::RemoveSmartPointer<const volatile RefPtr<int>>>,
906 "RemoveSmartPointer<const volatile RefPtr<int>> should be int");
907 static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>>,
908 "RemoveSmartPointer<nsCOMPtr<int>> should be int");
909 static_assert(
910 std::is_same_v<int, mozilla::RemoveSmartPointer<const nsCOMPtr<int>>>,
911 "RemoveSmartPointer<const nsCOMPtr<int>> should be int");
912 static_assert(
913 std::is_same_v<int, mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>>,
914 "RemoveSmartPointer<volatile nsCOMPtr<int>> should be int");
915 static_assert(
916 std::is_same_v<int,
917 mozilla::RemoveSmartPointer<const volatile nsCOMPtr<int>>>,
918 "RemoveSmartPointer<const volatile nsCOMPtr<int>> should be int");
920 static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>>,
921 "RemoveRawOrSmartPointer<int> should be int");
922 static_assert(
923 std::is_same_v<UniquePtr<int>,
924 mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>>,
925 "RemoveRawOrSmartPointer<UniquePtr<int>> should be UniquePtr<int>");
926 static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>>,
927 "RemoveRawOrSmartPointer<int*> should be int");
928 static_assert(
929 std::is_same_v<const int, mozilla::RemoveRawOrSmartPointer<const int*>>,
930 "RemoveRawOrSmartPointer<const int*> should be const int");
931 static_assert(
932 std::is_same_v<volatile int,
933 mozilla::RemoveRawOrSmartPointer<volatile int*>>,
934 "RemoveRawOrSmartPointer<volatile int*> should be volatile int");
935 static_assert(
936 std::is_same_v<const volatile int,
937 mozilla::RemoveRawOrSmartPointer<const volatile int*>>,
938 "RemoveRawOrSmartPointer<const volatile int*> should be const "
939 "volatile int");
940 static_assert(
941 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>>,
942 "RemoveRawOrSmartPointer<RefPtr<int>> should be int");
943 static_assert(
944 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>>,
945 "RemoveRawOrSmartPointer<const RefPtr<int>> should be int");
946 static_assert(
947 std::is_same_v<int,
948 mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>>,
949 "RemoveRawOrSmartPointer<volatile RefPtr<int>> should be int");
950 static_assert(
951 std::is_same_v<
952 int, mozilla::RemoveRawOrSmartPointer<const volatile RefPtr<int>>>,
953 "RemoveRawOrSmartPointer<const volatile RefPtr<int>> should be "
954 "int");
955 static_assert(
956 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>>,
957 "RemoveRawOrSmartPointer<nsCOMPtr<int>> should be int");
958 static_assert(
959 std::is_same_v<int,
960 mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>>,
961 "RemoveRawOrSmartPointer<const nsCOMPtr<int>> should be int");
962 static_assert(
963 std::is_same_v<int,
964 mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>>,
965 "RemoveRawOrSmartPointer<volatile nsCOMPtr<int>> should be int");
966 static_assert(
967 std::is_same_v<
968 int, mozilla::RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>>>,
969 "RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>> should be "
970 "int");
973 namespace TestThreadUtils {
975 static bool gDebug = false;
976 static int gAlive, gZombies;
977 static int gAllConstructions, gConstructions, gCopyConstructions,
978 gMoveConstructions, gDestructions, gAssignments, gMoves;
979 struct Spy {
980 static void ClearActions() {
981 gAllConstructions = gConstructions = gCopyConstructions =
982 gMoveConstructions = gDestructions = gAssignments = gMoves = 0;
984 static void ClearAll() {
985 ClearActions();
986 gAlive = 0;
989 explicit Spy(int aID) : mID(aID) {
990 ++gAlive;
991 ++gAllConstructions;
992 ++gConstructions;
993 if (gDebug) {
994 printf("Spy[%d@%p]()\n", mID, this);
997 Spy(const Spy& o) : mID(o.mID) {
998 ++gAlive;
999 ++gAllConstructions;
1000 ++gCopyConstructions;
1001 if (gDebug) {
1002 printf("Spy[%d@%p](&[%d@%p])\n", mID, this, o.mID, &o);
1005 Spy(Spy&& o) : mID(o.mID) {
1006 o.mID = -o.mID;
1007 ++gZombies;
1008 ++gAllConstructions;
1009 ++gMoveConstructions;
1010 if (gDebug) {
1011 printf("Spy[%d@%p](&&[%d->%d@%p])\n", mID, this, -o.mID, o.mID, &o);
1014 ~Spy() {
1015 if (mID >= 0) {
1016 --gAlive;
1017 } else {
1018 --gZombies;
1020 ++gDestructions;
1021 if (gDebug) {
1022 printf("~Spy[%d@%p]()\n", mID, this);
1024 mID = 0;
1026 Spy& operator=(const Spy& o) {
1027 ++gAssignments;
1028 if (gDebug) {
1029 printf("Spy[%d->%d@%p] = &[%d@%p]\n", mID, o.mID, this, o.mID, &o);
1031 mID = o.mID;
1032 return *this;
1034 Spy& operator=(Spy&& o) {
1035 --gAlive;
1036 ++gZombies;
1037 ++gMoves;
1038 if (gDebug) {
1039 printf("Spy[%d->%d@%p] = &&[%d->%d@%p]\n", mID, o.mID, this, o.mID,
1040 -o.mID, &o);
1042 mID = o.mID;
1043 o.mID = -o.mID;
1044 return *this;
1047 int mID; // ID given at construction, or negation if was moved from; 0 when
1048 // destroyed.
1051 struct ISpyWithISupports : public nsISupports {
1052 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
1053 NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
1054 NS_IMETHOD_(int32_t) ID() = 0;
1056 NS_DEFINE_STATIC_IID_ACCESSOR(ISpyWithISupports, NS_IFOO_IID)
1057 struct SpyWithISupports : public ISpyWithISupports, public Spy {
1058 private:
1059 virtual ~SpyWithISupports() = default;
1061 public:
1062 explicit SpyWithISupports(int aID) : Spy(aID){};
1063 NS_DECL_ISUPPORTS
1064 NS_IMETHOD_(nsrefcnt) RefCnt() override { return mRefCnt; }
1065 NS_IMETHOD_(int32_t) ID() override { return mID; }
1067 NS_IMPL_ISUPPORTS(SpyWithISupports, ISpyWithISupports)
1069 class IThreadUtilsObject : public nsISupports {
1070 public:
1071 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
1073 NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
1074 NS_IMETHOD_(int32_t) ID() = 0;
1077 NS_DEFINE_STATIC_IID_ACCESSOR(IThreadUtilsObject, NS_IFOO_IID)
1079 struct ThreadUtilsObjectNonRefCountedBase {
1080 virtual void MethodFromNonRefCountedBase() {}
1083 struct ThreadUtilsObject : public IThreadUtilsObject,
1084 public ThreadUtilsObjectNonRefCountedBase {
1085 // nsISupports implementation
1086 NS_DECL_ISUPPORTS
1088 // IThreadUtilsObject implementation
1089 NS_IMETHOD_(nsrefcnt) RefCnt() override { return mRefCnt; }
1090 NS_IMETHOD_(int32_t) ID() override { return 0; }
1092 int mCount; // Number of calls + arguments processed.
1093 int mA0, mA1, mA2, mA3;
1094 Spy mSpy;
1095 const Spy* mSpyPtr;
1096 ThreadUtilsObject()
1097 : mCount(0), mA0(0), mA1(0), mA2(0), mA3(0), mSpy(1), mSpyPtr(nullptr) {}
1099 private:
1100 virtual ~ThreadUtilsObject() = default;
1102 public:
1103 void Test0() { mCount += 1; }
1104 void Test1i(int a0) {
1105 mCount += 2;
1106 mA0 = a0;
1108 void Test2i(int a0, int a1) {
1109 mCount += 3;
1110 mA0 = a0;
1111 mA1 = a1;
1113 void Test3i(int a0, int a1, int a2) {
1114 mCount += 4;
1115 mA0 = a0;
1116 mA1 = a1;
1117 mA2 = a2;
1119 void Test4i(int a0, int a1, int a2, int a3) {
1120 mCount += 5;
1121 mA0 = a0;
1122 mA1 = a1;
1123 mA2 = a2;
1124 mA3 = a3;
1126 void Test1pi(int* ap) {
1127 mCount += 2;
1128 mA0 = ap ? *ap : -1;
1130 void Test1pci(const int* ap) {
1131 mCount += 2;
1132 mA0 = ap ? *ap : -1;
1134 void Test1ri(int& ar) {
1135 mCount += 2;
1136 mA0 = ar;
1138 void Test1rri(int&& arr) {
1139 mCount += 2;
1140 mA0 = arr;
1142 void Test1upi(mozilla::UniquePtr<int> aup) {
1143 mCount += 2;
1144 mA0 = aup ? *aup : -1;
1146 void Test1rupi(mozilla::UniquePtr<int>& aup) {
1147 mCount += 2;
1148 mA0 = aup ? *aup : -1;
1150 void Test1rrupi(mozilla::UniquePtr<int>&& aup) {
1151 mCount += 2;
1152 mA0 = aup ? *aup : -1;
1155 void Test1s(Spy) { mCount += 2; }
1156 void Test1ps(Spy*) { mCount += 2; }
1157 void Test1rs(Spy&) { mCount += 2; }
1158 void Test1rrs(Spy&&) { mCount += 2; }
1159 void Test1ups(mozilla::UniquePtr<Spy>) { mCount += 2; }
1160 void Test1rups(mozilla::UniquePtr<Spy>&) { mCount += 2; }
1161 void Test1rrups(mozilla::UniquePtr<Spy>&&) { mCount += 2; }
1163 // Possible parameter passing styles:
1164 void TestByValue(Spy s) {
1165 if (gDebug) {
1166 printf("TestByValue(Spy[%d@%p])\n", s.mID, &s);
1168 mSpy = s;
1170 void TestByConstLRef(const Spy& s) {
1171 if (gDebug) {
1172 printf("TestByConstLRef(Spy[%d@%p]&)\n", s.mID, &s);
1174 mSpy = s;
1176 void TestByRRef(Spy&& s) {
1177 if (gDebug) {
1178 printf("TestByRRef(Spy[%d@%p]&&)\n", s.mID, &s);
1180 mSpy = std::move(s);
1182 void TestByLRef(Spy& s) {
1183 if (gDebug) {
1184 printf("TestByLRef(Spy[%d@%p]&)\n", s.mID, &s);
1186 mSpy = s;
1187 mSpyPtr = &s;
1189 void TestByPointer(Spy* p) {
1190 if (p) {
1191 if (gDebug) {
1192 printf("TestByPointer(&Spy[%d@%p])\n", p->mID, p);
1194 mSpy = *p;
1195 } else {
1196 if (gDebug) {
1197 printf("TestByPointer(nullptr)\n");
1200 mSpyPtr = p;
1202 void TestByPointerToConst(const Spy* p) {
1203 if (p) {
1204 if (gDebug) {
1205 printf("TestByPointerToConst(&Spy[%d@%p])\n", p->mID, p);
1207 mSpy = *p;
1208 } else {
1209 if (gDebug) {
1210 printf("TestByPointerToConst(nullptr)\n");
1213 mSpyPtr = p;
1217 NS_IMPL_ISUPPORTS(ThreadUtilsObject, IThreadUtilsObject)
1219 class ThreadUtilsRefCountedFinal final {
1220 public:
1221 ThreadUtilsRefCountedFinal() : m_refCount(0) {}
1222 ~ThreadUtilsRefCountedFinal() = default;
1223 // 'AddRef' and 'Release' methods with different return types, to verify
1224 // that the return type doesn't influence storage selection.
1225 long AddRef(void) { return ++m_refCount; }
1226 void Release(void) { --m_refCount; }
1228 private:
1229 long m_refCount;
1232 class ThreadUtilsRefCountedBase {
1233 public:
1234 ThreadUtilsRefCountedBase() : m_refCount(0) {}
1235 virtual ~ThreadUtilsRefCountedBase() = default;
1236 // 'AddRef' and 'Release' methods with different return types, to verify
1237 // that the return type doesn't influence storage selection.
1238 virtual void AddRef(void) { ++m_refCount; }
1239 virtual MozExternalRefCountType Release(void) { return --m_refCount; }
1241 private:
1242 MozExternalRefCountType m_refCount;
1245 class ThreadUtilsRefCountedDerived : public ThreadUtilsRefCountedBase {};
1247 class ThreadUtilsNonRefCounted {};
1249 } // namespace TestThreadUtils
1251 TEST(ThreadUtils, main)
1253 using namespace TestThreadUtils;
1255 static_assert(!IsParameterStorageClass<int>::value,
1256 "'int' should not be recognized as Storage Class");
1257 static_assert(
1258 IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value,
1259 "StoreCopyPassByConstLRef<int> should be recognized as Storage Class");
1260 static_assert(
1261 IsParameterStorageClass<StoreCopyPassByRRef<int>>::value,
1262 "StoreCopyPassByRRef<int> should be recognized as Storage Class");
1263 static_assert(
1264 IsParameterStorageClass<StoreRefPassByLRef<int>>::value,
1265 "StoreRefPassByLRef<int> should be recognized as Storage Class");
1266 static_assert(
1267 IsParameterStorageClass<StoreConstRefPassByConstLRef<int>>::value,
1268 "StoreConstRefPassByConstLRef<int> should be recognized as Storage "
1269 "Class");
1270 static_assert(
1271 IsParameterStorageClass<StoreRefPtrPassByPtr<int>>::value,
1272 "StoreRefPtrPassByPtr<int> should be recognized as Storage Class");
1273 static_assert(IsParameterStorageClass<StorePtrPassByPtr<int>>::value,
1274 "StorePtrPassByPtr<int> should be recognized as Storage Class");
1275 static_assert(
1276 IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value,
1277 "StoreConstPtrPassByConstPtr<int> should be recognized as Storage Class");
1279 RefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject);
1280 int count = 0;
1282 // Test legacy functions.
1284 nsCOMPtr<nsIRunnable> r1 =
1285 NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt,
1286 &ThreadUtilsObject::Test0);
1287 r1->Run();
1288 EXPECT_EQ(count += 1, rpt->mCount);
1290 r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1291 &ThreadUtilsObject::Test1i, 11);
1292 r1->Run();
1293 EXPECT_EQ(count += 2, rpt->mCount);
1294 EXPECT_EQ(11, rpt->mA0);
1296 // Test calling a method from a non-ref-counted base.
1298 r1 = NewRunnableMethod(
1299 "TestThreadUtils::ThreadUtilsObjectNonRefCountedBase::"
1300 "MethodFromNonRefCountedBase",
1301 rpt, &ThreadUtilsObject::MethodFromNonRefCountedBase);
1302 r1->Run();
1303 EXPECT_EQ(count, rpt->mCount);
1305 // Test variadic function with simple POD arguments.
1307 r1 = NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt,
1308 &ThreadUtilsObject::Test0);
1309 r1->Run();
1310 EXPECT_EQ(count += 1, rpt->mCount);
1312 static_assert(std::is_same_v<::detail::ParameterStorage<int>::Type,
1313 StoreCopyPassByConstLRef<int>>,
1314 "detail::ParameterStorage<int>::Type should be "
1315 "StoreCopyPassByConstLRef<int>");
1317 r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1318 &ThreadUtilsObject::Test1i, 12);
1319 r1->Run();
1320 EXPECT_EQ(count += 2, rpt->mCount);
1321 EXPECT_EQ(12, rpt->mA0);
1323 r1 = NewRunnableMethod<int, int>("TestThreadUtils::ThreadUtilsObject::Test2i",
1324 rpt, &ThreadUtilsObject::Test2i, 21, 22);
1325 r1->Run();
1326 EXPECT_EQ(count += 3, rpt->mCount);
1327 EXPECT_EQ(21, rpt->mA0);
1328 EXPECT_EQ(22, rpt->mA1);
1330 r1 = NewRunnableMethod<int, int, int>(
1331 "TestThreadUtils::ThreadUtilsObject::Test3i", rpt,
1332 &ThreadUtilsObject::Test3i, 31, 32, 33);
1333 r1->Run();
1334 EXPECT_EQ(count += 4, rpt->mCount);
1335 EXPECT_EQ(31, rpt->mA0);
1336 EXPECT_EQ(32, rpt->mA1);
1337 EXPECT_EQ(33, rpt->mA2);
1339 r1 = NewRunnableMethod<int, int, int, int>(
1340 "TestThreadUtils::ThreadUtilsObject::Test4i", rpt,
1341 &ThreadUtilsObject::Test4i, 41, 42, 43, 44);
1342 r1->Run();
1343 EXPECT_EQ(count += 5, rpt->mCount);
1344 EXPECT_EQ(41, rpt->mA0);
1345 EXPECT_EQ(42, rpt->mA1);
1346 EXPECT_EQ(43, rpt->mA2);
1347 EXPECT_EQ(44, rpt->mA3);
1349 // More interesting types of arguments.
1351 // Passing a short to make sure forwarding works with an inexact type match.
1352 short int si = 11;
1353 r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1354 &ThreadUtilsObject::Test1i, si);
1355 r1->Run();
1356 EXPECT_EQ(count += 2, rpt->mCount);
1357 EXPECT_EQ(si, rpt->mA0);
1359 // Raw pointer, possible cv-qualified.
1360 static_assert(
1361 std::is_same_v<::detail::ParameterStorage<int*>::Type,
1362 StorePtrPassByPtr<int>>,
1363 "detail::ParameterStorage<int*>::Type should be StorePtrPassByPtr<int>");
1364 static_assert(std::is_same_v<::detail::ParameterStorage<int* const>::Type,
1365 StorePtrPassByPtr<int>>,
1366 "detail::ParameterStorage<int* const>::Type should be "
1367 "StorePtrPassByPtr<int>");
1368 static_assert(std::is_same_v<::detail::ParameterStorage<int* volatile>::Type,
1369 StorePtrPassByPtr<int>>,
1370 "detail::ParameterStorage<int* volatile>::Type should be "
1371 "StorePtrPassByPtr<int>");
1372 static_assert(
1373 std::is_same_v<::detail::ParameterStorage<int* const volatile>::Type,
1374 StorePtrPassByPtr<int>>,
1375 "detail::ParameterStorage<int* const volatile>::Type should be "
1376 "StorePtrPassByPtr<int>");
1377 static_assert(
1378 std::is_same_v<::detail::ParameterStorage<int*>::Type::stored_type, int*>,
1379 "detail::ParameterStorage<int*>::Type::stored_type should be int*");
1380 static_assert(
1381 std::is_same_v<::detail::ParameterStorage<int*>::Type::passed_type, int*>,
1382 "detail::ParameterStorage<int*>::Type::passed_type should be int*");
1384 int i = 12;
1385 r1 = NewRunnableMethod<int*>("TestThreadUtils::ThreadUtilsObject::Test1pi",
1386 rpt, &ThreadUtilsObject::Test1pi, &i);
1387 r1->Run();
1388 EXPECT_EQ(count += 2, rpt->mCount);
1389 EXPECT_EQ(i, rpt->mA0);
1392 // Raw pointer to const.
1393 static_assert(std::is_same_v<::detail::ParameterStorage<const int*>::Type,
1394 StoreConstPtrPassByConstPtr<int>>,
1395 "detail::ParameterStorage<const int*>::Type should be "
1396 "StoreConstPtrPassByConstPtr<int>");
1397 static_assert(
1398 std::is_same_v<::detail::ParameterStorage<const int* const>::Type,
1399 StoreConstPtrPassByConstPtr<int>>,
1400 "detail::ParameterStorage<const int* const>::Type should be "
1401 "StoreConstPtrPassByConstPtr<int>");
1402 static_assert(
1403 std::is_same_v<::detail::ParameterStorage<const int* volatile>::Type,
1404 StoreConstPtrPassByConstPtr<int>>,
1405 "detail::ParameterStorage<const int* volatile>::Type should be "
1406 "StoreConstPtrPassByConstPtr<int>");
1407 static_assert(std::is_same_v<
1408 ::detail::ParameterStorage<const int* const volatile>::Type,
1409 StoreConstPtrPassByConstPtr<int>>,
1410 "detail::ParameterStorage<const int* const volatile>::Type "
1411 "should be StoreConstPtrPassByConstPtr<int>");
1412 static_assert(
1413 std::is_same_v<::detail::ParameterStorage<const int*>::Type::stored_type,
1414 const int*>,
1415 "detail::ParameterStorage<const int*>::Type::stored_type should be const "
1416 "int*");
1417 static_assert(
1418 std::is_same_v<::detail::ParameterStorage<const int*>::Type::passed_type,
1419 const int*>,
1420 "detail::ParameterStorage<const int*>::Type::passed_type should be const "
1421 "int*");
1423 int i = 1201;
1424 r1 = NewRunnableMethod<const int*>(
1425 "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt,
1426 &ThreadUtilsObject::Test1pci, &i);
1427 r1->Run();
1428 EXPECT_EQ(count += 2, rpt->mCount);
1429 EXPECT_EQ(i, rpt->mA0);
1432 // nsRefPtr to pointer.
1433 static_assert(
1434 std::is_same_v<::detail::ParameterStorage<
1435 StoreRefPtrPassByPtr<SpyWithISupports>>::Type,
1436 StoreRefPtrPassByPtr<SpyWithISupports>>,
1437 "ParameterStorage<StoreRefPtrPassByPtr<SpyWithISupports>>::Type should "
1438 "be StoreRefPtrPassByPtr<SpyWithISupports>");
1439 static_assert(
1440 std::is_same_v<::detail::ParameterStorage<SpyWithISupports*>::Type,
1441 StoreRefPtrPassByPtr<SpyWithISupports>>,
1442 "ParameterStorage<SpyWithISupports*>::Type should be "
1443 "StoreRefPtrPassByPtr<SpyWithISupports>");
1444 static_assert(
1445 std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::stored_type,
1446 RefPtr<SpyWithISupports>>,
1447 "StoreRefPtrPassByPtr<SpyWithISupports>::stored_type should be "
1448 "RefPtr<SpyWithISupports>");
1449 static_assert(
1450 std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::passed_type,
1451 SpyWithISupports*>,
1452 "StoreRefPtrPassByPtr<SpyWithISupports>::passed_type should be "
1453 "SpyWithISupports*");
1454 // (more nsRefPtr tests below)
1456 // nsRefPtr for ref-countable classes that do not derive from ISupports.
1457 static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>,
1458 "ThreadUtilsRefCountedFinal has AddRef() and Release()");
1459 static_assert(
1460 std::is_same_v<
1461 ::detail::ParameterStorage<ThreadUtilsRefCountedFinal*>::Type,
1462 StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>>,
1463 "ParameterStorage<ThreadUtilsRefCountedFinal*>::Type should be "
1464 "StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>");
1465 static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>,
1466 "ThreadUtilsRefCountedBase has AddRef() and Release()");
1467 static_assert(
1468 std::is_same_v<
1469 ::detail::ParameterStorage<ThreadUtilsRefCountedBase*>::Type,
1470 StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>>,
1471 "ParameterStorage<ThreadUtilsRefCountedBase*>::Type should be "
1472 "StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>");
1473 static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>,
1474 "ThreadUtilsRefCountedDerived has AddRef() and Release()");
1475 static_assert(
1476 std::is_same_v<
1477 ::detail::ParameterStorage<ThreadUtilsRefCountedDerived*>::Type,
1478 StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>>,
1479 "ParameterStorage<ThreadUtilsRefCountedDerived*>::Type should be "
1480 "StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>");
1482 static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>,
1483 "ThreadUtilsNonRefCounted doesn't have AddRef() and Release()");
1484 static_assert(!std::is_same_v<
1485 ::detail::ParameterStorage<ThreadUtilsNonRefCounted*>::Type,
1486 StoreRefPtrPassByPtr<ThreadUtilsNonRefCounted>>,
1487 "ParameterStorage<ThreadUtilsNonRefCounted*>::Type should NOT "
1488 "be StoreRefPtrPassByPtr<ThreadUtilsNonRefCounted>");
1490 // Lvalue reference.
1491 static_assert(
1492 std::is_same_v<::detail::ParameterStorage<int&>::Type,
1493 StoreRefPassByLRef<int>>,
1494 "ParameterStorage<int&>::Type should be StoreRefPassByLRef<int>");
1495 static_assert(
1496 std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type,
1497 StoreRefPassByLRef<int>::stored_type>,
1498 "ParameterStorage<int&>::Type::stored_type should be "
1499 "StoreRefPassByLRef<int>::stored_type");
1500 static_assert(
1501 std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type, int&>,
1502 "ParameterStorage<int&>::Type::stored_type should be int&");
1503 static_assert(
1504 std::is_same_v<::detail::ParameterStorage<int&>::Type::passed_type, int&>,
1505 "ParameterStorage<int&>::Type::passed_type should be int&");
1507 int i = 13;
1508 r1 = NewRunnableMethod<int&>("TestThreadUtils::ThreadUtilsObject::Test1ri",
1509 rpt, &ThreadUtilsObject::Test1ri, i);
1510 r1->Run();
1511 EXPECT_EQ(count += 2, rpt->mCount);
1512 EXPECT_EQ(i, rpt->mA0);
1515 // Rvalue reference -- Actually storing a copy and then moving it.
1516 static_assert(
1517 std::is_same_v<::detail::ParameterStorage<int&&>::Type,
1518 StoreCopyPassByRRef<int>>,
1519 "ParameterStorage<int&&>::Type should be StoreCopyPassByRRef<int>");
1520 static_assert(
1521 std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type,
1522 StoreCopyPassByRRef<int>::stored_type>,
1523 "ParameterStorage<int&&>::Type::stored_type should be "
1524 "StoreCopyPassByRRef<int>::stored_type");
1525 static_assert(
1526 std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type, int>,
1527 "ParameterStorage<int&&>::Type::stored_type should be int");
1528 static_assert(
1529 std::is_same_v<::detail::ParameterStorage<int&&>::Type::passed_type,
1530 int&&>,
1531 "ParameterStorage<int&&>::Type::passed_type should be int&&");
1533 int i = 14;
1534 r1 = NewRunnableMethod<int&&>(
1535 "TestThreadUtils::ThreadUtilsObject::Test1rri", rpt,
1536 &ThreadUtilsObject::Test1rri, std::move(i));
1538 r1->Run();
1539 EXPECT_EQ(count += 2, rpt->mCount);
1540 EXPECT_EQ(14, rpt->mA0);
1542 // Null unique pointer, by semi-implicit store&move with "T&&" syntax.
1543 static_assert(std::is_same_v<
1544 ::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type,
1545 StoreCopyPassByRRef<mozilla::UniquePtr<int>>>,
1546 "ParameterStorage<UniquePtr<int>&&>::Type should be "
1547 "StoreCopyPassByRRef<UniquePtr<int>>");
1548 static_assert(
1549 std::is_same_v<::detail::ParameterStorage<
1550 mozilla::UniquePtr<int>&&>::Type::stored_type,
1551 StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1552 "ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be "
1553 "StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1554 static_assert(
1555 std::is_same_v<::detail::ParameterStorage<
1556 mozilla::UniquePtr<int>&&>::Type::stored_type,
1557 mozilla::UniquePtr<int>>,
1558 "ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be "
1559 "UniquePtr<int>");
1560 static_assert(
1561 std::is_same_v<::detail::ParameterStorage<
1562 mozilla::UniquePtr<int>&&>::Type::passed_type,
1563 mozilla::UniquePtr<int>&&>,
1564 "ParameterStorage<UniquePtr<int>&&>::Type::passed_type should be "
1565 "UniquePtr<int>&&");
1567 mozilla::UniquePtr<int> upi;
1568 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1569 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1570 &ThreadUtilsObject::Test1upi, std::move(upi));
1572 r1->Run();
1573 EXPECT_EQ(count += 2, rpt->mCount);
1574 EXPECT_EQ(-1, rpt->mA0);
1575 rpt->mA0 = 0;
1577 // Null unique pointer, by explicit store&move with "StoreCopyPassByRRef<T>"
1578 // syntax.
1579 static_assert(
1580 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1581 mozilla::UniquePtr<int>>>::Type::stored_type,
1582 StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1583 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1584 "type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1585 static_assert(
1586 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1587 mozilla::UniquePtr<int>>>::Type::stored_type,
1588 StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1589 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1590 "type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1591 static_assert(
1592 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1593 mozilla::UniquePtr<int>>>::Type::stored_type,
1594 mozilla::UniquePtr<int>>,
1595 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1596 "type should be UniquePtr<int>");
1597 static_assert(
1598 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1599 mozilla::UniquePtr<int>>>::Type::passed_type,
1600 mozilla::UniquePtr<int>&&>,
1601 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::passed_"
1602 "type should be UniquePtr<int>&&");
1604 mozilla::UniquePtr<int> upi;
1605 r1 = NewRunnableMethod<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>(
1606 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1607 &ThreadUtilsObject::Test1upi, std::move(upi));
1609 r1->Run();
1610 EXPECT_EQ(count += 2, rpt->mCount);
1611 EXPECT_EQ(-1, rpt->mA0);
1613 // Unique pointer as xvalue.
1615 mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
1616 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1617 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1618 &ThreadUtilsObject::Test1upi, std::move(upi));
1620 r1->Run();
1621 EXPECT_EQ(count += 2, rpt->mCount);
1622 EXPECT_EQ(1, rpt->mA0);
1625 mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
1626 r1 = NewRunnableMethod<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>(
1627 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1628 &ThreadUtilsObject::Test1upi, std::move(upi));
1630 r1->Run();
1631 EXPECT_EQ(count += 2, rpt->mCount);
1632 EXPECT_EQ(1, rpt->mA0);
1634 // Unique pointer as prvalue.
1635 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1636 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1637 &ThreadUtilsObject::Test1upi, mozilla::MakeUnique<int>(2));
1638 r1->Run();
1639 EXPECT_EQ(count += 2, rpt->mCount);
1640 EXPECT_EQ(2, rpt->mA0);
1642 // Unique pointer as lvalue to lref.
1644 mozilla::UniquePtr<int> upi;
1645 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&>(
1646 "TestThreadUtils::ThreadUtilsObject::Test1rupi", rpt,
1647 &ThreadUtilsObject::Test1rupi, upi);
1648 // Passed as lref, so Run() must be called while local upi is still alive!
1649 r1->Run();
1651 EXPECT_EQ(count += 2, rpt->mCount);
1652 EXPECT_EQ(-1, rpt->mA0);
1654 // Verify copy/move assumptions.
1656 Spy::ClearAll();
1657 if (gDebug) {
1658 printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n",
1659 __LINE__);
1661 { // Block around nsCOMPtr lifetime.
1662 nsCOMPtr<nsIRunnable> r5;
1663 { // Block around Spy lifetime.
1664 if (gDebug) {
1665 printf("%d - Spy s(20)\n", __LINE__);
1667 Spy s(20);
1668 EXPECT_EQ(1, gConstructions);
1669 EXPECT_EQ(1, gAlive);
1670 if (gDebug) {
1671 printf(
1672 "%d - r5 = "
1673 "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef,"
1674 " s)\n",
1675 __LINE__);
1677 r5 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(
1678 "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
1679 &ThreadUtilsObject::TestByConstLRef, s);
1680 EXPECT_EQ(2, gAlive);
1681 EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
1682 Spy::ClearActions();
1683 if (gDebug) {
1684 printf("%d - End block with Spy s(20)\n", __LINE__);
1687 EXPECT_EQ(1, gDestructions);
1688 EXPECT_EQ(1, gAlive);
1689 Spy::ClearActions();
1690 if (gDebug) {
1691 printf("%d - Run()\n", __LINE__);
1693 r5->Run();
1694 EXPECT_EQ(0, gCopyConstructions); // No copies in call.
1695 EXPECT_EQ(20, rpt->mSpy.mID);
1696 EXPECT_EQ(0, gDestructions);
1697 EXPECT_EQ(1, gAlive);
1698 Spy::ClearActions();
1699 if (gDebug) {
1700 printf("%d - End block with r\n", __LINE__);
1703 if (gDebug) {
1704 printf("%d - After end block with r\n", __LINE__);
1706 EXPECT_EQ(1, gDestructions);
1707 EXPECT_EQ(0, gAlive);
1709 Spy::ClearAll();
1710 if (gDebug) {
1711 printf("%d - Test: Store copy from prvalue, pass by const lvalue ref\n",
1712 __LINE__);
1715 if (gDebug) {
1716 printf(
1717 "%d - r6 = "
1718 "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef, "
1719 "Spy(21))\n",
1720 __LINE__);
1722 nsCOMPtr<nsIRunnable> r6 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(
1723 "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
1724 &ThreadUtilsObject::TestByConstLRef, Spy(21));
1725 EXPECT_EQ(1, gAlive);
1726 EXPECT_EQ(1, gConstructions);
1727 EXPECT_LE(1, gMoveConstructions);
1728 Spy::ClearActions();
1729 if (gDebug) {
1730 printf("%d - Run()\n", __LINE__);
1732 r6->Run();
1733 EXPECT_EQ(0, gCopyConstructions); // No copies in call.
1734 EXPECT_EQ(21, rpt->mSpy.mID);
1735 EXPECT_EQ(0, gDestructions);
1736 EXPECT_EQ(1, gAlive);
1737 Spy::ClearActions();
1738 if (gDebug) {
1739 printf("%d - End block with r\n", __LINE__);
1742 if (gDebug) {
1743 printf("%d - After end block with r\n", __LINE__);
1745 EXPECT_EQ(1, gDestructions);
1746 EXPECT_EQ(0, gAlive);
1748 Spy::ClearAll();
1749 if (gDebug) {
1750 printf("%d - Test: Store copy from lvalue, pass by rvalue ref\n", __LINE__);
1752 { // Block around nsCOMPtr lifetime.
1753 nsCOMPtr<nsIRunnable> r7;
1754 { // Block around Spy lifetime.
1755 if (gDebug) {
1756 printf("%d - Spy s(30)\n", __LINE__);
1758 Spy s(30);
1759 EXPECT_EQ(1, gConstructions);
1760 EXPECT_EQ(1, gAlive);
1761 if (gDebug) {
1762 printf(
1763 "%d - r7 = "
1764 "NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, s)\n",
1765 __LINE__);
1767 r7 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(
1768 "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
1769 &ThreadUtilsObject::TestByRRef, s);
1770 EXPECT_EQ(2, gAlive);
1771 EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
1772 Spy::ClearActions();
1773 if (gDebug) {
1774 printf("%d - End block with Spy s(30)\n", __LINE__);
1777 EXPECT_EQ(1, gDestructions);
1778 EXPECT_EQ(1, gAlive);
1779 Spy::ClearActions();
1780 if (gDebug) {
1781 printf("%d - Run()\n", __LINE__);
1783 r7->Run();
1784 EXPECT_LE(1, gMoves); // Move in call.
1785 EXPECT_EQ(30, rpt->mSpy.mID);
1786 EXPECT_EQ(0, gDestructions);
1787 EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
1788 EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
1789 Spy::ClearActions();
1790 if (gDebug) {
1791 printf("%d - End block with r\n", __LINE__);
1794 if (gDebug) {
1795 printf("%d - After end block with r\n", __LINE__);
1797 EXPECT_EQ(1, gDestructions);
1798 EXPECT_EQ(0, gAlive);
1800 Spy::ClearAll();
1801 if (gDebug) {
1802 printf("%d - Test: Store copy from prvalue, pass by rvalue ref\n",
1803 __LINE__);
1806 if (gDebug) {
1807 printf(
1808 "%d - r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, "
1809 "Spy(31))\n",
1810 __LINE__);
1812 nsCOMPtr<nsIRunnable> r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(
1813 "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
1814 &ThreadUtilsObject::TestByRRef, Spy(31));
1815 EXPECT_EQ(1, gAlive);
1816 EXPECT_EQ(1, gConstructions);
1817 EXPECT_LE(1, gMoveConstructions);
1818 Spy::ClearActions();
1819 if (gDebug) {
1820 printf("%d - Run()\n", __LINE__);
1822 r8->Run();
1823 EXPECT_LE(1, gMoves); // Move in call.
1824 EXPECT_EQ(31, rpt->mSpy.mID);
1825 EXPECT_EQ(0, gDestructions);
1826 EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
1827 EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
1828 Spy::ClearActions();
1829 if (gDebug) {
1830 printf("%d - End block with r\n", __LINE__);
1833 if (gDebug) {
1834 printf("%d - After end block with r\n", __LINE__);
1836 EXPECT_EQ(1, gDestructions);
1837 EXPECT_EQ(0, gAlive);
1839 Spy::ClearAll();
1840 if (gDebug) {
1841 printf("%d - Test: Store lvalue ref, pass lvalue ref\n", __LINE__);
1844 if (gDebug) {
1845 printf("%d - Spy s(40)\n", __LINE__);
1847 Spy s(40);
1848 EXPECT_EQ(1, gConstructions);
1849 EXPECT_EQ(1, gAlive);
1850 Spy::ClearActions();
1851 if (gDebug) {
1852 printf("%d - r9 = NewRunnableMethod<Spy&>(&TestByLRef, s)\n", __LINE__);
1854 nsCOMPtr<nsIRunnable> r9 = NewRunnableMethod<Spy&>(
1855 "TestThreadUtils::ThreadUtilsObject::TestByLRef", rpt,
1856 &ThreadUtilsObject::TestByLRef, s);
1857 EXPECT_EQ(0, gAllConstructions);
1858 EXPECT_EQ(0, gDestructions);
1859 EXPECT_EQ(1, gAlive);
1860 Spy::ClearActions();
1861 if (gDebug) {
1862 printf("%d - Run()\n", __LINE__);
1864 r9->Run();
1865 EXPECT_LE(1, gAssignments); // Assignment from reference in call.
1866 EXPECT_EQ(40, rpt->mSpy.mID);
1867 EXPECT_EQ(&s, rpt->mSpyPtr);
1868 EXPECT_EQ(0, gDestructions);
1869 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
1870 Spy::ClearActions();
1871 if (gDebug) {
1872 printf("%d - End block with r\n", __LINE__);
1875 if (gDebug) {
1876 printf("%d - After end block with r\n", __LINE__);
1878 EXPECT_EQ(1, gDestructions);
1879 EXPECT_EQ(0, gAlive);
1881 Spy::ClearAll();
1882 if (gDebug) {
1883 printf("%d - Test: Store nsRefPtr, pass by pointer\n", __LINE__);
1885 { // Block around nsCOMPtr lifetime.
1886 nsCOMPtr<nsIRunnable> r10;
1887 SpyWithISupports* ptr = 0;
1888 { // Block around RefPtr<Spy> lifetime.
1889 if (gDebug) {
1890 printf("%d - RefPtr<SpyWithISupports> s(new SpyWithISupports(45))\n",
1891 __LINE__);
1893 RefPtr<SpyWithISupports> s(new SpyWithISupports(45));
1894 ptr = s.get();
1895 EXPECT_EQ(1, gConstructions);
1896 EXPECT_EQ(1, gAlive);
1897 if (gDebug) {
1898 printf(
1899 "%d - r10 = "
1900 "NewRunnableMethod<StoreRefPtrPassByPtr<Spy>>(&TestByRRef, "
1901 "s.get())\n",
1902 __LINE__);
1904 r10 = NewRunnableMethod<StoreRefPtrPassByPtr<SpyWithISupports>>(
1905 "TestThreadUtils::ThreadUtilsObject::TestByPointer", rpt,
1906 &ThreadUtilsObject::TestByPointer, s.get());
1907 EXPECT_LE(0, gAllConstructions);
1908 EXPECT_EQ(1, gAlive);
1909 Spy::ClearActions();
1910 if (gDebug) {
1911 printf("%d - End block with RefPtr<Spy> s\n", __LINE__);
1914 EXPECT_EQ(0, gDestructions);
1915 EXPECT_EQ(1, gAlive);
1916 Spy::ClearActions();
1917 if (gDebug) {
1918 printf("%d - Run()\n", __LINE__);
1920 r10->Run();
1921 EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
1922 EXPECT_EQ(45, rpt->mSpy.mID);
1923 EXPECT_EQ(ptr, rpt->mSpyPtr);
1924 EXPECT_EQ(0, gDestructions);
1925 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
1926 Spy::ClearActions();
1927 if (gDebug) {
1928 printf("%d - End block with r\n", __LINE__);
1931 if (gDebug) {
1932 printf("%d - After end block with r\n", __LINE__);
1934 EXPECT_EQ(1, gDestructions);
1935 EXPECT_EQ(0, gAlive);
1937 Spy::ClearAll();
1938 if (gDebug) {
1939 printf("%d - Test: Store pointer to lvalue, pass by pointer\n", __LINE__);
1942 if (gDebug) {
1943 printf("%d - Spy s(55)\n", __LINE__);
1945 Spy s(55);
1946 EXPECT_EQ(1, gConstructions);
1947 EXPECT_EQ(1, gAlive);
1948 Spy::ClearActions();
1949 if (gDebug) {
1950 printf("%d - r11 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
1951 __LINE__);
1953 nsCOMPtr<nsIRunnable> r11 = NewRunnableMethod<Spy*>(
1954 "TestThreadUtils::ThreadUtilsObject::TestByPointer", rpt,
1955 &ThreadUtilsObject::TestByPointer, &s);
1956 EXPECT_EQ(0, gAllConstructions);
1957 EXPECT_EQ(0, gDestructions);
1958 EXPECT_EQ(1, gAlive);
1959 Spy::ClearActions();
1960 if (gDebug) {
1961 printf("%d - Run()\n", __LINE__);
1963 r11->Run();
1964 EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
1965 EXPECT_EQ(55, rpt->mSpy.mID);
1966 EXPECT_EQ(&s, rpt->mSpyPtr);
1967 EXPECT_EQ(0, gDestructions);
1968 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
1969 Spy::ClearActions();
1970 if (gDebug) {
1971 printf("%d - End block with r\n", __LINE__);
1974 if (gDebug) {
1975 printf("%d - After end block with r\n", __LINE__);
1977 EXPECT_EQ(1, gDestructions);
1978 EXPECT_EQ(0, gAlive);
1980 Spy::ClearAll();
1981 if (gDebug) {
1982 printf("%d - Test: Store pointer to const lvalue, pass by pointer\n",
1983 __LINE__);
1986 if (gDebug) {
1987 printf("%d - Spy s(60)\n", __LINE__);
1989 Spy s(60);
1990 EXPECT_EQ(1, gConstructions);
1991 EXPECT_EQ(1, gAlive);
1992 Spy::ClearActions();
1993 if (gDebug) {
1994 printf("%d - r12 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
1995 __LINE__);
1997 nsCOMPtr<nsIRunnable> r12 = NewRunnableMethod<const Spy*>(
1998 "TestThreadUtils::ThreadUtilsObject::TestByPointerToConst", rpt,
1999 &ThreadUtilsObject::TestByPointerToConst, &s);
2000 EXPECT_EQ(0, gAllConstructions);
2001 EXPECT_EQ(0, gDestructions);
2002 EXPECT_EQ(1, gAlive);
2003 Spy::ClearActions();
2004 if (gDebug) {
2005 printf("%d - Run()\n", __LINE__);
2007 r12->Run();
2008 EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
2009 EXPECT_EQ(60, rpt->mSpy.mID);
2010 EXPECT_EQ(&s, rpt->mSpyPtr);
2011 EXPECT_EQ(0, gDestructions);
2012 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
2013 Spy::ClearActions();
2014 if (gDebug) {
2015 printf("%d - End block with r\n", __LINE__);
2018 if (gDebug) {
2019 printf("%d - After end block with r\n", __LINE__);
2021 EXPECT_EQ(1, gDestructions);
2022 EXPECT_EQ(0, gAlive);