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/. */
7 #include "nsComponentManagerUtils.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
;
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
,
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
,
34 TEST_CALL_NEWTHREAD_SUICIDAL
,
38 bool gRunnableExecuted
[MAX_TESTS
];
40 class nsFoo
: public nsISupports
{
42 nsresult
DoFoo(bool* aBool
) {
48 virtual ~nsFoo() = default;
51 NS_IMPL_ISUPPORTS0(nsFoo
)
53 class TestSuicide
: public mozilla::Runnable
{
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);
63 MOZ_RELEASE_ASSERT(mThread
);
65 gRunnableExecuted
[TEST_CALL_NEWTHREAD_SUICIDAL
] = true;
70 nsCOMPtr
<nsIThread
> mThread
;
73 class nsBar
: public nsISupports
{
74 virtual ~nsBar() = default;
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;
88 void DoBar3(nsFoo
* aFoo
) {
89 aFoo
->DoFoo(&gRunnableExecuted
[TEST_CALL_NONVOID_ARG_VOID_RETURN
]);
91 nsresult
DoBar4(nsFoo
* aFoo
) {
93 &gRunnableExecuted
[TEST_CALL_NONVOID_ARG_NONVOID_RETURN
]);
95 void DoBar5(nsFoo
* aFoo
) {
97 gRunnableExecuted
[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT
] = true;
99 nsresult
DoBar6(char* aFoo
) {
101 gRunnableExecuted
[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT
] = true;
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;
112 void __stdcall
DoBar3std(nsFoo
* aFoo
) {
113 aFoo
->DoFoo(&gRunnableExecuted
[TEST_STDCALL_NONVOID_ARG_VOID_RETURN
]);
115 nsresult __stdcall
DoBar4std(nsFoo
* aFoo
) {
117 &gRunnableExecuted
[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN
]);
119 void __stdcall
DoBar5std(nsFoo
* aFoo
) {
121 gRunnableExecuted
[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT
] = true;
123 nsresult __stdcall
DoBar6std(char* aFoo
) {
125 gRunnableExecuted
[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT
] = true;
131 NS_IMPL_ISUPPORTS0(nsBar
)
133 struct TestCopyWithNoMove
{
134 explicit TestCopyWithNoMove(int* aCopyCounter
) : mCopyCounter(aCopyCounter
) {}
135 TestCopyWithNoMove(const TestCopyWithNoMove
& a
)
136 : mCopyCounter(a
.mCopyCounter
) {
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
); }
146 struct TestCopyWithDeletedMove
{
147 explicit TestCopyWithDeletedMove(int* aCopyCounter
)
148 : mCopyCounter(aCopyCounter
) {}
149 TestCopyWithDeletedMove(const TestCopyWithDeletedMove
& a
)
150 : mCopyCounter(a
.mCopyCounter
) {
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
); }
160 explicit TestMove(int* aMoveCounter
) : mMoveCounter(aMoveCounter
) {}
161 TestMove(const TestMove
&) = delete;
162 TestMove(TestMove
&& a
) : mMoveCounter(a
.mMoveCounter
) {
163 a
.mMoveCounter
= nullptr;
166 ~TestMove() { mMoveCounter
= nullptr; }
167 void operator()() { MOZ_RELEASE_ASSERT(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
) {
177 TestCopyMove(TestCopyMove
&& a
)
178 : mCopyCounter(a
.mCopyCounter
), mMoveCounter(a
.mMoveCounter
) {
179 a
.mMoveCounter
= nullptr;
183 mCopyCounter
= nullptr;
184 mMoveCounter
= nullptr;
187 MOZ_RELEASE_ASSERT(mCopyCounter
);
188 MOZ_RELEASE_ASSERT(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
205 EXPECT_TRUE(NS_SUCCEEDED(aRunnable
->GetName(name
))) << "Runnable::GetName()";
206 EXPECT_TRUE(name
.EqualsASCII(aExpectedName
)) << "Verify Runnable name";
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.
235 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
237 TestCopyWithNoMove
tracker(©Counter
);
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();
247 "RunnableFactory with copyable-only (and no move) function, "
254 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
256 // Passing as rvalue, but using copy.
257 // (TestCopyWithDeletedMove wouldn't allow this.)
259 aNamed
? RunnableFactory::Create("unused",
260 TestCopyWithNoMove(©Counter
))
261 : RunnableFactory::Create("TestNewRunnableFunction",
262 TestCopyWithNoMove(©Counter
));
264 trackedRunnable
->Run();
267 "RunnableFactory with copyable-only (and no move) function "
271 if constexpr (RunnableFactory::SupportsCopyWithDeletedMove
) {
274 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
276 TestCopyWithDeletedMove
tracker(©Counter
);
277 trackedRunnable
= aNamed
? RunnableFactory::Create("unused", tracker
)
278 : RunnableFactory::Create(
279 "TestNewRunnableFunction", tracker
);
281 trackedRunnable
->Run();
284 "RunnableFactory with copyable-only (and deleted move) "
289 // Test RunnableFactory with movable-only function object.
293 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
295 TestMove
tracker(&moveCounter
);
297 aNamed
? RunnableFactory::Create("unused", std::move(tracker
))
298 : RunnableFactory::Create("TestNewRunnableFunction",
301 trackedRunnable
->Run();
303 Expect("RunnableFactory with movable-only function, moves", moveCounter
, 1);
308 nsCOMPtr
<nsIRunnable
> 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",
321 // Test RunnableFactory with copyable&movable function object.
326 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
328 TestCopyMove
tracker(©Counter
, &moveCounter
);
330 aNamed
? RunnableFactory::Create("unused", std::move(tracker
))
331 : RunnableFactory::Create("TestNewRunnableFunction",
334 trackedRunnable
->Run();
336 Expect("RunnableFactory with copyable&movable function, copies",
338 Expect("RunnableFactory with copyable&movable function, moves", moveCounter
,
345 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
348 aNamed
? RunnableFactory::Create(
349 "unused", TestCopyMove(©Counter
, &moveCounter
))
350 : RunnableFactory::Create(
351 "TestNewRunnableFunction",
352 TestCopyMove(©Counter
, &moveCounter
));
354 trackedRunnable
->Run();
356 Expect("RunnableFactory with copyable&movable function rvalue, copies",
358 Expect("RunnableFactory with copyable&movable function rvalue, moves",
362 // Test RunnableFactory with copyable-only lambda capture.
366 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
368 TestCopyWithNoMove
tracker(©Counter
);
369 // Expect 2 copies (here -> local lambda -> runnable lambda).
372 ? RunnableFactory::Create("unused",
373 [tracker
]() mutable { tracker(); })
374 : RunnableFactory::Create("TestNewRunnableFunction",
375 [tracker
]() mutable { tracker(); });
377 trackedRunnable
->Run();
380 "RunnableFactory with copyable-only (and no move) capture, "
387 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
389 TestCopyWithDeletedMove
tracker(©Counter
);
390 // Expect 2 copies (here -> local lambda -> runnable lambda).
393 ? RunnableFactory::Create("unused",
394 [tracker
]() mutable { tracker(); })
395 : RunnableFactory::Create("TestNewRunnableFunction",
396 [tracker
]() mutable { tracker(); });
398 trackedRunnable
->Run();
401 "RunnableFactory with copyable-only (and deleted move) capture, "
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.
414 nsCOMPtr
<nsIRunnable
> trackedRunnable
;
416 TestCopyMove
tracker(©Counter
, &moveCounter
);
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
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);
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);
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
>();
473 RefPtr
<CancelableRunnable
> func
=
474 NS_NewCancelableRunnableFunction("unused", [foo
, &ran
] { ran
= true; });
476 EXPECT_EQ(foo
->refCount(), 2u);
479 EXPECT_EQ(foo
->refCount(), 1u);
483 // Test no-op after cancelation.
485 auto foo
= MakeRefPtr
<TestRefCounted
>();
488 RefPtr
<CancelableRunnable
> func
=
489 NS_NewCancelableRunnableFunction("unused", [foo
, &ran
] { ran
= true; });
491 EXPECT_EQ(foo
->refCount(), 2u);
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
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
),
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
,
537 : NewRunnableMethod
<RefPtr
<nsFoo
>>("nsBar::DoBar3", bar
,
538 &nsBar::DoBar3
, foo
));
539 NS_DispatchToMainThread(
540 aNamed
? NewRunnableMethod
<RefPtr
<nsFoo
>>("unused", bar
, &nsBar::DoBar4
,
542 : NewRunnableMethod
<RefPtr
<nsFoo
>>("nsBar::DoBar4", bar
,
543 &nsBar::DoBar4
, foo
));
544 NS_DispatchToMainThread(
546 ? NewRunnableMethod
<nsFoo
*>("unused", bar
, &nsBar::DoBar5
, rawFoo
)
547 : NewRunnableMethod
<nsFoo
*>("nsBar::DoBar5", bar
, &nsBar::DoBar5
,
549 NS_DispatchToMainThread(
551 ? NewRunnableMethod
<char*>("unused", bar
, &nsBar::DoBar6
, message
)
552 : NewRunnableMethod
<char*>("nsBar::DoBar6", bar
, &nsBar::DoBar6
,
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
,
572 : NewRunnableMethod
<nsFoo
*>(bar
, &nsBar::DoBar5std
, rawFoo
));
573 NS_DispatchToMainThread(
574 aNamed
? NewRunnableMethod
<char*>("unused", bar
, &nsBar::DoBar6std
,
576 : NewRunnableMethod
<char*>(bar
, &nsBar::DoBar6std
, message
));
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());
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);
607 RefPtr
<nsFoo
> foo
= new nsFoo();
608 const char* expectedName
= "NamedRunnable";
610 RefPtr
<Runnable
> NamedRunnable
=
611 NewRunnableMethod
<bool*>(expectedName
, foo
, &nsFoo::DoFoo
, &unused
);
612 ExpectRunnableName(NamedRunnable
, expectedName
);
616 class IdleObjectWithoutSetDeadline final
{
618 NS_INLINE_DECL_REFCOUNTING(IdleObjectWithoutSetDeadline
)
619 IdleObjectWithoutSetDeadline() : mRunnableExecuted(false) {}
620 void Method() { mRunnableExecuted
= true; }
621 bool mRunnableExecuted
;
624 ~IdleObjectWithoutSetDeadline() = default;
627 class IdleObjectParentWithSetDeadline
{
629 IdleObjectParentWithSetDeadline() : mSetDeadlineCalled(false) {}
630 void SetDeadline(TimeStamp aDeadline
) { mSetDeadlineCalled
= true; }
631 bool mSetDeadlineCalled
;
634 class IdleObjectInheritedSetDeadline final
635 : public IdleObjectParentWithSetDeadline
{
637 NS_INLINE_DECL_REFCOUNTING(IdleObjectInheritedSetDeadline
)
638 IdleObjectInheritedSetDeadline() : mRunnableExecuted(false) {}
639 void Method() { mRunnableExecuted
= true; }
640 bool mRunnableExecuted
;
643 ~IdleObjectInheritedSetDeadline() = default;
646 class IdleObject final
{
648 NS_INLINE_DECL_REFCOUNTING(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
) {
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";
671 CheckExecutedMethods("Method0", 0);
672 mRunnableExecuted
[0] = true;
673 mSetIdleDeadlineCalled
= false;
677 CheckExecutedMethods("Method1", 1);
678 ASSERT_TRUE(mSetIdleDeadlineCalled
);
679 mRunnableExecuted
[1] = true;
680 mSetIdleDeadlineCalled
= false;
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
));
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;
718 CheckExecutedMethods("Method5", 5);
719 ASSERT_TRUE(mSetIdleDeadlineCalled
);
720 mRunnableExecuted
[5] = true;
721 mSetIdleDeadlineCalled
= false;
725 CheckExecutedMethods("Method6", 6);
726 mRunnableExecuted
[6] = true;
727 mSetIdleDeadlineCalled
= false;
731 CheckExecutedMethods("Method7", 7);
732 ASSERT_TRUE(mSetIdleDeadlineCalled
);
733 mRunnableExecuted
[7] = true;
734 mSetIdleDeadlineCalled
= false;
738 nsCOMPtr
<nsITimer
> mTimer
;
739 bool mRunnableExecuted
[8];
740 bool mSetIdleDeadlineCalled
;
741 ~IdleObject() = default;
744 // Disable test due to frequent failures
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",
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
);
795 TEST(ThreadUtils
, IdleTaskRunner
)
797 using namespace mozilla
;
801 RefPtr
<IdleTaskRunner
> runner1
= IdleTaskRunner::Create(
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.
811 RefPtr
<IdleTaskRunner
> runner2
= IdleTaskRunner::Create(
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.
823 RefPtr
<IdleTaskRunner
> runner3
= IdleTaskRunner::Create(
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
834 RefPtr
<IdleTaskRunner
> runner4
= IdleTaskRunner::Create(
839 "runner4", 0, TimeDuration::FromMilliseconds(10),
840 TimeDuration::FromMilliseconds(3), false, nullptr);
842 // Firstly we wait until the two repeating tasks reach their limits.
844 SpinEventLoopUntil("xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt1"_ns
,
845 [&]() { return cnt1
>= 100; }));
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
, [&]() {
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.
861 // At any point ==> 0 <= cnt4 <= 1 since this is a non-repeating
863 MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
864 "xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt4"_ns
, [&]() {
865 // At any point: 0 <= cnt4 <= 1
867 EXPECT_TRUE(false) << "The 'mRepeating' flag doesn't work.";
868 return true; // Stop on failure.
873 // The repeating timers require an explicit Cancel() call.
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");
898 std::is_same_v
<int, mozilla::RemoveSmartPointer
<const RefPtr
<int>>>,
899 "RemoveSmartPointer<const RefPtr<int>> should be int");
901 std::is_same_v
<int, mozilla::RemoveSmartPointer
<volatile RefPtr
<int>>>,
902 "RemoveSmartPointer<volatile RefPtr<int>> should be 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");
910 std::is_same_v
<int, mozilla::RemoveSmartPointer
<const nsCOMPtr
<int>>>,
911 "RemoveSmartPointer<const nsCOMPtr<int>> should be int");
913 std::is_same_v
<int, mozilla::RemoveSmartPointer
<volatile nsCOMPtr
<int>>>,
914 "RemoveSmartPointer<volatile nsCOMPtr<int>> should be 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");
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");
929 std::is_same_v
<const int, mozilla::RemoveRawOrSmartPointer
<const int*>>,
930 "RemoveRawOrSmartPointer<const int*> should be const int");
932 std::is_same_v
<volatile int,
933 mozilla::RemoveRawOrSmartPointer
<volatile int*>>,
934 "RemoveRawOrSmartPointer<volatile int*> should be volatile int");
936 std::is_same_v
<const volatile int,
937 mozilla::RemoveRawOrSmartPointer
<const volatile int*>>,
938 "RemoveRawOrSmartPointer<const volatile int*> should be const "
941 std::is_same_v
<int, mozilla::RemoveRawOrSmartPointer
<RefPtr
<int>>>,
942 "RemoveRawOrSmartPointer<RefPtr<int>> should be int");
944 std::is_same_v
<int, mozilla::RemoveRawOrSmartPointer
<const RefPtr
<int>>>,
945 "RemoveRawOrSmartPointer<const RefPtr<int>> should be int");
948 mozilla::RemoveRawOrSmartPointer
<volatile RefPtr
<int>>>,
949 "RemoveRawOrSmartPointer<volatile RefPtr<int>> should be int");
952 int, mozilla::RemoveRawOrSmartPointer
<const volatile RefPtr
<int>>>,
953 "RemoveRawOrSmartPointer<const volatile RefPtr<int>> should be "
956 std::is_same_v
<int, mozilla::RemoveRawOrSmartPointer
<nsCOMPtr
<int>>>,
957 "RemoveRawOrSmartPointer<nsCOMPtr<int>> should be int");
960 mozilla::RemoveRawOrSmartPointer
<const nsCOMPtr
<int>>>,
961 "RemoveRawOrSmartPointer<const nsCOMPtr<int>> should be int");
964 mozilla::RemoveRawOrSmartPointer
<volatile nsCOMPtr
<int>>>,
965 "RemoveRawOrSmartPointer<volatile nsCOMPtr<int>> should be int");
968 int, mozilla::RemoveRawOrSmartPointer
<const volatile nsCOMPtr
<int>>>,
969 "RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>> should be "
973 namespace TestThreadUtils
{
975 static bool gDebug
= false;
976 static int gAlive
, gZombies
;
977 static int gAllConstructions
, gConstructions
, gCopyConstructions
,
978 gMoveConstructions
, gDestructions
, gAssignments
, gMoves
;
980 static void ClearActions() {
981 gAllConstructions
= gConstructions
= gCopyConstructions
=
982 gMoveConstructions
= gDestructions
= gAssignments
= gMoves
= 0;
984 static void ClearAll() {
989 explicit Spy(int aID
) : mID(aID
) {
994 printf("Spy[%d@%p]()\n", mID
, this);
997 Spy(const Spy
& o
) : mID(o
.mID
) {
1000 ++gCopyConstructions
;
1002 printf("Spy[%d@%p](&[%d@%p])\n", mID
, this, o
.mID
, &o
);
1005 Spy(Spy
&& o
) : mID(o
.mID
) {
1008 ++gAllConstructions
;
1009 ++gMoveConstructions
;
1011 printf("Spy[%d@%p](&&[%d->%d@%p])\n", mID
, this, -o
.mID
, o
.mID
, &o
);
1022 printf("~Spy[%d@%p]()\n", mID
, this);
1026 Spy
& operator=(const Spy
& o
) {
1029 printf("Spy[%d->%d@%p] = &[%d@%p]\n", mID
, o
.mID
, this, o
.mID
, &o
);
1034 Spy
& operator=(Spy
&& o
) {
1039 printf("Spy[%d->%d@%p] = &&[%d->%d@%p]\n", mID
, o
.mID
, this, o
.mID
,
1047 int mID
; // ID given at construction, or negation if was moved from; 0 when
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
{
1059 virtual ~SpyWithISupports() = default;
1062 explicit SpyWithISupports(int aID
) : Spy(aID
){};
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
{
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
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
;
1097 : mCount(0), mA0(0), mA1(0), mA2(0), mA3(0), mSpy(1), mSpyPtr(nullptr) {}
1100 virtual ~ThreadUtilsObject() = default;
1103 void Test0() { mCount
+= 1; }
1104 void Test1i(int a0
) {
1108 void Test2i(int a0
, int a1
) {
1113 void Test3i(int a0
, int a1
, int a2
) {
1119 void Test4i(int a0
, int a1
, int a2
, int a3
) {
1126 void Test1pi(int* ap
) {
1128 mA0
= ap
? *ap
: -1;
1130 void Test1pci(const int* ap
) {
1132 mA0
= ap
? *ap
: -1;
1134 void Test1ri(int& ar
) {
1138 void Test1rri(int&& arr
) {
1142 void Test1upi(mozilla::UniquePtr
<int> aup
) {
1144 mA0
= aup
? *aup
: -1;
1146 void Test1rupi(mozilla::UniquePtr
<int>& aup
) {
1148 mA0
= aup
? *aup
: -1;
1150 void Test1rrupi(mozilla::UniquePtr
<int>&& aup
) {
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
) {
1166 printf("TestByValue(Spy[%d@%p])\n", s
.mID
, &s
);
1170 void TestByConstLRef(const Spy
& s
) {
1172 printf("TestByConstLRef(Spy[%d@%p]&)\n", s
.mID
, &s
);
1176 void TestByRRef(Spy
&& s
) {
1178 printf("TestByRRef(Spy[%d@%p]&&)\n", s
.mID
, &s
);
1180 mSpy
= std::move(s
);
1182 void TestByLRef(Spy
& s
) {
1184 printf("TestByLRef(Spy[%d@%p]&)\n", s
.mID
, &s
);
1189 void TestByPointer(Spy
* p
) {
1192 printf("TestByPointer(&Spy[%d@%p])\n", p
->mID
, p
);
1197 printf("TestByPointer(nullptr)\n");
1202 void TestByPointerToConst(const Spy
* p
) {
1205 printf("TestByPointerToConst(&Spy[%d@%p])\n", p
->mID
, p
);
1210 printf("TestByPointerToConst(nullptr)\n");
1217 NS_IMPL_ISUPPORTS(ThreadUtilsObject
, IThreadUtilsObject
)
1219 class ThreadUtilsRefCountedFinal final
{
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
; }
1232 class ThreadUtilsRefCountedBase
{
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
; }
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");
1258 IsParameterStorageClass
<StoreCopyPassByConstLRef
<int>>::value
,
1259 "StoreCopyPassByConstLRef<int> should be recognized as Storage Class");
1261 IsParameterStorageClass
<StoreCopyPassByRRef
<int>>::value
,
1262 "StoreCopyPassByRRef<int> should be recognized as Storage Class");
1264 IsParameterStorageClass
<StoreRefPassByLRef
<int>>::value
,
1265 "StoreRefPassByLRef<int> should be recognized as Storage Class");
1267 IsParameterStorageClass
<StoreConstRefPassByConstLRef
<int>>::value
,
1268 "StoreConstRefPassByConstLRef<int> should be recognized as Storage "
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");
1276 IsParameterStorageClass
<StoreConstPtrPassByConstPtr
<int>>::value
,
1277 "StoreConstPtrPassByConstPtr<int> should be recognized as Storage Class");
1279 RefPtr
<ThreadUtilsObject
> rpt(new ThreadUtilsObject
);
1282 // Test legacy functions.
1284 nsCOMPtr
<nsIRunnable
> r1
=
1285 NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt
,
1286 &ThreadUtilsObject::Test0
);
1288 EXPECT_EQ(count
+= 1, rpt
->mCount
);
1290 r1
= NewRunnableMethod
<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt
,
1291 &ThreadUtilsObject::Test1i
, 11);
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
);
1303 EXPECT_EQ(count
, rpt
->mCount
);
1305 // Test variadic function with simple POD arguments.
1307 r1
= NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt
,
1308 &ThreadUtilsObject::Test0
);
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);
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);
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);
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);
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.
1353 r1
= NewRunnableMethod
<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt
,
1354 &ThreadUtilsObject::Test1i
, si
);
1356 EXPECT_EQ(count
+= 2, rpt
->mCount
);
1357 EXPECT_EQ(si
, rpt
->mA0
);
1359 // Raw pointer, possible cv-qualified.
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>");
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>");
1378 std::is_same_v
<::detail::ParameterStorage
<int*>::Type::stored_type
, int*>,
1379 "detail::ParameterStorage<int*>::Type::stored_type should be int*");
1381 std::is_same_v
<::detail::ParameterStorage
<int*>::Type::passed_type
, int*>,
1382 "detail::ParameterStorage<int*>::Type::passed_type should be int*");
1385 r1
= NewRunnableMethod
<int*>("TestThreadUtils::ThreadUtilsObject::Test1pi",
1386 rpt
, &ThreadUtilsObject::Test1pi
, &i
);
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>");
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>");
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>");
1413 std::is_same_v
<::detail::ParameterStorage
<const int*>::Type::stored_type
,
1415 "detail::ParameterStorage<const int*>::Type::stored_type should be const "
1418 std::is_same_v
<::detail::ParameterStorage
<const int*>::Type::passed_type
,
1420 "detail::ParameterStorage<const int*>::Type::passed_type should be const "
1424 r1
= NewRunnableMethod
<const int*>(
1425 "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt
,
1426 &ThreadUtilsObject::Test1pci
, &i
);
1428 EXPECT_EQ(count
+= 2, rpt
->mCount
);
1429 EXPECT_EQ(i
, rpt
->mA0
);
1432 // nsRefPtr to pointer.
1434 std::is_same_v
<::detail::ParameterStorage
<
1435 StoreRefPtrPassByPtr
<SpyWithISupports
>>::Type
,
1436 StoreRefPtrPassByPtr
<SpyWithISupports
>>,
1437 "ParameterStorage<StoreRefPtrPassByPtr<SpyWithISupports>>::Type should "
1438 "be StoreRefPtrPassByPtr<SpyWithISupports>");
1440 std::is_same_v
<::detail::ParameterStorage
<SpyWithISupports
*>::Type
,
1441 StoreRefPtrPassByPtr
<SpyWithISupports
>>,
1442 "ParameterStorage<SpyWithISupports*>::Type should be "
1443 "StoreRefPtrPassByPtr<SpyWithISupports>");
1445 std::is_same_v
<StoreRefPtrPassByPtr
<SpyWithISupports
>::stored_type
,
1446 RefPtr
<SpyWithISupports
>>,
1447 "StoreRefPtrPassByPtr<SpyWithISupports>::stored_type should be "
1448 "RefPtr<SpyWithISupports>");
1450 std::is_same_v
<StoreRefPtrPassByPtr
<SpyWithISupports
>::passed_type
,
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()");
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()");
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()");
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.
1492 std::is_same_v
<::detail::ParameterStorage
<int&>::Type
,
1493 StoreRefPassByLRef
<int>>,
1494 "ParameterStorage<int&>::Type should be StoreRefPassByLRef<int>");
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");
1501 std::is_same_v
<::detail::ParameterStorage
<int&>::Type::stored_type
, int&>,
1502 "ParameterStorage<int&>::Type::stored_type should be int&");
1504 std::is_same_v
<::detail::ParameterStorage
<int&>::Type::passed_type
, int&>,
1505 "ParameterStorage<int&>::Type::passed_type should be int&");
1508 r1
= NewRunnableMethod
<int&>("TestThreadUtils::ThreadUtilsObject::Test1ri",
1509 rpt
, &ThreadUtilsObject::Test1ri
, i
);
1511 EXPECT_EQ(count
+= 2, rpt
->mCount
);
1512 EXPECT_EQ(i
, rpt
->mA0
);
1515 // Rvalue reference -- Actually storing a copy and then moving it.
1517 std::is_same_v
<::detail::ParameterStorage
<int&&>::Type
,
1518 StoreCopyPassByRRef
<int>>,
1519 "ParameterStorage<int&&>::Type should be StoreCopyPassByRRef<int>");
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");
1526 std::is_same_v
<::detail::ParameterStorage
<int&&>::Type::stored_type
, int>,
1527 "ParameterStorage<int&&>::Type::stored_type should be int");
1529 std::is_same_v
<::detail::ParameterStorage
<int&&>::Type::passed_type
,
1531 "ParameterStorage<int&&>::Type::passed_type should be int&&");
1534 r1
= NewRunnableMethod
<int&&>(
1535 "TestThreadUtils::ThreadUtilsObject::Test1rri", rpt
,
1536 &ThreadUtilsObject::Test1rri
, std::move(i
));
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>>");
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");
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 "
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
));
1573 EXPECT_EQ(count
+= 2, rpt
->mCount
);
1574 EXPECT_EQ(-1, rpt
->mA0
);
1577 // Null unique pointer, by explicit store&move with "StoreCopyPassByRRef<T>"
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");
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");
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>");
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
));
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
));
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
));
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));
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!
1651 EXPECT_EQ(count
+= 2, rpt
->mCount
);
1652 EXPECT_EQ(-1, rpt
->mA0
);
1654 // Verify copy/move assumptions.
1658 printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n",
1661 { // Block around nsCOMPtr lifetime.
1662 nsCOMPtr
<nsIRunnable
> r5
;
1663 { // Block around Spy lifetime.
1665 printf("%d - Spy s(20)\n", __LINE__
);
1668 EXPECT_EQ(1, gConstructions
);
1669 EXPECT_EQ(1, gAlive
);
1673 "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef,"
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();
1684 printf("%d - End block with Spy s(20)\n", __LINE__
);
1687 EXPECT_EQ(1, gDestructions
);
1688 EXPECT_EQ(1, gAlive
);
1689 Spy::ClearActions();
1691 printf("%d - Run()\n", __LINE__
);
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();
1700 printf("%d - End block with r\n", __LINE__
);
1704 printf("%d - After end block with r\n", __LINE__
);
1706 EXPECT_EQ(1, gDestructions
);
1707 EXPECT_EQ(0, gAlive
);
1711 printf("%d - Test: Store copy from prvalue, pass by const lvalue ref\n",
1718 "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef, "
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();
1730 printf("%d - Run()\n", __LINE__
);
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();
1739 printf("%d - End block with r\n", __LINE__
);
1743 printf("%d - After end block with r\n", __LINE__
);
1745 EXPECT_EQ(1, gDestructions
);
1746 EXPECT_EQ(0, gAlive
);
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.
1756 printf("%d - Spy s(30)\n", __LINE__
);
1759 EXPECT_EQ(1, gConstructions
);
1760 EXPECT_EQ(1, gAlive
);
1764 "NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, s)\n",
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();
1774 printf("%d - End block with Spy s(30)\n", __LINE__
);
1777 EXPECT_EQ(1, gDestructions
);
1778 EXPECT_EQ(1, gAlive
);
1779 Spy::ClearActions();
1781 printf("%d - Run()\n", __LINE__
);
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();
1791 printf("%d - End block with r\n", __LINE__
);
1795 printf("%d - After end block with r\n", __LINE__
);
1797 EXPECT_EQ(1, gDestructions
);
1798 EXPECT_EQ(0, gAlive
);
1802 printf("%d - Test: Store copy from prvalue, pass by rvalue ref\n",
1808 "%d - r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, "
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();
1820 printf("%d - Run()\n", __LINE__
);
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();
1830 printf("%d - End block with r\n", __LINE__
);
1834 printf("%d - After end block with r\n", __LINE__
);
1836 EXPECT_EQ(1, gDestructions
);
1837 EXPECT_EQ(0, gAlive
);
1841 printf("%d - Test: Store lvalue ref, pass lvalue ref\n", __LINE__
);
1845 printf("%d - Spy s(40)\n", __LINE__
);
1848 EXPECT_EQ(1, gConstructions
);
1849 EXPECT_EQ(1, gAlive
);
1850 Spy::ClearActions();
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();
1862 printf("%d - Run()\n", __LINE__
);
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();
1872 printf("%d - End block with r\n", __LINE__
);
1876 printf("%d - After end block with r\n", __LINE__
);
1878 EXPECT_EQ(1, gDestructions
);
1879 EXPECT_EQ(0, gAlive
);
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.
1890 printf("%d - RefPtr<SpyWithISupports> s(new SpyWithISupports(45))\n",
1893 RefPtr
<SpyWithISupports
> s(new SpyWithISupports(45));
1895 EXPECT_EQ(1, gConstructions
);
1896 EXPECT_EQ(1, gAlive
);
1900 "NewRunnableMethod<StoreRefPtrPassByPtr<Spy>>(&TestByRRef, "
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();
1911 printf("%d - End block with RefPtr<Spy> s\n", __LINE__
);
1914 EXPECT_EQ(0, gDestructions
);
1915 EXPECT_EQ(1, gAlive
);
1916 Spy::ClearActions();
1918 printf("%d - Run()\n", __LINE__
);
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();
1928 printf("%d - End block with r\n", __LINE__
);
1932 printf("%d - After end block with r\n", __LINE__
);
1934 EXPECT_EQ(1, gDestructions
);
1935 EXPECT_EQ(0, gAlive
);
1939 printf("%d - Test: Store pointer to lvalue, pass by pointer\n", __LINE__
);
1943 printf("%d - Spy s(55)\n", __LINE__
);
1946 EXPECT_EQ(1, gConstructions
);
1947 EXPECT_EQ(1, gAlive
);
1948 Spy::ClearActions();
1950 printf("%d - r11 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
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();
1961 printf("%d - Run()\n", __LINE__
);
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();
1971 printf("%d - End block with r\n", __LINE__
);
1975 printf("%d - After end block with r\n", __LINE__
);
1977 EXPECT_EQ(1, gDestructions
);
1978 EXPECT_EQ(0, gAlive
);
1982 printf("%d - Test: Store pointer to const lvalue, pass by pointer\n",
1987 printf("%d - Spy s(60)\n", __LINE__
);
1990 EXPECT_EQ(1, gConstructions
);
1991 EXPECT_EQ(1, gAlive
);
1992 Spy::ClearActions();
1994 printf("%d - r12 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
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();
2005 printf("%d - Run()\n", __LINE__
);
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();
2015 printf("%d - End block with r\n", __LINE__
);
2019 printf("%d - After end block with r\n", __LINE__
);
2021 EXPECT_EQ(1, gDestructions
);
2022 EXPECT_EQ(0, gAlive
);