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