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/. */
4
5 #include <type_traits>
6
7 #include "nsComponentManagerUtils.h"
8 #include "nsThreadUtils.h"
9 #include "mozilla/IdleTaskRunner.h"
10 #include "mozilla/RefCounted.h"
11 #include "mozilla/SpinEventLoopUntil.h"
12 #include "mozilla/UniquePtr.h"
13
14 #include "gtest/gtest.h"
15
16 using namespace mozilla;
17
18 enum {
19 TEST_CALL_VOID_ARG_VOID_RETURN,
20 TEST_CALL_VOID_ARG_VOID_RETURN_CONST,
21 TEST_CALL_VOID_ARG_NONVOID_RETURN,
22 TEST_CALL_NONVOID_ARG_VOID_RETURN,
23 TEST_CALL_NONVOID_ARG_NONVOID_RETURN,
24 TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT,
25 TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
26 #ifdef HAVE_STDCALL
27 TEST_STDCALL_VOID_ARG_VOID_RETURN,
28 TEST_STDCALL_VOID_ARG_NONVOID_RETURN,
29 TEST_STDCALL_NONVOID_ARG_VOID_RETURN,
30 TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN,
31 TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
32 #endif
33 TEST_CALL_NEWTHREAD_SUICIDAL,
34 MAX_TESTS
35 };
36
37 bool gRunnableExecuted[MAX_TESTS];
38
39 class nsFoo : public nsISupports {
40 NS_DECL_ISUPPORTS
DoFoo(bool * aBool)41 nsresult DoFoo(bool* aBool) {
42 *aBool = true;
43 return NS_OK;
44 }
45
46 private:
47 virtual ~nsFoo() = default;
48 };
49
50 NS_IMPL_ISUPPORTS0(nsFoo)
51
52 class TestSuicide : public mozilla::Runnable {
53 public:
TestSuicide()54 TestSuicide() : mozilla::Runnable("TestSuicide") {}
Run()55 NS_IMETHOD Run() override {
56 // Runs first time on thread "Suicide", then dies on MainThread
57 if (!NS_IsMainThread()) {
58 mThread = do_GetCurrentThread();
59 NS_DispatchToMainThread(this);
60 return NS_OK;
61 }
62 MOZ_RELEASE_ASSERT(mThread);
63 mThread->Shutdown();
64 gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true;
65 return NS_OK;
66 }
67
68 private:
69 nsCOMPtr<nsIThread> mThread;
70 };
71
72 class nsBar : public nsISupports {
73 virtual ~nsBar() = default;
74
75 public:
76 NS_DECL_ISUPPORTS
DoBar1(void)77 void DoBar1(void) {
78 gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true;
79 }
DoBar1Const(void) const80 void DoBar1Const(void) const {
81 gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN_CONST] = true;
82 }
DoBar2(void)83 nsresult DoBar2(void) {
84 gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true;
85 return NS_OK;
86 }
DoBar3(nsFoo * aFoo)87 void DoBar3(nsFoo* aFoo) {
88 aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN]);
89 }
DoBar4(nsFoo * aFoo)90 nsresult DoBar4(nsFoo* aFoo) {
91 return aFoo->DoFoo(
92 &gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN]);
93 }
DoBar5(nsFoo * aFoo)94 void DoBar5(nsFoo* aFoo) {
95 if (aFoo)
96 gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
97 }
DoBar6(char * aFoo)98 nsresult DoBar6(char* aFoo) {
99 if (strlen(aFoo))
100 gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT] = true;
101 return NS_OK;
102 }
103 #ifdef HAVE_STDCALL
DoBar1std(void)104 void __stdcall DoBar1std(void) {
105 gRunnableExecuted[TEST_STDCALL_VOID_ARG_VOID_RETURN] = true;
106 }
DoBar2std(void)107 nsresult __stdcall DoBar2std(void) {
108 gRunnableExecuted[TEST_STDCALL_VOID_ARG_NONVOID_RETURN] = true;
109 return NS_OK;
110 }
DoBar3std(nsFoo * aFoo)111 void __stdcall DoBar3std(nsFoo* aFoo) {
112 aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN]);
113 }
DoBar4std(nsFoo * aFoo)114 nsresult __stdcall DoBar4std(nsFoo* aFoo) {
115 return aFoo->DoFoo(
116 &gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN]);
117 }
DoBar5std(nsFoo * aFoo)118 void __stdcall DoBar5std(nsFoo* aFoo) {
119 if (aFoo)
120 gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
121 }
DoBar6std(char * aFoo)122 nsresult __stdcall DoBar6std(char* aFoo) {
123 if (strlen(aFoo))
124 gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
125 return NS_OK;
126 }
127 #endif
128 };
129
130 NS_IMPL_ISUPPORTS0(nsBar)
131
132 struct TestCopyWithNoMove {
TestCopyWithNoMoveTestCopyWithNoMove133 explicit TestCopyWithNoMove(int* aCopyCounter) : mCopyCounter(aCopyCounter) {}
TestCopyWithNoMoveTestCopyWithNoMove134 TestCopyWithNoMove(const TestCopyWithNoMove& a)
135 : mCopyCounter(a.mCopyCounter) {
136 *mCopyCounter += 1;
137 };
138 // No 'move' declaration, allows passing object by rvalue copy.
139 // Destructor nulls member variable...
~TestCopyWithNoMoveTestCopyWithNoMove140 ~TestCopyWithNoMove() { mCopyCounter = nullptr; }
141 // ... so we can check that the object is called when still alive.
operator ()TestCopyWithNoMove142 void operator()() { MOZ_RELEASE_ASSERT(mCopyCounter); }
143 int* mCopyCounter;
144 };
145 struct TestCopyWithDeletedMove {
TestCopyWithDeletedMoveTestCopyWithDeletedMove146 explicit TestCopyWithDeletedMove(int* aCopyCounter)
147 : mCopyCounter(aCopyCounter) {}
TestCopyWithDeletedMoveTestCopyWithDeletedMove148 TestCopyWithDeletedMove(const TestCopyWithDeletedMove& a)
149 : mCopyCounter(a.mCopyCounter) {
150 *mCopyCounter += 1;
151 };
152 // Deleted move prevents passing by rvalue (even if copy would work)
153 TestCopyWithDeletedMove(TestCopyWithDeletedMove&&) = delete;
~TestCopyWithDeletedMoveTestCopyWithDeletedMove154 ~TestCopyWithDeletedMove() { mCopyCounter = nullptr; }
operator ()TestCopyWithDeletedMove155 void operator()() { MOZ_RELEASE_ASSERT(mCopyCounter); }
156 int* mCopyCounter;
157 };
158 struct TestMove {
TestMoveTestMove159 explicit TestMove(int* aMoveCounter) : mMoveCounter(aMoveCounter) {}
160 TestMove(const TestMove&) = delete;
TestMoveTestMove161 TestMove(TestMove&& a) : mMoveCounter(a.mMoveCounter) {
162 a.mMoveCounter = nullptr;
163 *mMoveCounter += 1;
164 }
~TestMoveTestMove165 ~TestMove() { mMoveCounter = nullptr; }
operator ()TestMove166 void operator()() { MOZ_RELEASE_ASSERT(mMoveCounter); }
167 int* mMoveCounter;
168 };
169 struct TestCopyMove {
TestCopyMoveTestCopyMove170 TestCopyMove(int* aCopyCounter, int* aMoveCounter)
171 : mCopyCounter(aCopyCounter), mMoveCounter(aMoveCounter) {}
TestCopyMoveTestCopyMove172 TestCopyMove(const TestCopyMove& a)
173 : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) {
174 *mCopyCounter += 1;
175 };
TestCopyMoveTestCopyMove176 TestCopyMove(TestCopyMove&& a)
177 : mCopyCounter(a.mCopyCounter), mMoveCounter(a.mMoveCounter) {
178 a.mMoveCounter = nullptr;
179 *mMoveCounter += 1;
180 }
~TestCopyMoveTestCopyMove181 ~TestCopyMove() {
182 mCopyCounter = nullptr;
183 mMoveCounter = nullptr;
184 }
operator ()TestCopyMove185 void operator()() {
186 MOZ_RELEASE_ASSERT(mCopyCounter);
187 MOZ_RELEASE_ASSERT(mMoveCounter);
188 }
189 int* mCopyCounter;
190 int* mMoveCounter;
191 };
192
193 struct TestRefCounted : RefCounted<TestRefCounted> {
194 MOZ_DECLARE_REFCOUNTED_TYPENAME(TestRefCounted);
195 };
196
Expect(const char * aContext,int aCounter,int aMaxExpected)197 static void Expect(const char* aContext, int aCounter, int aMaxExpected) {
198 EXPECT_LE(aCounter, aMaxExpected) << aContext;
199 }
200
ExpectRunnableName(Runnable * aRunnable,const char * aExpectedName)201 static void ExpectRunnableName(Runnable* aRunnable, const char* aExpectedName) {
202 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
203 nsAutoCString name;
204 EXPECT_TRUE(NS_SUCCEEDED(aRunnable->GetName(name))) << "Runnable::GetName()";
205 EXPECT_TRUE(name.EqualsASCII(aExpectedName)) << "Verify Runnable name";
206 #endif
207 }
208
209 struct BasicRunnableFactory {
210 static constexpr bool SupportsCopyWithDeletedMove = true;
211
212 template <typename Function>
CreateBasicRunnableFactory213 static auto Create(const char* aName, Function&& aFunc) {
214 return NS_NewRunnableFunction(aName, std::forward<Function>(aFunc));
215 }
216 };
217
218 struct CancelableRunnableFactory {
219 static constexpr bool SupportsCopyWithDeletedMove = false;
220
221 template <typename Function>
CreateCancelableRunnableFactory222 static auto Create(const char* aName, Function&& aFunc) {
223 return NS_NewCancelableRunnableFunction(aName,
224 std::forward<Function>(aFunc));
225 }
226 };
227
228 template <typename RunnableFactory>
TestRunnableFactory(bool aNamed)229 static void TestRunnableFactory(bool aNamed) {
230 // Test RunnableFactory with copyable-only function object.
231 {
232 int copyCounter = 0;
233 {
234 nsCOMPtr<nsIRunnable> trackedRunnable;
235 {
236 TestCopyWithNoMove tracker(©Counter);
237 trackedRunnable = aNamed ? RunnableFactory::Create("unused", tracker)
238 : RunnableFactory::Create(
239 "TestNewRunnableFunction", tracker);
240 // Original 'tracker' is destroyed here.
241 }
242 // Verify that the runnable contains a non-destroyed function object.
243 trackedRunnable->Run();
244 }
245 Expect(
246 "RunnableFactory with copyable-only (and no move) function, "
247 "copies",
248 copyCounter, 1);
249 }
250 {
251 int copyCounter = 0;
252 {
253 nsCOMPtr<nsIRunnable> trackedRunnable;
254 {
255 // Passing as rvalue, but using copy.
256 // (TestCopyWithDeletedMove wouldn't allow this.)
257 trackedRunnable =
258 aNamed ? RunnableFactory::Create("unused",
259 TestCopyWithNoMove(©Counter))
260 : RunnableFactory::Create("TestNewRunnableFunction",
261 TestCopyWithNoMove(©Counter));
262 }
263 trackedRunnable->Run();
264 }
265 Expect(
266 "RunnableFactory with copyable-only (and no move) function "
267 "rvalue, copies",
268 copyCounter, 1);
269 }
270 if constexpr (RunnableFactory::SupportsCopyWithDeletedMove) {
271 int copyCounter = 0;
272 {
273 nsCOMPtr<nsIRunnable> trackedRunnable;
274 {
275 TestCopyWithDeletedMove tracker(©Counter);
276 trackedRunnable = aNamed ? RunnableFactory::Create("unused", tracker)
277 : RunnableFactory::Create(
278 "TestNewRunnableFunction", tracker);
279 }
280 trackedRunnable->Run();
281 }
282 Expect(
283 "RunnableFactory with copyable-only (and deleted move) "
284 "function, copies",
285 copyCounter, 1);
286 }
287
288 // Test RunnableFactory with movable-only function object.
289 {
290 int moveCounter = 0;
291 {
292 nsCOMPtr<nsIRunnable> trackedRunnable;
293 {
294 TestMove tracker(&moveCounter);
295 trackedRunnable =
296 aNamed ? RunnableFactory::Create("unused", std::move(tracker))
297 : RunnableFactory::Create("TestNewRunnableFunction",
298 std::move(tracker));
299 }
300 trackedRunnable->Run();
301 }
302 Expect("RunnableFactory with movable-only function, moves", moveCounter, 1);
303 }
304 {
305 int moveCounter = 0;
306 {
307 nsCOMPtr<nsIRunnable> trackedRunnable;
308 {
309 trackedRunnable =
310 aNamed ? RunnableFactory::Create("unused", TestMove(&moveCounter))
311 : RunnableFactory::Create("TestNewRunnableFunction",
312 TestMove(&moveCounter));
313 }
314 trackedRunnable->Run();
315 }
316 Expect("RunnableFactory with movable-only function rvalue, moves",
317 moveCounter, 1);
318 }
319
320 // Test RunnableFactory with copyable&movable function object.
321 {
322 int copyCounter = 0;
323 int moveCounter = 0;
324 {
325 nsCOMPtr<nsIRunnable> trackedRunnable;
326 {
327 TestCopyMove tracker(©Counter, &moveCounter);
328 trackedRunnable =
329 aNamed ? RunnableFactory::Create("unused", std::move(tracker))
330 : RunnableFactory::Create("TestNewRunnableFunction",
331 std::move(tracker));
332 }
333 trackedRunnable->Run();
334 }
335 Expect("RunnableFactory with copyable&movable function, copies",
336 copyCounter, 0);
337 Expect("RunnableFactory with copyable&movable function, moves", moveCounter,
338 1);
339 }
340 {
341 int copyCounter = 0;
342 int moveCounter = 0;
343 {
344 nsCOMPtr<nsIRunnable> trackedRunnable;
345 {
346 trackedRunnable =
347 aNamed ? RunnableFactory::Create(
348 "unused", TestCopyMove(©Counter, &moveCounter))
349 : RunnableFactory::Create(
350 "TestNewRunnableFunction",
351 TestCopyMove(©Counter, &moveCounter));
352 }
353 trackedRunnable->Run();
354 }
355 Expect("RunnableFactory with copyable&movable function rvalue, copies",
356 copyCounter, 0);
357 Expect("RunnableFactory with copyable&movable function rvalue, moves",
358 moveCounter, 1);
359 }
360
361 // Test RunnableFactory with copyable-only lambda capture.
362 {
363 int copyCounter = 0;
364 {
365 nsCOMPtr<nsIRunnable> trackedRunnable;
366 {
367 TestCopyWithNoMove tracker(©Counter);
368 // Expect 2 copies (here -> local lambda -> runnable lambda).
369 trackedRunnable =
370 aNamed
371 ? RunnableFactory::Create("unused",
372 [tracker]() mutable { tracker(); })
373 : RunnableFactory::Create("TestNewRunnableFunction",
374 [tracker]() mutable { tracker(); });
375 }
376 trackedRunnable->Run();
377 }
378 Expect(
379 "RunnableFactory with copyable-only (and no move) capture, "
380 "copies",
381 copyCounter, 2);
382 }
383 {
384 int copyCounter = 0;
385 {
386 nsCOMPtr<nsIRunnable> trackedRunnable;
387 {
388 TestCopyWithDeletedMove tracker(©Counter);
389 // Expect 2 copies (here -> local lambda -> runnable lambda).
390 trackedRunnable =
391 aNamed
392 ? RunnableFactory::Create("unused",
393 [tracker]() mutable { tracker(); })
394 : RunnableFactory::Create("TestNewRunnableFunction",
395 [tracker]() mutable { tracker(); });
396 }
397 trackedRunnable->Run();
398 }
399 Expect(
400 "RunnableFactory with copyable-only (and deleted move) capture, "
401 "copies",
402 copyCounter, 2);
403 }
404
405 // Note: Not possible to use move-only captures.
406 // (Until we can use C++14 generalized lambda captures)
407
408 // Test RunnableFactory with copyable&movable lambda capture.
409 {
410 int copyCounter = 0;
411 int moveCounter = 0;
412 {
413 nsCOMPtr<nsIRunnable> trackedRunnable;
414 {
415 TestCopyMove tracker(©Counter, &moveCounter);
416 trackedRunnable =
417 aNamed
418 ? RunnableFactory::Create("unused",
419 [tracker]() mutable { tracker(); })
420 : RunnableFactory::Create("TestNewRunnableFunction",
421 [tracker]() mutable { tracker(); });
422 // Expect 1 copy (here -> local lambda) and 1 move (local -> runnable
423 // lambda).
424 }
425 trackedRunnable->Run();
426 }
427 Expect("RunnableFactory with copyable&movable capture, copies", copyCounter,
428 1);
429 Expect("RunnableFactory with copyable&movable capture, moves", moveCounter,
430 1);
431 }
432 }
433
TEST(ThreadUtils,NewRunnableFunction)434 TEST(ThreadUtils, NewRunnableFunction)
435 { TestRunnableFactory<BasicRunnableFactory>(/*aNamed*/ false); }
436
TEST(ThreadUtils,NewNamedRunnableFunction)437 TEST(ThreadUtils, NewNamedRunnableFunction)
438 {
439 // The named overload shall behave identical to the non-named counterpart.
440 TestRunnableFactory<BasicRunnableFactory>(/*aNamed*/ true);
441
442 // Test naming.
443 {
444 const char* expectedName = "NamedRunnable";
445 RefPtr<Runnable> NamedRunnable =
446 NS_NewRunnableFunction(expectedName, [] {});
447 ExpectRunnableName(NamedRunnable, expectedName);
448 }
449 }
450
TEST(ThreadUtils,NewCancelableRunnableFunction)451 TEST(ThreadUtils, NewCancelableRunnableFunction)
452 { TestRunnableFactory<CancelableRunnableFactory>(/*aNamed*/ false); }
453
TEST(ThreadUtils,NewNamedCancelableRunnableFunction)454 TEST(ThreadUtils, NewNamedCancelableRunnableFunction)
455 {
456 // The named overload shall behave identical to the non-named counterpart.
457 TestRunnableFactory<CancelableRunnableFactory>(/*aNamed*/ true);
458
459 // Test naming.
460 {
461 const char* expectedName = "NamedRunnable";
462 RefPtr<Runnable> NamedRunnable =
463 NS_NewCancelableRunnableFunction(expectedName, [] {});
464 ExpectRunnableName(NamedRunnable, expectedName);
465 }
466
467 // Test release on cancelation.
468 {
469 auto foo = MakeRefPtr<TestRefCounted>();
470 bool ran = false;
471
472 RefPtr<CancelableRunnable> func =
473 NS_NewCancelableRunnableFunction("unused", [foo, &ran] { ran = true; });
474
475 EXPECT_EQ(foo->refCount(), 2u);
476 func->Cancel();
477
478 EXPECT_EQ(foo->refCount(), 1u);
479 EXPECT_FALSE(ran);
480 }
481
482 // Test no-op after cancelation.
483 {
484 auto foo = MakeRefPtr<TestRefCounted>();
485 bool ran = false;
486
487 RefPtr<CancelableRunnable> func =
488 NS_NewCancelableRunnableFunction("unused", [foo, &ran] { ran = true; });
489
490 EXPECT_EQ(foo->refCount(), 2u);
491 func->Cancel();
492 func->Run();
493
494 EXPECT_FALSE(ran);
495 }
496 }
497
TestNewRunnableMethod(bool aNamed)498 static void TestNewRunnableMethod(bool aNamed) {
499 memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool));
500 // Scope the smart ptrs so that the runnables need to hold on to whatever they
501 // need
502 {
503 RefPtr<nsFoo> foo = new nsFoo();
504 RefPtr<nsBar> bar = new nsBar();
505 RefPtr<const nsBar> constBar = bar;
506
507 // This pointer will be freed at the end of the block
508 // Do not dereference this pointer in the runnable method!
509 RefPtr<nsFoo> rawFoo = new nsFoo();
510
511 // Read only string. Dereferencing in runnable method to check this works.
512 char* message = (char*)"Test message";
513
514 {
515 auto bar = MakeRefPtr<nsBar>();
516
517 NS_DispatchToMainThread(
518 aNamed ? NewRunnableMethod("unused", std::move(bar), &nsBar::DoBar1)
519 : NewRunnableMethod("nsBar::DoBar1", std::move(bar),
520 &nsBar::DoBar1));
521 }
522
523 NS_DispatchToMainThread(
524 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1)
525 : NewRunnableMethod("nsBar::DoBar1", bar, &nsBar::DoBar1));
526 NS_DispatchToMainThread(
527 aNamed ? NewRunnableMethod("unused", constBar, &nsBar::DoBar1Const)
528 : NewRunnableMethod("nsBar::DoBar1Const", constBar,
529 &nsBar::DoBar1Const));
530 NS_DispatchToMainThread(
531 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2)
532 : NewRunnableMethod("nsBar::DoBar2", bar, &nsBar::DoBar2));
533 NS_DispatchToMainThread(
534 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar3,
535 foo)
536 : NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar3", bar,
537 &nsBar::DoBar3, foo));
538 NS_DispatchToMainThread(
539 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar4,
540 foo)
541 : NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar4", bar,
542 &nsBar::DoBar4, foo));
543 NS_DispatchToMainThread(
544 aNamed
545 ? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5, rawFoo)
546 : NewRunnableMethod<nsFoo*>("nsBar::DoBar5", bar, &nsBar::DoBar5,
547 rawFoo));
548 NS_DispatchToMainThread(
549 aNamed
550 ? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6, message)
551 : NewRunnableMethod<char*>("nsBar::DoBar6", bar, &nsBar::DoBar6,
552 message));
553 #ifdef HAVE_STDCALL
554 NS_DispatchToMainThread(
555 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1std)
556 : NewRunnableMethod(bar, &nsBar::DoBar1std));
557 NS_DispatchToMainThread(
558 aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2std)
559 : NewRunnableMethod(bar, &nsBar::DoBar2std));
560 NS_DispatchToMainThread(
561 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
562 &nsBar::DoBar3std, foo)
563 : NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar3std, foo));
564 NS_DispatchToMainThread(
565 aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
566 &nsBar::DoBar4std, foo)
567 : NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar4std, foo));
568 NS_DispatchToMainThread(
569 aNamed ? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5std,
570 rawFoo)
571 : NewRunnableMethod<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo));
572 NS_DispatchToMainThread(
573 aNamed ? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6std,
574 message)
575 : NewRunnableMethod<char*>(bar, &nsBar::DoBar6std, message));
576 #endif
577 }
578
579 // Spin the event loop
580 NS_ProcessPendingEvents(nullptr);
581
582 // Now test a suicidal event in NS_New(Named)Thread
583 nsCOMPtr<nsIThread> thread;
584 NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide());
585 ASSERT_TRUE(thread);
586
587 while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) {
588 NS_ProcessPendingEvents(nullptr);
589 }
590
591 for (uint32_t i = 0; i < MAX_TESTS; i++) {
592 EXPECT_TRUE(gRunnableExecuted[i]) << "Error in test " << i;
593 }
594 }
595
TEST(ThreadUtils,RunnableMethod)596 TEST(ThreadUtils, RunnableMethod)
597 { TestNewRunnableMethod(/* aNamed */ false); }
598
TEST(ThreadUtils,NamedRunnableMethod)599 TEST(ThreadUtils, NamedRunnableMethod)
600 {
601 // The named overloads shall behave identical to the non-named counterparts.
602 TestNewRunnableMethod(/* aNamed */ true);
603
604 // Test naming.
605 {
606 RefPtr<nsFoo> foo = new nsFoo();
607 const char* expectedName = "NamedRunnable";
608 bool unused;
609 RefPtr<Runnable> NamedRunnable =
610 NewRunnableMethod<bool*>(expectedName, foo, &nsFoo::DoFoo, &unused);
611 ExpectRunnableName(NamedRunnable, expectedName);
612 }
613 }
614
615 class IdleObjectWithoutSetDeadline final {
616 public:
617 NS_INLINE_DECL_REFCOUNTING(IdleObjectWithoutSetDeadline)
IdleObjectWithoutSetDeadline()618 IdleObjectWithoutSetDeadline() : mRunnableExecuted(false) {}
Method()619 void Method() { mRunnableExecuted = true; }
620 bool mRunnableExecuted;
621
622 private:
623 ~IdleObjectWithoutSetDeadline() = default;
624 };
625
626 class IdleObjectParentWithSetDeadline {
627 public:
IdleObjectParentWithSetDeadline()628 IdleObjectParentWithSetDeadline() : mSetDeadlineCalled(false) {}
SetDeadline(TimeStamp aDeadline)629 void SetDeadline(TimeStamp aDeadline) { mSetDeadlineCalled = true; }
630 bool mSetDeadlineCalled;
631 };
632
633 class IdleObjectInheritedSetDeadline final
634 : public IdleObjectParentWithSetDeadline {
635 public:
636 NS_INLINE_DECL_REFCOUNTING(IdleObjectInheritedSetDeadline)
IdleObjectInheritedSetDeadline()637 IdleObjectInheritedSetDeadline() : mRunnableExecuted(false) {}
Method()638 void Method() { mRunnableExecuted = true; }
639 bool mRunnableExecuted;
640
641 private:
642 ~IdleObjectInheritedSetDeadline() = default;
643 };
644
645 class IdleObject final {
646 public:
647 NS_INLINE_DECL_REFCOUNTING(IdleObject)
IdleObject()648 IdleObject() {
649 for (uint32_t index = 0; index < ArrayLength(mRunnableExecuted); ++index) {
650 mRunnableExecuted[index] = false;
651 mSetIdleDeadlineCalled = false;
652 }
653 }
SetDeadline(TimeStamp aTimeStamp)654 void SetDeadline(TimeStamp aTimeStamp) { mSetIdleDeadlineCalled = true; }
655
CheckExecutedMethods(const char * aKey,uint32_t aNumExecuted)656 void CheckExecutedMethods(const char* aKey, uint32_t aNumExecuted) {
657 uint32_t index;
658 for (index = 0; index < aNumExecuted; ++index) {
659 ASSERT_TRUE(mRunnableExecuted[index])
660 << aKey << ": Method" << index << " should've executed";
661 }
662
663 for (; index < ArrayLength(mRunnableExecuted); ++index) {
664 ASSERT_FALSE(mRunnableExecuted[index])
665 << aKey << ": Method" << index << " shouldn't have executed";
666 }
667 }
668
Method0()669 void Method0() {
670 CheckExecutedMethods("Method0", 0);
671 mRunnableExecuted[0] = true;
672 mSetIdleDeadlineCalled = false;
673 }
674
Method1()675 void Method1() {
676 CheckExecutedMethods("Method1", 1);
677 ASSERT_TRUE(mSetIdleDeadlineCalled);
678 mRunnableExecuted[1] = true;
679 mSetIdleDeadlineCalled = false;
680 }
681
Method2()682 void Method2() {
683 CheckExecutedMethods("Method2", 2);
684 ASSERT_TRUE(mSetIdleDeadlineCalled);
685 mRunnableExecuted[2] = true;
686 mSetIdleDeadlineCalled = false;
687 NS_DispatchToCurrentThread(
688 NewRunnableMethod("IdleObject::Method3", this, &IdleObject::Method3));
689 }
690
Method3()691 void Method3() {
692 CheckExecutedMethods("Method3", 3);
693
694 NS_NewTimerWithFuncCallback(getter_AddRefs(mTimer), Method4, this, 10,
695 nsITimer::TYPE_ONE_SHOT, "IdleObject::Method3");
696 NS_DispatchToCurrentThreadQueue(
697 NewIdleRunnableMethodWithTimer("IdleObject::Method5", this,
698 &IdleObject::Method5),
699 50, EventQueuePriority::Idle);
700 NS_DispatchToCurrentThreadQueue(
701 NewRunnableMethod("IdleObject::Method6", this, &IdleObject::Method6),
702 100, EventQueuePriority::Idle);
703
704 PR_Sleep(PR_MillisecondsToInterval(200));
705 mRunnableExecuted[3] = true;
706 mSetIdleDeadlineCalled = false;
707 }
708
Method4(nsITimer * aTimer,void * aClosure)709 static void Method4(nsITimer* aTimer, void* aClosure) {
710 RefPtr<IdleObject> self = static_cast<IdleObject*>(aClosure);
711 self->CheckExecutedMethods("Method4", 4);
712 self->mRunnableExecuted[4] = true;
713 self->mSetIdleDeadlineCalled = false;
714 }
715
Method5()716 void Method5() {
717 CheckExecutedMethods("Method5", 5);
718 ASSERT_TRUE(mSetIdleDeadlineCalled);
719 mRunnableExecuted[5] = true;
720 mSetIdleDeadlineCalled = false;
721 }
722
Method6()723 void Method6() {
724 CheckExecutedMethods("Method6", 6);
725 mRunnableExecuted[6] = true;
726 mSetIdleDeadlineCalled = false;
727 }
728
Method7()729 void Method7() {
730 CheckExecutedMethods("Method7", 7);
731 ASSERT_TRUE(mSetIdleDeadlineCalled);
732 mRunnableExecuted[7] = true;
733 mSetIdleDeadlineCalled = false;
734 }
735
736 private:
737 nsCOMPtr<nsITimer> mTimer;
738 bool mRunnableExecuted[8];
739 bool mSetIdleDeadlineCalled;
740 ~IdleObject() = default;
741 };
742
TEST(ThreadUtils,IdleRunnableMethod)743 TEST(ThreadUtils, IdleRunnableMethod)
744 {
745 {
746 RefPtr<IdleObject> idle = new IdleObject();
747 RefPtr<IdleObjectWithoutSetDeadline> idleNoSetDeadline =
748 new IdleObjectWithoutSetDeadline();
749 RefPtr<IdleObjectInheritedSetDeadline> idleInheritedSetDeadline =
750 new IdleObjectInheritedSetDeadline();
751
752 NS_DispatchToCurrentThread(
753 NewRunnableMethod("IdleObject::Method0", idle, &IdleObject::Method0));
754 NS_DispatchToCurrentThreadQueue(
755 NewIdleRunnableMethod("IdleObject::Method1", idle,
756 &IdleObject::Method1),
757 EventQueuePriority::Idle);
758 NS_DispatchToCurrentThreadQueue(
759 NewIdleRunnableMethodWithTimer("IdleObject::Method2", idle,
760 &IdleObject::Method2),
761 60000, EventQueuePriority::Idle);
762 NS_DispatchToCurrentThreadQueue(
763 NewIdleRunnableMethod("IdleObject::Method7", idle,
764 &IdleObject::Method7),
765 EventQueuePriority::Idle);
766 NS_DispatchToCurrentThreadQueue(
767 NewIdleRunnableMethod<const char*, uint32_t>(
768 "IdleObject::CheckExecutedMethods", idle,
769 &IdleObject::CheckExecutedMethods, "final", 8),
770 EventQueuePriority::Idle);
771 NS_DispatchToCurrentThreadQueue(
772 NewIdleRunnableMethod("IdleObjectWithoutSetDeadline::Method",
773 idleNoSetDeadline,
774 &IdleObjectWithoutSetDeadline::Method),
775 EventQueuePriority::Idle);
776 NS_DispatchToCurrentThreadQueue(
777 NewIdleRunnableMethod("IdleObjectInheritedSetDeadline::Method",
778 idleInheritedSetDeadline,
779 &IdleObjectInheritedSetDeadline::Method),
780 EventQueuePriority::Idle);
781
782 NS_ProcessPendingEvents(nullptr);
783
784 ASSERT_TRUE(idleNoSetDeadline->mRunnableExecuted);
785 ASSERT_TRUE(idleInheritedSetDeadline->mRunnableExecuted);
786 ASSERT_TRUE(idleInheritedSetDeadline->mSetDeadlineCalled);
787 }
788 }
789
TEST(ThreadUtils,IdleTaskRunner)790 TEST(ThreadUtils, IdleTaskRunner)
791 {
792 using namespace mozilla;
793
794 // Repeating.
795 int cnt1 = 0;
796 RefPtr<IdleTaskRunner> runner1 = IdleTaskRunner::Create(
797 [&cnt1](TimeStamp) {
798 cnt1++;
799 return true;
800 },
801 "runner1", 0, 10, 3, true, nullptr);
802
803 // Non-repeating but callback always return false so it's still repeating.
804 int cnt2 = 0;
805 RefPtr<IdleTaskRunner> runner2 = IdleTaskRunner::Create(
806 [&cnt2](TimeStamp) {
807 cnt2++;
808 return false;
809 },
810 "runner2", 0, 10, 3, false, nullptr);
811
812 // Repeating until cnt3 >= 2 by returning 'true' in MayStopProcessing
813 // callback. The strategy is to stop repeating as early as possible so that we
814 // are more probable to catch the bug if it didn't stop as expected.
815 int cnt3 = 0;
816 RefPtr<IdleTaskRunner> runner3 = IdleTaskRunner::Create(
817 [&cnt3](TimeStamp) {
818 cnt3++;
819 return true;
820 },
821 "runner3", 0, 10, 3, true, [&cnt3] { return cnt3 >= 2; });
822
823 // Non-repeating can callback return true so the callback will
824 // be only run once.
825 int cnt4 = 0;
826 RefPtr<IdleTaskRunner> runner4 = IdleTaskRunner::Create(
827 [&cnt4](TimeStamp) {
828 cnt4++;
829 return true;
830 },
831 "runner4", 0, 10, 3, false, nullptr);
832
833 // Firstly we wait until the two repeating tasks reach their limits.
834 MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return cnt1 >= 100; }));
835 MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return cnt2 >= 100; }));
836
837 // At any point ==> 0 <= cnt3 <= 2 since MayStopProcessing() would return
838 // true when cnt3 >= 2.
839 MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() {
840 if (cnt3 > 2) {
841 EXPECT_TRUE(false) << "MaybeContinueProcess() doesn't work.";
842 return true; // Stop on failure.
843 }
844 return cnt3 == 2; // Stop finish if we have reached its max value.
845 }));
846
847 // At any point ==> 0 <= cnt4 <= 1 since this is a non-repeating
848 // idle runner.
849 MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() {
850 // At any point: 0 <= cnt4 <= 1
851 if (cnt4 > 1) {
852 EXPECT_TRUE(false) << "The 'mRepeating' flag doesn't work.";
853 return true; // Stop on failure.
854 }
855 return cnt4 == 1;
856 }));
857
858 // The repeating timers require an explicit Cancel() call.
859 runner1->Cancel();
860 runner2->Cancel();
861 }
862
863 // {9e70a320-be02-11d1-8031-006008159b5a}
864 #define NS_IFOO_IID \
865 { \
866 0x9e70a320, 0xbe02, 0x11d1, { \
867 0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a \
868 } \
869 }
870
TEST(ThreadUtils,TypeTraits)871 TEST(ThreadUtils, TypeTraits)
872 {
873 static_assert(!mozilla::IsRefcountedSmartPointer<int>::value,
874 "IsRefcountedSmartPointer<int> should be false");
875 static_assert(mozilla::IsRefcountedSmartPointer<RefPtr<int>>::value,
876 "IsRefcountedSmartPointer<RefPtr<...>> should be true");
877 static_assert(mozilla::IsRefcountedSmartPointer<const RefPtr<int>>::value,
878 "IsRefcountedSmartPointer<const RefPtr<...>> should be true");
879 static_assert(
880 mozilla::IsRefcountedSmartPointer<volatile RefPtr<int>>::value,
881 "IsRefcountedSmartPointer<volatile RefPtr<...>> should be true");
882 static_assert(
883 mozilla::IsRefcountedSmartPointer<const volatile RefPtr<int>>::value,
884 "IsRefcountedSmartPointer<const volatile RefPtr<...>> should be true");
885 static_assert(mozilla::IsRefcountedSmartPointer<nsCOMPtr<int>>::value,
886 "IsRefcountedSmartPointer<nsCOMPtr<...>> should be true");
887 static_assert(mozilla::IsRefcountedSmartPointer<const nsCOMPtr<int>>::value,
888 "IsRefcountedSmartPointer<const nsCOMPtr<...>> should be true");
889 static_assert(
890 mozilla::IsRefcountedSmartPointer<volatile nsCOMPtr<int>>::value,
891 "IsRefcountedSmartPointer<volatile nsCOMPtr<...>> should be true");
892 static_assert(
893 mozilla::IsRefcountedSmartPointer<const volatile nsCOMPtr<int>>::value,
894 "IsRefcountedSmartPointer<const volatile nsCOMPtr<...>> should be true");
895
896 static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>::Type>,
897 "RemoveSmartPointer<int>::Type should be int");
898 static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>::Type>,
899 "RemoveSmartPointer<int*>::Type should be int*");
900 static_assert(
901 std::is_same_v<UniquePtr<int>,
902 mozilla::RemoveSmartPointer<UniquePtr<int>>::Type>,
903 "RemoveSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>");
904 static_assert(
905 std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>::Type>,
906 "RemoveSmartPointer<RefPtr<int>>::Type should be int");
907 static_assert(
908 std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>::Type>,
909 "RemoveSmartPointer<const RefPtr<int>>::Type should be int");
910 static_assert(
911 std::is_same_v<int,
912 mozilla::RemoveSmartPointer<volatile RefPtr<int>>::Type>,
913 "RemoveSmartPointer<volatile RefPtr<int>>::Type should be int");
914 static_assert(
915 std::is_same_v<
916 int, mozilla::RemoveSmartPointer<const volatile RefPtr<int>>::Type>,
917 "RemoveSmartPointer<const volatile RefPtr<int>>::Type should be int");
918 static_assert(
919 std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>::Type>,
920 "RemoveSmartPointer<nsCOMPtr<int>>::Type should be int");
921 static_assert(
922 std::is_same_v<int,
923 mozilla::RemoveSmartPointer<const nsCOMPtr<int>>::Type>,
924 "RemoveSmartPointer<const nsCOMPtr<int>>::Type should be int");
925 static_assert(
926 std::is_same_v<int,
927 mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>::Type>,
928 "RemoveSmartPointer<volatile nsCOMPtr<int>>::Type should be int");
929 static_assert(
930 std::is_same_v<
931 int, mozilla::RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type>,
932 "RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type should be int");
933
934 static_assert(
935 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>::Type>,
936 "RemoveRawOrSmartPointer<int>::Type should be int");
937 static_assert(
938 std::is_same_v<UniquePtr<int>,
939 mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>::Type>,
940 "RemoveRawOrSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>");
941 static_assert(
942 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>::Type>,
943 "RemoveRawOrSmartPointer<int*>::Type should be int");
944 static_assert(
945 std::is_same_v<const int,
946 mozilla::RemoveRawOrSmartPointer<const int*>::Type>,
947 "RemoveRawOrSmartPointer<const int*>::Type should be const int");
948 static_assert(
949 std::is_same_v<volatile int,
950 mozilla::RemoveRawOrSmartPointer<volatile int*>::Type>,
951 "RemoveRawOrSmartPointer<volatile int*>::Type should be volatile int");
952 static_assert(
953 std::is_same_v<const volatile int, mozilla::RemoveRawOrSmartPointer<
954 const volatile int*>::Type>,
955 "RemoveRawOrSmartPointer<const volatile int*>::Type should be const "
956 "volatile int");
957 static_assert(
958 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>::Type>,
959 "RemoveRawOrSmartPointer<RefPtr<int>>::Type should be int");
960 static_assert(
961 std::is_same_v<int,
962 mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>::Type>,
963 "RemoveRawOrSmartPointer<const RefPtr<int>>::Type should be int");
964 static_assert(
965 std::is_same_v<
966 int, mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type>,
967 "RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type should be int");
968 static_assert(
969 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<
970 const volatile RefPtr<int>>::Type>,
971 "RemoveRawOrSmartPointer<const volatile RefPtr<int>>::Type should be "
972 "int");
973 static_assert(
974 std::is_same_v<int,
975 mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type>,
976 "RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type should be int");
977 static_assert(
978 std::is_same_v<
979 int, mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type>,
980 "RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type should be int");
981 static_assert(
982 std::is_same_v<
983 int, mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type>,
984 "RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type should be int");
985 static_assert(
986 std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<
987 const volatile nsCOMPtr<int>>::Type>,
988 "RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>>::Type should be "
989 "int");
990 }
991
992 namespace TestThreadUtils {
993
994 static bool gDebug = false;
995 static int gAlive, gZombies;
996 static int gAllConstructions, gConstructions, gCopyConstructions,
997 gMoveConstructions, gDestructions, gAssignments, gMoves;
998 struct Spy {
ClearActionsTestThreadUtils::Spy999 static void ClearActions() {
1000 gAllConstructions = gConstructions = gCopyConstructions =
1001 gMoveConstructions = gDestructions = gAssignments = gMoves = 0;
1002 }
ClearAllTestThreadUtils::Spy1003 static void ClearAll() {
1004 ClearActions();
1005 gAlive = 0;
1006 }
1007
SpyTestThreadUtils::Spy1008 explicit Spy(int aID) : mID(aID) {
1009 ++gAlive;
1010 ++gAllConstructions;
1011 ++gConstructions;
1012 if (gDebug) {
1013 printf("Spy[%d@%p]()\n", mID, this);
1014 }
1015 }
SpyTestThreadUtils::Spy1016 Spy(const Spy& o) : mID(o.mID) {
1017 ++gAlive;
1018 ++gAllConstructions;
1019 ++gCopyConstructions;
1020 if (gDebug) {
1021 printf("Spy[%d@%p](&[%d@%p])\n", mID, this, o.mID, &o);
1022 }
1023 }
SpyTestThreadUtils::Spy1024 Spy(Spy&& o) : mID(o.mID) {
1025 o.mID = -o.mID;
1026 ++gZombies;
1027 ++gAllConstructions;
1028 ++gMoveConstructions;
1029 if (gDebug) {
1030 printf("Spy[%d@%p](&&[%d->%d@%p])\n", mID, this, -o.mID, o.mID, &o);
1031 }
1032 }
~SpyTestThreadUtils::Spy1033 ~Spy() {
1034 if (mID >= 0) {
1035 --gAlive;
1036 } else {
1037 --gZombies;
1038 }
1039 ++gDestructions;
1040 if (gDebug) {
1041 printf("~Spy[%d@%p]()\n", mID, this);
1042 }
1043 mID = 0;
1044 }
operator =TestThreadUtils::Spy1045 Spy& operator=(const Spy& o) {
1046 ++gAssignments;
1047 if (gDebug) {
1048 printf("Spy[%d->%d@%p] = &[%d@%p]\n", mID, o.mID, this, o.mID, &o);
1049 }
1050 mID = o.mID;
1051 return *this;
1052 };
operator =TestThreadUtils::Spy1053 Spy& operator=(Spy&& o) {
1054 --gAlive;
1055 ++gZombies;
1056 ++gMoves;
1057 if (gDebug) {
1058 printf("Spy[%d->%d@%p] = &&[%d->%d@%p]\n", mID, o.mID, this, o.mID,
1059 -o.mID, &o);
1060 }
1061 mID = o.mID;
1062 o.mID = -o.mID;
1063 return *this;
1064 };
1065
1066 int mID; // ID given at construction, or negation if was moved from; 0 when
1067 // destroyed.
1068 };
1069
1070 struct ISpyWithISupports : public nsISupports {
1071 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
1072 NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
1073 NS_IMETHOD_(int32_t) ID() = 0;
1074 };
1075 NS_DEFINE_STATIC_IID_ACCESSOR(ISpyWithISupports, NS_IFOO_IID)
1076 struct SpyWithISupports : public ISpyWithISupports, public Spy {
1077 private:
1078 virtual ~SpyWithISupports() = default;
1079
1080 public:
SpyWithISupportsTestThreadUtils::SpyWithISupports1081 explicit SpyWithISupports(int aID) : Spy(aID){};
1082 NS_DECL_ISUPPORTS
NS_IMETHOD_TestThreadUtils::SpyWithISupports1083 NS_IMETHOD_(nsrefcnt) RefCnt() override { return mRefCnt; }
IDTestThreadUtils::SpyWithISupports1084 NS_IMETHOD_(int32_t) ID() override { return mID; }
1085 };
1086 NS_IMPL_ISUPPORTS(SpyWithISupports, ISpyWithISupports)
1087
1088 class IThreadUtilsObject : public nsISupports {
1089 public:
1090 NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
1091
1092 NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
1093 NS_IMETHOD_(int32_t) ID() = 0;
1094 };
1095
1096 NS_DEFINE_STATIC_IID_ACCESSOR(IThreadUtilsObject, NS_IFOO_IID)
1097
1098 struct ThreadUtilsObjectNonRefCountedBase {
MethodFromNonRefCountedBaseTestThreadUtils::ThreadUtilsObjectNonRefCountedBase1099 virtual void MethodFromNonRefCountedBase() {}
1100 };
1101
1102 struct ThreadUtilsObject : public IThreadUtilsObject,
1103 public ThreadUtilsObjectNonRefCountedBase {
1104 // nsISupports implementation
1105 NS_DECL_ISUPPORTS
1106
1107 // IThreadUtilsObject implementation
NS_IMETHOD_TestThreadUtils::ThreadUtilsObject1108 NS_IMETHOD_(nsrefcnt) RefCnt() override { return mRefCnt; }
IDTestThreadUtils::ThreadUtilsObject1109 NS_IMETHOD_(int32_t) ID() override { return 0; }
1110
1111 int mCount; // Number of calls + arguments processed.
1112 int mA0, mA1, mA2, mA3;
1113 Spy mSpy;
1114 const Spy* mSpyPtr;
ThreadUtilsObjectTestThreadUtils::ThreadUtilsObject1115 ThreadUtilsObject()
1116 : mCount(0), mA0(0), mA1(0), mA2(0), mA3(0), mSpy(1), mSpyPtr(nullptr) {}
1117
1118 private:
1119 virtual ~ThreadUtilsObject() = default;
1120
1121 public:
Test0TestThreadUtils::ThreadUtilsObject1122 void Test0() { mCount += 1; }
Test1iTestThreadUtils::ThreadUtilsObject1123 void Test1i(int a0) {
1124 mCount += 2;
1125 mA0 = a0;
1126 }
Test2iTestThreadUtils::ThreadUtilsObject1127 void Test2i(int a0, int a1) {
1128 mCount += 3;
1129 mA0 = a0;
1130 mA1 = a1;
1131 }
Test3iTestThreadUtils::ThreadUtilsObject1132 void Test3i(int a0, int a1, int a2) {
1133 mCount += 4;
1134 mA0 = a0;
1135 mA1 = a1;
1136 mA2 = a2;
1137 }
Test4iTestThreadUtils::ThreadUtilsObject1138 void Test4i(int a0, int a1, int a2, int a3) {
1139 mCount += 5;
1140 mA0 = a0;
1141 mA1 = a1;
1142 mA2 = a2;
1143 mA3 = a3;
1144 }
Test1piTestThreadUtils::ThreadUtilsObject1145 void Test1pi(int* ap) {
1146 mCount += 2;
1147 mA0 = ap ? *ap : -1;
1148 }
Test1pciTestThreadUtils::ThreadUtilsObject1149 void Test1pci(const int* ap) {
1150 mCount += 2;
1151 mA0 = ap ? *ap : -1;
1152 }
Test1riTestThreadUtils::ThreadUtilsObject1153 void Test1ri(int& ar) {
1154 mCount += 2;
1155 mA0 = ar;
1156 }
Test1rriTestThreadUtils::ThreadUtilsObject1157 void Test1rri(int&& arr) {
1158 mCount += 2;
1159 mA0 = arr;
1160 }
Test1upiTestThreadUtils::ThreadUtilsObject1161 void Test1upi(mozilla::UniquePtr<int> aup) {
1162 mCount += 2;
1163 mA0 = aup ? *aup : -1;
1164 }
Test1rupiTestThreadUtils::ThreadUtilsObject1165 void Test1rupi(mozilla::UniquePtr<int>& aup) {
1166 mCount += 2;
1167 mA0 = aup ? *aup : -1;
1168 }
Test1rrupiTestThreadUtils::ThreadUtilsObject1169 void Test1rrupi(mozilla::UniquePtr<int>&& aup) {
1170 mCount += 2;
1171 mA0 = aup ? *aup : -1;
1172 }
1173
Test1sTestThreadUtils::ThreadUtilsObject1174 void Test1s(Spy) { mCount += 2; }
Test1psTestThreadUtils::ThreadUtilsObject1175 void Test1ps(Spy*) { mCount += 2; }
Test1rsTestThreadUtils::ThreadUtilsObject1176 void Test1rs(Spy&) { mCount += 2; }
Test1rrsTestThreadUtils::ThreadUtilsObject1177 void Test1rrs(Spy&&) { mCount += 2; }
Test1upsTestThreadUtils::ThreadUtilsObject1178 void Test1ups(mozilla::UniquePtr<Spy>) { mCount += 2; }
Test1rupsTestThreadUtils::ThreadUtilsObject1179 void Test1rups(mozilla::UniquePtr<Spy>&) { mCount += 2; }
Test1rrupsTestThreadUtils::ThreadUtilsObject1180 void Test1rrups(mozilla::UniquePtr<Spy>&&) { mCount += 2; }
1181
1182 // Possible parameter passing styles:
TestByValueTestThreadUtils::ThreadUtilsObject1183 void TestByValue(Spy s) {
1184 if (gDebug) {
1185 printf("TestByValue(Spy[%d@%p])\n", s.mID, &s);
1186 }
1187 mSpy = s;
1188 };
TestByConstLRefTestThreadUtils::ThreadUtilsObject1189 void TestByConstLRef(const Spy& s) {
1190 if (gDebug) {
1191 printf("TestByConstLRef(Spy[%d@%p]&)\n", s.mID, &s);
1192 }
1193 mSpy = s;
1194 };
TestByRRefTestThreadUtils::ThreadUtilsObject1195 void TestByRRef(Spy&& s) {
1196 if (gDebug) {
1197 printf("TestByRRef(Spy[%d@%p]&&)\n", s.mID, &s);
1198 }
1199 mSpy = std::move(s);
1200 };
TestByLRefTestThreadUtils::ThreadUtilsObject1201 void TestByLRef(Spy& s) {
1202 if (gDebug) {
1203 printf("TestByLRef(Spy[%d@%p]&)\n", s.mID, &s);
1204 }
1205 mSpy = s;
1206 mSpyPtr = &s;
1207 };
TestByPointerTestThreadUtils::ThreadUtilsObject1208 void TestByPointer(Spy* p) {
1209 if (p) {
1210 if (gDebug) {
1211 printf("TestByPointer(&Spy[%d@%p])\n", p->mID, p);
1212 }
1213 mSpy = *p;
1214 } else {
1215 if (gDebug) {
1216 printf("TestByPointer(nullptr)\n");
1217 }
1218 }
1219 mSpyPtr = p;
1220 };
TestByPointerToConstTestThreadUtils::ThreadUtilsObject1221 void TestByPointerToConst(const Spy* p) {
1222 if (p) {
1223 if (gDebug) {
1224 printf("TestByPointerToConst(&Spy[%d@%p])\n", p->mID, p);
1225 }
1226 mSpy = *p;
1227 } else {
1228 if (gDebug) {
1229 printf("TestByPointerToConst(nullptr)\n");
1230 }
1231 }
1232 mSpyPtr = p;
1233 };
1234 };
1235
1236 NS_IMPL_ISUPPORTS(ThreadUtilsObject, IThreadUtilsObject)
1237
1238 class ThreadUtilsRefCountedFinal final {
1239 public:
ThreadUtilsRefCountedFinal()1240 ThreadUtilsRefCountedFinal() : m_refCount(0) {}
1241 ~ThreadUtilsRefCountedFinal() = default;
1242 // 'AddRef' and 'Release' methods with different return types, to verify
1243 // that the return type doesn't influence storage selection.
AddRef(void)1244 long AddRef(void) { return ++m_refCount; }
Release(void)1245 void Release(void) { --m_refCount; }
1246
1247 private:
1248 long m_refCount;
1249 };
1250
1251 class ThreadUtilsRefCountedBase {
1252 public:
ThreadUtilsRefCountedBase()1253 ThreadUtilsRefCountedBase() : m_refCount(0) {}
1254 virtual ~ThreadUtilsRefCountedBase() = default;
1255 // 'AddRef' and 'Release' methods with different return types, to verify
1256 // that the return type doesn't influence storage selection.
AddRef(void)1257 virtual void AddRef(void) { ++m_refCount; }
Release(void)1258 virtual MozExternalRefCountType Release(void) { return --m_refCount; }
1259
1260 private:
1261 MozExternalRefCountType m_refCount;
1262 };
1263
1264 class ThreadUtilsRefCountedDerived : public ThreadUtilsRefCountedBase {};
1265
1266 class ThreadUtilsNonRefCounted {};
1267
1268 } // namespace TestThreadUtils
1269
TEST(ThreadUtils,main)1270 TEST(ThreadUtils, main)
1271 {
1272 using namespace TestThreadUtils;
1273
1274 static_assert(!IsParameterStorageClass<int>::value,
1275 "'int' should not be recognized as Storage Class");
1276 static_assert(
1277 IsParameterStorageClass<StoreCopyPassByValue<int>>::value,
1278 "StoreCopyPassByValue<int> should be recognized as Storage Class");
1279 static_assert(
1280 IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value,
1281 "StoreCopyPassByConstLRef<int> should be recognized as Storage Class");
1282 static_assert(
1283 IsParameterStorageClass<StoreCopyPassByLRef<int>>::value,
1284 "StoreCopyPassByLRef<int> should be recognized as Storage Class");
1285 static_assert(
1286 IsParameterStorageClass<StoreCopyPassByRRef<int>>::value,
1287 "StoreCopyPassByRRef<int> should be recognized as Storage Class");
1288 static_assert(
1289 IsParameterStorageClass<StoreRefPassByLRef<int>>::value,
1290 "StoreRefPassByLRef<int> should be recognized as Storage Class");
1291 static_assert(
1292 IsParameterStorageClass<StoreConstRefPassByConstLRef<int>>::value,
1293 "StoreConstRefPassByConstLRef<int> should be recognized as Storage "
1294 "Class");
1295 static_assert(
1296 IsParameterStorageClass<StoreRefPtrPassByPtr<int>>::value,
1297 "StoreRefPtrPassByPtr<int> should be recognized as Storage Class");
1298 static_assert(IsParameterStorageClass<StorePtrPassByPtr<int>>::value,
1299 "StorePtrPassByPtr<int> should be recognized as Storage Class");
1300 static_assert(
1301 IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value,
1302 "StoreConstPtrPassByConstPtr<int> should be recognized as Storage Class");
1303 static_assert(
1304 IsParameterStorageClass<StoreCopyPassByConstPtr<int>>::value,
1305 "StoreCopyPassByConstPtr<int> should be recognized as Storage Class");
1306 static_assert(
1307 IsParameterStorageClass<StoreCopyPassByPtr<int>>::value,
1308 "StoreCopyPassByPtr<int> should be recognized as Storage Class");
1309
1310 RefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject);
1311 int count = 0;
1312
1313 // Test legacy functions.
1314
1315 nsCOMPtr<nsIRunnable> r1 =
1316 NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt,
1317 &ThreadUtilsObject::Test0);
1318 r1->Run();
1319 EXPECT_EQ(count += 1, rpt->mCount);
1320
1321 r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1322 &ThreadUtilsObject::Test1i, 11);
1323 r1->Run();
1324 EXPECT_EQ(count += 2, rpt->mCount);
1325 EXPECT_EQ(11, rpt->mA0);
1326
1327 // Test calling a method from a non-ref-counted base.
1328
1329 r1 = NewRunnableMethod(
1330 "TestThreadUtils::ThreadUtilsObjectNonRefCountedBase::"
1331 "MethodFromNonRefCountedBase",
1332 rpt, &ThreadUtilsObject::MethodFromNonRefCountedBase);
1333 r1->Run();
1334 EXPECT_EQ(count, rpt->mCount);
1335
1336 // Test variadic function with simple POD arguments.
1337
1338 r1 = NewRunnableMethod("TestThreadUtils::ThreadUtilsObject::Test0", rpt,
1339 &ThreadUtilsObject::Test0);
1340 r1->Run();
1341 EXPECT_EQ(count += 1, rpt->mCount);
1342
1343 static_assert(std::is_same_v<::detail::ParameterStorage<int>::Type,
1344 StoreCopyPassByConstLRef<int>>,
1345 "detail::ParameterStorage<int>::Type should be "
1346 "StoreCopyPassByConstLRef<int>");
1347 static_assert(std::is_same_v<
1348 ::detail::ParameterStorage<StoreCopyPassByValue<int>>::Type,
1349 StoreCopyPassByValue<int>>,
1350 "detail::ParameterStorage<StoreCopyPassByValue<int>>::Type "
1351 "should be StoreCopyPassByValue<int>");
1352
1353 r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1354 &ThreadUtilsObject::Test1i, 12);
1355 r1->Run();
1356 EXPECT_EQ(count += 2, rpt->mCount);
1357 EXPECT_EQ(12, rpt->mA0);
1358
1359 r1 = NewRunnableMethod<int, int>("TestThreadUtils::ThreadUtilsObject::Test2i",
1360 rpt, &ThreadUtilsObject::Test2i, 21, 22);
1361 r1->Run();
1362 EXPECT_EQ(count += 3, rpt->mCount);
1363 EXPECT_EQ(21, rpt->mA0);
1364 EXPECT_EQ(22, rpt->mA1);
1365
1366 r1 = NewRunnableMethod<int, int, int>(
1367 "TestThreadUtils::ThreadUtilsObject::Test3i", rpt,
1368 &ThreadUtilsObject::Test3i, 31, 32, 33);
1369 r1->Run();
1370 EXPECT_EQ(count += 4, rpt->mCount);
1371 EXPECT_EQ(31, rpt->mA0);
1372 EXPECT_EQ(32, rpt->mA1);
1373 EXPECT_EQ(33, rpt->mA2);
1374
1375 r1 = NewRunnableMethod<int, int, int, int>(
1376 "TestThreadUtils::ThreadUtilsObject::Test4i", rpt,
1377 &ThreadUtilsObject::Test4i, 41, 42, 43, 44);
1378 r1->Run();
1379 EXPECT_EQ(count += 5, rpt->mCount);
1380 EXPECT_EQ(41, rpt->mA0);
1381 EXPECT_EQ(42, rpt->mA1);
1382 EXPECT_EQ(43, rpt->mA2);
1383 EXPECT_EQ(44, rpt->mA3);
1384
1385 // More interesting types of arguments.
1386
1387 // Passing a short to make sure forwarding works with an inexact type match.
1388 short int si = 11;
1389 r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
1390 &ThreadUtilsObject::Test1i, si);
1391 r1->Run();
1392 EXPECT_EQ(count += 2, rpt->mCount);
1393 EXPECT_EQ(si, rpt->mA0);
1394
1395 // Raw pointer, possible cv-qualified.
1396 static_assert(
1397 std::is_same_v<::detail::ParameterStorage<int*>::Type,
1398 StorePtrPassByPtr<int>>,
1399 "detail::ParameterStorage<int*>::Type should be StorePtrPassByPtr<int>");
1400 static_assert(std::is_same_v<::detail::ParameterStorage<int* const>::Type,
1401 StorePtrPassByPtr<int>>,
1402 "detail::ParameterStorage<int* const>::Type should be "
1403 "StorePtrPassByPtr<int>");
1404 static_assert(std::is_same_v<::detail::ParameterStorage<int* volatile>::Type,
1405 StorePtrPassByPtr<int>>,
1406 "detail::ParameterStorage<int* volatile>::Type should be "
1407 "StorePtrPassByPtr<int>");
1408 static_assert(
1409 std::is_same_v<::detail::ParameterStorage<int* const volatile>::Type,
1410 StorePtrPassByPtr<int>>,
1411 "detail::ParameterStorage<int* const volatile>::Type should be "
1412 "StorePtrPassByPtr<int>");
1413 static_assert(
1414 std::is_same_v<::detail::ParameterStorage<int*>::Type::stored_type, int*>,
1415 "detail::ParameterStorage<int*>::Type::stored_type should be int*");
1416 static_assert(
1417 std::is_same_v<::detail::ParameterStorage<int*>::Type::passed_type, int*>,
1418 "detail::ParameterStorage<int*>::Type::passed_type should be int*");
1419 {
1420 int i = 12;
1421 r1 = NewRunnableMethod<int*>("TestThreadUtils::ThreadUtilsObject::Test1pi",
1422 rpt, &ThreadUtilsObject::Test1pi, &i);
1423 r1->Run();
1424 EXPECT_EQ(count += 2, rpt->mCount);
1425 EXPECT_EQ(i, rpt->mA0);
1426 }
1427
1428 // Raw pointer to const.
1429 static_assert(std::is_same_v<::detail::ParameterStorage<const int*>::Type,
1430 StoreConstPtrPassByConstPtr<int>>,
1431 "detail::ParameterStorage<const int*>::Type should be "
1432 "StoreConstPtrPassByConstPtr<int>");
1433 static_assert(
1434 std::is_same_v<::detail::ParameterStorage<const int* const>::Type,
1435 StoreConstPtrPassByConstPtr<int>>,
1436 "detail::ParameterStorage<const int* const>::Type should be "
1437 "StoreConstPtrPassByConstPtr<int>");
1438 static_assert(
1439 std::is_same_v<::detail::ParameterStorage<const int* volatile>::Type,
1440 StoreConstPtrPassByConstPtr<int>>,
1441 "detail::ParameterStorage<const int* volatile>::Type should be "
1442 "StoreConstPtrPassByConstPtr<int>");
1443 static_assert(std::is_same_v<
1444 ::detail::ParameterStorage<const int* const volatile>::Type,
1445 StoreConstPtrPassByConstPtr<int>>,
1446 "detail::ParameterStorage<const int* const volatile>::Type "
1447 "should be StoreConstPtrPassByConstPtr<int>");
1448 static_assert(
1449 std::is_same_v<::detail::ParameterStorage<const int*>::Type::stored_type,
1450 const int*>,
1451 "detail::ParameterStorage<const int*>::Type::stored_type should be const "
1452 "int*");
1453 static_assert(
1454 std::is_same_v<::detail::ParameterStorage<const int*>::Type::passed_type,
1455 const int*>,
1456 "detail::ParameterStorage<const int*>::Type::passed_type should be const "
1457 "int*");
1458 {
1459 int i = 1201;
1460 r1 = NewRunnableMethod<const int*>(
1461 "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt,
1462 &ThreadUtilsObject::Test1pci, &i);
1463 r1->Run();
1464 EXPECT_EQ(count += 2, rpt->mCount);
1465 EXPECT_EQ(i, rpt->mA0);
1466 }
1467
1468 // Raw pointer to copy.
1469 static_assert(std::is_same_v<StoreCopyPassByPtr<int>::stored_type, int>,
1470 "StoreCopyPassByPtr<int>::stored_type should be int");
1471 static_assert(std::is_same_v<StoreCopyPassByPtr<int>::passed_type, int*>,
1472 "StoreCopyPassByPtr<int>::passed_type should be int*");
1473 {
1474 int i = 1202;
1475 r1 = NewRunnableMethod<StoreCopyPassByPtr<int>>(
1476 "TestThreadUtils::ThreadUtilsObject::Test1pi", rpt,
1477 &ThreadUtilsObject::Test1pi, i);
1478 r1->Run();
1479 EXPECT_EQ(count += 2, rpt->mCount);
1480 EXPECT_EQ(i, rpt->mA0);
1481 }
1482
1483 // Raw pointer to const copy.
1484 static_assert(std::is_same_v<StoreCopyPassByConstPtr<int>::stored_type, int>,
1485 "StoreCopyPassByConstPtr<int>::stored_type should be int");
1486 static_assert(
1487 std::is_same_v<StoreCopyPassByConstPtr<int>::passed_type, const int*>,
1488 "StoreCopyPassByConstPtr<int>::passed_type should be const int*");
1489 {
1490 int i = 1203;
1491 r1 = NewRunnableMethod<StoreCopyPassByConstPtr<int>>(
1492 "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt,
1493 &ThreadUtilsObject::Test1pci, i);
1494 r1->Run();
1495 EXPECT_EQ(count += 2, rpt->mCount);
1496 EXPECT_EQ(i, rpt->mA0);
1497 }
1498
1499 // nsRefPtr to pointer.
1500 static_assert(
1501 std::is_same_v<::detail::ParameterStorage<
1502 StoreRefPtrPassByPtr<SpyWithISupports>>::Type,
1503 StoreRefPtrPassByPtr<SpyWithISupports>>,
1504 "ParameterStorage<StoreRefPtrPassByPtr<SpyWithISupports>>::Type should "
1505 "be StoreRefPtrPassByPtr<SpyWithISupports>");
1506 static_assert(
1507 std::is_same_v<::detail::ParameterStorage<SpyWithISupports*>::Type,
1508 StoreRefPtrPassByPtr<SpyWithISupports>>,
1509 "ParameterStorage<SpyWithISupports*>::Type should be "
1510 "StoreRefPtrPassByPtr<SpyWithISupports>");
1511 static_assert(
1512 std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::stored_type,
1513 RefPtr<SpyWithISupports>>,
1514 "StoreRefPtrPassByPtr<SpyWithISupports>::stored_type should be "
1515 "RefPtr<SpyWithISupports>");
1516 static_assert(
1517 std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::passed_type,
1518 SpyWithISupports*>,
1519 "StoreRefPtrPassByPtr<SpyWithISupports>::passed_type should be "
1520 "SpyWithISupports*");
1521 // (more nsRefPtr tests below)
1522
1523 // nsRefPtr for ref-countable classes that do not derive from ISupports.
1524 static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>::value,
1525 "ThreadUtilsRefCountedFinal has AddRef() and Release()");
1526 static_assert(
1527 std::is_same_v<
1528 ::detail::ParameterStorage<ThreadUtilsRefCountedFinal*>::Type,
1529 StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>>,
1530 "ParameterStorage<ThreadUtilsRefCountedFinal*>::Type should be "
1531 "StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>");
1532 static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>::value,
1533 "ThreadUtilsRefCountedBase has AddRef() and Release()");
1534 static_assert(
1535 std::is_same_v<
1536 ::detail::ParameterStorage<ThreadUtilsRefCountedBase*>::Type,
1537 StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>>,
1538 "ParameterStorage<ThreadUtilsRefCountedBase*>::Type should be "
1539 "StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>");
1540 static_assert(
1541 ::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>::value,
1542 "ThreadUtilsRefCountedDerived has AddRef() and Release()");
1543 static_assert(
1544 std::is_same_v<
1545 ::detail::ParameterStorage<ThreadUtilsRefCountedDerived*>::Type,
1546 StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>>,
1547 "ParameterStorage<ThreadUtilsRefCountedDerived*>::Type should be "
1548 "StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>");
1549
1550 static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>::value,
1551 "ThreadUtilsNonRefCounted doesn't have AddRef() and Release()");
1552 static_assert(!std::is_same_v<
1553 ::detail::ParameterStorage<ThreadUtilsNonRefCounted*>::Type,
1554 StoreRefPtrPassByPtr<ThreadUtilsNonRefCounted>>,
1555 "ParameterStorage<ThreadUtilsNonRefCounted*>::Type should NOT "
1556 "be StoreRefPtrPassByPtr<ThreadUtilsNonRefCounted>");
1557
1558 // Lvalue reference.
1559 static_assert(
1560 std::is_same_v<::detail::ParameterStorage<int&>::Type,
1561 StoreRefPassByLRef<int>>,
1562 "ParameterStorage<int&>::Type should be StoreRefPassByLRef<int>");
1563 static_assert(
1564 std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type,
1565 StoreRefPassByLRef<int>::stored_type>,
1566 "ParameterStorage<int&>::Type::stored_type should be "
1567 "StoreRefPassByLRef<int>::stored_type");
1568 static_assert(
1569 std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type, int&>,
1570 "ParameterStorage<int&>::Type::stored_type should be int&");
1571 static_assert(
1572 std::is_same_v<::detail::ParameterStorage<int&>::Type::passed_type, int&>,
1573 "ParameterStorage<int&>::Type::passed_type should be int&");
1574 {
1575 int i = 13;
1576 r1 = NewRunnableMethod<int&>("TestThreadUtils::ThreadUtilsObject::Test1ri",
1577 rpt, &ThreadUtilsObject::Test1ri, i);
1578 r1->Run();
1579 EXPECT_EQ(count += 2, rpt->mCount);
1580 EXPECT_EQ(i, rpt->mA0);
1581 }
1582
1583 // Rvalue reference -- Actually storing a copy and then moving it.
1584 static_assert(
1585 std::is_same_v<::detail::ParameterStorage<int&&>::Type,
1586 StoreCopyPassByRRef<int>>,
1587 "ParameterStorage<int&&>::Type should be StoreCopyPassByRRef<int>");
1588 static_assert(
1589 std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type,
1590 StoreCopyPassByRRef<int>::stored_type>,
1591 "ParameterStorage<int&&>::Type::stored_type should be "
1592 "StoreCopyPassByRRef<int>::stored_type");
1593 static_assert(
1594 std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type, int>,
1595 "ParameterStorage<int&&>::Type::stored_type should be int");
1596 static_assert(
1597 std::is_same_v<::detail::ParameterStorage<int&&>::Type::passed_type,
1598 int&&>,
1599 "ParameterStorage<int&&>::Type::passed_type should be int&&");
1600 {
1601 int i = 14;
1602 r1 = NewRunnableMethod<int&&>(
1603 "TestThreadUtils::ThreadUtilsObject::Test1rri", rpt,
1604 &ThreadUtilsObject::Test1rri, std::move(i));
1605 }
1606 r1->Run();
1607 EXPECT_EQ(count += 2, rpt->mCount);
1608 EXPECT_EQ(14, rpt->mA0);
1609
1610 // Null unique pointer, by semi-implicit store&move with "T&&" syntax.
1611 static_assert(std::is_same_v<
1612 ::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type,
1613 StoreCopyPassByRRef<mozilla::UniquePtr<int>>>,
1614 "ParameterStorage<UniquePtr<int>&&>::Type should be "
1615 "StoreCopyPassByRRef<UniquePtr<int>>");
1616 static_assert(
1617 std::is_same_v<::detail::ParameterStorage<
1618 mozilla::UniquePtr<int>&&>::Type::stored_type,
1619 StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1620 "ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be "
1621 "StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1622 static_assert(
1623 std::is_same_v<::detail::ParameterStorage<
1624 mozilla::UniquePtr<int>&&>::Type::stored_type,
1625 mozilla::UniquePtr<int>>,
1626 "ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be "
1627 "UniquePtr<int>");
1628 static_assert(
1629 std::is_same_v<::detail::ParameterStorage<
1630 mozilla::UniquePtr<int>&&>::Type::passed_type,
1631 mozilla::UniquePtr<int>&&>,
1632 "ParameterStorage<UniquePtr<int>&&>::Type::passed_type should be "
1633 "UniquePtr<int>&&");
1634 {
1635 mozilla::UniquePtr<int> upi;
1636 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1637 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1638 &ThreadUtilsObject::Test1upi, std::move(upi));
1639 }
1640 r1->Run();
1641 EXPECT_EQ(count += 2, rpt->mCount);
1642 EXPECT_EQ(-1, rpt->mA0);
1643 rpt->mA0 = 0;
1644
1645 // Null unique pointer, by explicit store&move with "StoreCopyPassByRRef<T>"
1646 // syntax.
1647 static_assert(
1648 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1649 mozilla::UniquePtr<int>>>::Type::stored_type,
1650 StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1651 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1652 "type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1653 static_assert(
1654 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1655 mozilla::UniquePtr<int>>>::Type::stored_type,
1656 StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>,
1657 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1658 "type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
1659 static_assert(
1660 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1661 mozilla::UniquePtr<int>>>::Type::stored_type,
1662 mozilla::UniquePtr<int>>,
1663 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_"
1664 "type should be UniquePtr<int>");
1665 static_assert(
1666 std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
1667 mozilla::UniquePtr<int>>>::Type::passed_type,
1668 mozilla::UniquePtr<int>&&>,
1669 "ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::passed_"
1670 "type should be UniquePtr<int>&&");
1671 {
1672 mozilla::UniquePtr<int> upi;
1673 r1 = NewRunnableMethod<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>(
1674 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1675 &ThreadUtilsObject::Test1upi, std::move(upi));
1676 }
1677 r1->Run();
1678 EXPECT_EQ(count += 2, rpt->mCount);
1679 EXPECT_EQ(-1, rpt->mA0);
1680
1681 // Unique pointer as xvalue.
1682 {
1683 mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
1684 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1685 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1686 &ThreadUtilsObject::Test1upi, std::move(upi));
1687 }
1688 r1->Run();
1689 EXPECT_EQ(count += 2, rpt->mCount);
1690 EXPECT_EQ(1, rpt->mA0);
1691
1692 {
1693 mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
1694 r1 = NewRunnableMethod<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>(
1695 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1696 &ThreadUtilsObject::Test1upi, std::move(upi));
1697 }
1698 r1->Run();
1699 EXPECT_EQ(count += 2, rpt->mCount);
1700 EXPECT_EQ(1, rpt->mA0);
1701
1702 // Unique pointer as prvalue.
1703 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>(
1704 "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
1705 &ThreadUtilsObject::Test1upi, mozilla::MakeUnique<int>(2));
1706 r1->Run();
1707 EXPECT_EQ(count += 2, rpt->mCount);
1708 EXPECT_EQ(2, rpt->mA0);
1709
1710 // Unique pointer as lvalue to lref.
1711 {
1712 mozilla::UniquePtr<int> upi;
1713 r1 = NewRunnableMethod<mozilla::UniquePtr<int>&>(
1714 "TestThreadUtils::ThreadUtilsObject::Test1rupi", rpt,
1715 &ThreadUtilsObject::Test1rupi, upi);
1716 // Passed as lref, so Run() must be called while local upi is still alive!
1717 r1->Run();
1718 }
1719 EXPECT_EQ(count += 2, rpt->mCount);
1720 EXPECT_EQ(-1, rpt->mA0);
1721
1722 // Verify copy/move assumptions.
1723
1724 Spy::ClearAll();
1725 if (gDebug) {
1726 printf("%d - Test: Store copy from lvalue, pass by value\n", __LINE__);
1727 }
1728 { // Block around nsCOMPtr lifetime.
1729 nsCOMPtr<nsIRunnable> r2;
1730 { // Block around Spy lifetime.
1731 if (gDebug) {
1732 printf("%d - Spy s(10)\n", __LINE__);
1733 }
1734 Spy s(10);
1735 EXPECT_EQ(1, gConstructions);
1736 EXPECT_EQ(1, gAlive);
1737 if (gDebug) {
1738 printf(
1739 "%d - r2 = "
1740 "NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, s)\n",
1741 __LINE__);
1742 }
1743 r2 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
1744 "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
1745 &ThreadUtilsObject::TestByValue, s);
1746 EXPECT_EQ(2, gAlive);
1747 EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
1748 Spy::ClearActions();
1749 if (gDebug) {
1750 printf("%d - End block with Spy s(10)\n", __LINE__);
1751 }
1752 }
1753 EXPECT_EQ(1, gDestructions);
1754 EXPECT_EQ(1, gAlive);
1755 Spy::ClearActions();
1756 if (gDebug) {
1757 printf("%d - Run()\n", __LINE__);
1758 }
1759 r2->Run();
1760 EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call.
1761 EXPECT_EQ(10, rpt->mSpy.mID);
1762 EXPECT_LE(1, gDestructions);
1763 EXPECT_EQ(1, gAlive);
1764 Spy::ClearActions();
1765 if (gDebug) {
1766 printf("%d - End block with r\n", __LINE__);
1767 }
1768 }
1769 if (gDebug) {
1770 printf("%d - After end block with r\n", __LINE__);
1771 }
1772 EXPECT_EQ(1, gDestructions);
1773 EXPECT_EQ(0, gAlive);
1774
1775 Spy::ClearAll();
1776 if (gDebug) {
1777 printf("%d - Test: Store copy from prvalue, pass by value\n", __LINE__);
1778 }
1779 {
1780 if (gDebug) {
1781 printf(
1782 "%d - r3 = "
1783 "NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, "
1784 "Spy(11))\n",
1785 __LINE__);
1786 }
1787 nsCOMPtr<nsIRunnable> r3 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
1788 "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
1789 &ThreadUtilsObject::TestByValue, Spy(11));
1790 EXPECT_EQ(1, gAlive);
1791 EXPECT_EQ(1, gConstructions);
1792 EXPECT_LE(1, gMoveConstructions);
1793 Spy::ClearActions();
1794 if (gDebug) {
1795 printf("%d - Run()\n", __LINE__);
1796 }
1797 r3->Run();
1798 EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call.
1799 EXPECT_EQ(11, rpt->mSpy.mID);
1800 EXPECT_LE(1, gDestructions);
1801 EXPECT_EQ(1, gAlive);
1802 Spy::ClearActions();
1803 if (gDebug) {
1804 printf("%d - End block with r\n", __LINE__);
1805 }
1806 }
1807 if (gDebug) {
1808 printf("%d - After end block with r\n", __LINE__);
1809 }
1810 EXPECT_EQ(1, gDestructions);
1811 EXPECT_EQ(0, gAlive);
1812
1813 Spy::ClearAll();
1814 { // Store copy from xvalue, pass by value.
1815 nsCOMPtr<nsIRunnable> r4;
1816 {
1817 Spy s(12);
1818 EXPECT_EQ(1, gConstructions);
1819 EXPECT_EQ(1, gAlive);
1820 Spy::ClearActions();
1821 r4 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
1822 "TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
1823 &ThreadUtilsObject::TestByValue, std::move(s));
1824 EXPECT_LE(1, gMoveConstructions);
1825 EXPECT_EQ(1, gAlive);
1826 EXPECT_EQ(1, gZombies);
1827 Spy::ClearActions();
1828 }
1829 EXPECT_EQ(1, gDestructions);
1830 EXPECT_EQ(1, gAlive);
1831 EXPECT_EQ(0, gZombies);
1832 Spy::ClearActions();
1833 r4->Run();
1834 EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call.
1835 EXPECT_EQ(12, rpt->mSpy.mID);
1836 EXPECT_LE(1, gDestructions);
1837 EXPECT_EQ(1, gAlive);
1838 Spy::ClearActions();
1839 }
1840 EXPECT_EQ(1, gDestructions);
1841 EXPECT_EQ(0, gAlive);
1842 // Won't test xvalues anymore, prvalues are enough to verify all rvalues.
1843
1844 Spy::ClearAll();
1845 if (gDebug) {
1846 printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n",
1847 __LINE__);
1848 }
1849 { // Block around nsCOMPtr lifetime.
1850 nsCOMPtr<nsIRunnable> r5;
1851 { // Block around Spy lifetime.
1852 if (gDebug) {
1853 printf("%d - Spy s(20)\n", __LINE__);
1854 }
1855 Spy s(20);
1856 EXPECT_EQ(1, gConstructions);
1857 EXPECT_EQ(1, gAlive);
1858 if (gDebug) {
1859 printf(
1860 "%d - r5 = "
1861 "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef,"
1862 " s)\n",
1863 __LINE__);
1864 }
1865 r5 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(
1866 "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
1867 &ThreadUtilsObject::TestByConstLRef, s);
1868 EXPECT_EQ(2, gAlive);
1869 EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
1870 Spy::ClearActions();
1871 if (gDebug) {
1872 printf("%d - End block with Spy s(20)\n", __LINE__);
1873 }
1874 }
1875 EXPECT_EQ(1, gDestructions);
1876 EXPECT_EQ(1, gAlive);
1877 Spy::ClearActions();
1878 if (gDebug) {
1879 printf("%d - Run()\n", __LINE__);
1880 }
1881 r5->Run();
1882 EXPECT_EQ(0, gCopyConstructions); // No copies in call.
1883 EXPECT_EQ(20, rpt->mSpy.mID);
1884 EXPECT_EQ(0, gDestructions);
1885 EXPECT_EQ(1, gAlive);
1886 Spy::ClearActions();
1887 if (gDebug) {
1888 printf("%d - End block with r\n", __LINE__);
1889 }
1890 }
1891 if (gDebug) {
1892 printf("%d - After end block with r\n", __LINE__);
1893 }
1894 EXPECT_EQ(1, gDestructions);
1895 EXPECT_EQ(0, gAlive);
1896
1897 Spy::ClearAll();
1898 if (gDebug) {
1899 printf("%d - Test: Store copy from prvalue, pass by const lvalue ref\n",
1900 __LINE__);
1901 }
1902 {
1903 if (gDebug) {
1904 printf(
1905 "%d - r6 = "
1906 "NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef, "
1907 "Spy(21))\n",
1908 __LINE__);
1909 }
1910 nsCOMPtr<nsIRunnable> r6 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>(
1911 "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
1912 &ThreadUtilsObject::TestByConstLRef, Spy(21));
1913 EXPECT_EQ(1, gAlive);
1914 EXPECT_EQ(1, gConstructions);
1915 EXPECT_LE(1, gMoveConstructions);
1916 Spy::ClearActions();
1917 if (gDebug) {
1918 printf("%d - Run()\n", __LINE__);
1919 }
1920 r6->Run();
1921 EXPECT_EQ(0, gCopyConstructions); // No copies in call.
1922 EXPECT_EQ(21, rpt->mSpy.mID);
1923 EXPECT_EQ(0, gDestructions);
1924 EXPECT_EQ(1, gAlive);
1925 Spy::ClearActions();
1926 if (gDebug) {
1927 printf("%d - End block with r\n", __LINE__);
1928 }
1929 }
1930 if (gDebug) {
1931 printf("%d - After end block with r\n", __LINE__);
1932 }
1933 EXPECT_EQ(1, gDestructions);
1934 EXPECT_EQ(0, gAlive);
1935
1936 Spy::ClearAll();
1937 if (gDebug) {
1938 printf("%d - Test: Store copy from lvalue, pass by rvalue ref\n", __LINE__);
1939 }
1940 { // Block around nsCOMPtr lifetime.
1941 nsCOMPtr<nsIRunnable> r7;
1942 { // Block around Spy lifetime.
1943 if (gDebug) {
1944 printf("%d - Spy s(30)\n", __LINE__);
1945 }
1946 Spy s(30);
1947 EXPECT_EQ(1, gConstructions);
1948 EXPECT_EQ(1, gAlive);
1949 if (gDebug) {
1950 printf(
1951 "%d - r7 = "
1952 "NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, s)\n",
1953 __LINE__);
1954 }
1955 r7 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(
1956 "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
1957 &ThreadUtilsObject::TestByRRef, s);
1958 EXPECT_EQ(2, gAlive);
1959 EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
1960 Spy::ClearActions();
1961 if (gDebug) {
1962 printf("%d - End block with Spy s(30)\n", __LINE__);
1963 }
1964 }
1965 EXPECT_EQ(1, gDestructions);
1966 EXPECT_EQ(1, gAlive);
1967 Spy::ClearActions();
1968 if (gDebug) {
1969 printf("%d - Run()\n", __LINE__);
1970 }
1971 r7->Run();
1972 EXPECT_LE(1, gMoves); // Move in call.
1973 EXPECT_EQ(30, rpt->mSpy.mID);
1974 EXPECT_EQ(0, gDestructions);
1975 EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
1976 EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
1977 Spy::ClearActions();
1978 if (gDebug) {
1979 printf("%d - End block with r\n", __LINE__);
1980 }
1981 }
1982 if (gDebug) {
1983 printf("%d - After end block with r\n", __LINE__);
1984 }
1985 EXPECT_EQ(1, gDestructions);
1986 EXPECT_EQ(0, gAlive);
1987
1988 Spy::ClearAll();
1989 if (gDebug) {
1990 printf("%d - Test: Store copy from prvalue, pass by rvalue ref\n",
1991 __LINE__);
1992 }
1993 {
1994 if (gDebug) {
1995 printf(
1996 "%d - r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(&TestByRRef, "
1997 "Spy(31))\n",
1998 __LINE__);
1999 }
2000 nsCOMPtr<nsIRunnable> r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>(
2001 "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
2002 &ThreadUtilsObject::TestByRRef, Spy(31));
2003 EXPECT_EQ(1, gAlive);
2004 EXPECT_EQ(1, gConstructions);
2005 EXPECT_LE(1, gMoveConstructions);
2006 Spy::ClearActions();
2007 if (gDebug) {
2008 printf("%d - Run()\n", __LINE__);
2009 }
2010 r8->Run();
2011 EXPECT_LE(1, gMoves); // Move in call.
2012 EXPECT_EQ(31, rpt->mSpy.mID);
2013 EXPECT_EQ(0, gDestructions);
2014 EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
2015 EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
2016 Spy::ClearActions();
2017 if (gDebug) {
2018 printf("%d - End block with r\n", __LINE__);
2019 }
2020 }
2021 if (gDebug) {
2022 printf("%d - After end block with r\n", __LINE__);
2023 }
2024 EXPECT_EQ(1, gDestructions);
2025 EXPECT_EQ(0, gAlive);
2026
2027 Spy::ClearAll();
2028 if (gDebug) {
2029 printf("%d - Test: Store lvalue ref, pass lvalue ref\n", __LINE__);
2030 }
2031 {
2032 if (gDebug) {
2033 printf("%d - Spy s(40)\n", __LINE__);
2034 }
2035 Spy s(40);
2036 EXPECT_EQ(1, gConstructions);
2037 EXPECT_EQ(1, gAlive);
2038 Spy::ClearActions();
2039 if (gDebug) {
2040 printf("%d - r9 = NewRunnableMethod<Spy&>(&TestByLRef, s)\n", __LINE__);
2041 }
2042 nsCOMPtr<nsIRunnable> r9 = NewRunnableMethod<Spy&>(
2043 "TestThreadUtils::ThreadUtilsObject::TestByLRef", rpt,
2044 &ThreadUtilsObject::TestByLRef, s);
2045 EXPECT_EQ(0, gAllConstructions);
2046 EXPECT_EQ(0, gDestructions);
2047 EXPECT_EQ(1, gAlive);
2048 Spy::ClearActions();
2049 if (gDebug) {
2050 printf("%d - Run()\n", __LINE__);
2051 }
2052 r9->Run();
2053 EXPECT_LE(1, gAssignments); // Assignment from reference in call.
2054 EXPECT_EQ(40, rpt->mSpy.mID);
2055 EXPECT_EQ(&s, rpt->mSpyPtr);
2056 EXPECT_EQ(0, gDestructions);
2057 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
2058 Spy::ClearActions();
2059 if (gDebug) {
2060 printf("%d - End block with r\n", __LINE__);
2061 }
2062 }
2063 if (gDebug) {
2064 printf("%d - After end block with r\n", __LINE__);
2065 }
2066 EXPECT_EQ(1, gDestructions);
2067 EXPECT_EQ(0, gAlive);
2068
2069 Spy::ClearAll();
2070 if (gDebug) {
2071 printf("%d - Test: Store nsRefPtr, pass by pointer\n", __LINE__);
2072 }
2073 { // Block around nsCOMPtr lifetime.
2074 nsCOMPtr<nsIRunnable> r10;
2075 SpyWithISupports* ptr = 0;
2076 { // Block around RefPtr<Spy> lifetime.
2077 if (gDebug) {
2078 printf("%d - RefPtr<SpyWithISupports> s(new SpyWithISupports(45))\n",
2079 __LINE__);
2080 }
2081 RefPtr<SpyWithISupports> s(new SpyWithISupports(45));
2082 ptr = s.get();
2083 EXPECT_EQ(1, gConstructions);
2084 EXPECT_EQ(1, gAlive);
2085 if (gDebug) {
2086 printf(
2087 "%d - r10 = "
2088 "NewRunnableMethod<StoreRefPtrPassByPtr<Spy>>(&TestByRRef, "
2089 "s.get())\n",
2090 __LINE__);
2091 }
2092 r10 = NewRunnableMethod<StoreRefPtrPassByPtr<SpyWithISupports>>(
2093 "TestThreadUtils::ThreadUtilsObject::TestByPointer", rpt,
2094 &ThreadUtilsObject::TestByPointer, s.get());
2095 EXPECT_LE(0, gAllConstructions);
2096 EXPECT_EQ(1, gAlive);
2097 Spy::ClearActions();
2098 if (gDebug) {
2099 printf("%d - End block with RefPtr<Spy> s\n", __LINE__);
2100 }
2101 }
2102 EXPECT_EQ(0, gDestructions);
2103 EXPECT_EQ(1, gAlive);
2104 Spy::ClearActions();
2105 if (gDebug) {
2106 printf("%d - Run()\n", __LINE__);
2107 }
2108 r10->Run();
2109 EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
2110 EXPECT_EQ(45, rpt->mSpy.mID);
2111 EXPECT_EQ(ptr, rpt->mSpyPtr);
2112 EXPECT_EQ(0, gDestructions);
2113 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
2114 Spy::ClearActions();
2115 if (gDebug) {
2116 printf("%d - End block with r\n", __LINE__);
2117 }
2118 }
2119 if (gDebug) {
2120 printf("%d - After end block with r\n", __LINE__);
2121 }
2122 EXPECT_EQ(1, gDestructions);
2123 EXPECT_EQ(0, gAlive);
2124
2125 Spy::ClearAll();
2126 if (gDebug) {
2127 printf("%d - Test: Store pointer to lvalue, pass by pointer\n", __LINE__);
2128 }
2129 {
2130 if (gDebug) {
2131 printf("%d - Spy s(55)\n", __LINE__);
2132 }
2133 Spy s(55);
2134 EXPECT_EQ(1, gConstructions);
2135 EXPECT_EQ(1, gAlive);
2136 Spy::ClearActions();
2137 if (gDebug) {
2138 printf("%d - r11 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
2139 __LINE__);
2140 }
2141 nsCOMPtr<nsIRunnable> r11 = NewRunnableMethod<Spy*>(
2142 "TestThreadUtils::ThreadUtilsObject::TestByPointer", rpt,
2143 &ThreadUtilsObject::TestByPointer, &s);
2144 EXPECT_EQ(0, gAllConstructions);
2145 EXPECT_EQ(0, gDestructions);
2146 EXPECT_EQ(1, gAlive);
2147 Spy::ClearActions();
2148 if (gDebug) {
2149 printf("%d - Run()\n", __LINE__);
2150 }
2151 r11->Run();
2152 EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
2153 EXPECT_EQ(55, rpt->mSpy.mID);
2154 EXPECT_EQ(&s, rpt->mSpyPtr);
2155 EXPECT_EQ(0, gDestructions);
2156 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
2157 Spy::ClearActions();
2158 if (gDebug) {
2159 printf("%d - End block with r\n", __LINE__);
2160 }
2161 }
2162 if (gDebug) {
2163 printf("%d - After end block with r\n", __LINE__);
2164 }
2165 EXPECT_EQ(1, gDestructions);
2166 EXPECT_EQ(0, gAlive);
2167
2168 Spy::ClearAll();
2169 if (gDebug) {
2170 printf("%d - Test: Store pointer to const lvalue, pass by pointer\n",
2171 __LINE__);
2172 }
2173 {
2174 if (gDebug) {
2175 printf("%d - Spy s(60)\n", __LINE__);
2176 }
2177 Spy s(60);
2178 EXPECT_EQ(1, gConstructions);
2179 EXPECT_EQ(1, gAlive);
2180 Spy::ClearActions();
2181 if (gDebug) {
2182 printf("%d - r12 = NewRunnableMethod<Spy*>(&TestByPointer, s)\n",
2183 __LINE__);
2184 }
2185 nsCOMPtr<nsIRunnable> r12 = NewRunnableMethod<const Spy*>(
2186 "TestThreadUtils::ThreadUtilsObject::TestByPointerToConst", rpt,
2187 &ThreadUtilsObject::TestByPointerToConst, &s);
2188 EXPECT_EQ(0, gAllConstructions);
2189 EXPECT_EQ(0, gDestructions);
2190 EXPECT_EQ(1, gAlive);
2191 Spy::ClearActions();
2192 if (gDebug) {
2193 printf("%d - Run()\n", __LINE__);
2194 }
2195 r12->Run();
2196 EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
2197 EXPECT_EQ(60, rpt->mSpy.mID);
2198 EXPECT_EQ(&s, rpt->mSpyPtr);
2199 EXPECT_EQ(0, gDestructions);
2200 EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
2201 Spy::ClearActions();
2202 if (gDebug) {
2203 printf("%d - End block with r\n", __LINE__);
2204 }
2205 }
2206 if (gDebug) {
2207 printf("%d - After end block with r\n", __LINE__);
2208 }
2209 EXPECT_EQ(1, gDestructions);
2210 EXPECT_EQ(0, gAlive);
2211 }
2212