/src/mozilla-central/xpcom/tests/gtest/TestThreadManager.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nsIThreadManager.h" |
8 | | #include "nsCOMPtr.h" |
9 | | #include "nsXPCOM.h" |
10 | | #include "nsThreadUtils.h" |
11 | | #include "nsServiceManagerUtils.h" |
12 | | #include "mozilla/Atomics.h" |
13 | | #include "gtest/gtest.h" |
14 | | |
15 | | using mozilla::Atomic; |
16 | | using mozilla::Runnable; |
17 | | |
18 | | class WaitCondition final : public nsINestedEventLoopCondition |
19 | | { |
20 | | public: |
21 | | NS_DECL_THREADSAFE_ISUPPORTS |
22 | | |
23 | | WaitCondition(Atomic<uint32_t>& aCounter, uint32_t aMaxCount) |
24 | | : mCounter(aCounter) |
25 | | , mMaxCount(aMaxCount) |
26 | 0 | { |
27 | 0 | } |
28 | | |
29 | | NS_IMETHODIMP IsDone(bool* aDone) override |
30 | 0 | { |
31 | 0 | *aDone = (mCounter == mMaxCount); |
32 | 0 | return NS_OK; |
33 | 0 | } |
34 | | |
35 | | private: |
36 | | ~WaitCondition() = default; |
37 | | |
38 | | Atomic<uint32_t>& mCounter; |
39 | | const uint32_t mMaxCount; |
40 | | }; |
41 | | |
42 | | NS_IMPL_ISUPPORTS(WaitCondition, nsINestedEventLoopCondition) |
43 | | |
44 | | class SpinRunnable final : public Runnable |
45 | | { |
46 | | public: |
47 | | explicit SpinRunnable(nsINestedEventLoopCondition* aCondition) |
48 | | : Runnable("SpinRunnable") |
49 | | , mCondition(aCondition) |
50 | | , mResult(NS_OK) |
51 | 0 | { |
52 | 0 | } |
53 | | |
54 | | NS_IMETHODIMP Run() |
55 | 0 | { |
56 | 0 | nsCOMPtr<nsIThreadManager> threadMan = |
57 | 0 | do_GetService("@mozilla.org/thread-manager;1"); |
58 | 0 | mResult = threadMan->SpinEventLoopUntil(mCondition); |
59 | 0 | return NS_OK; |
60 | 0 | } |
61 | | |
62 | | nsresult SpinLoopResult() |
63 | 0 | { |
64 | 0 | return mResult; |
65 | 0 | } |
66 | | |
67 | | private: |
68 | 0 | ~SpinRunnable() = default; |
69 | | |
70 | | nsCOMPtr<nsINestedEventLoopCondition> mCondition; |
71 | | Atomic<nsresult> mResult; |
72 | | }; |
73 | | |
74 | | class CountRunnable final : public Runnable |
75 | | { |
76 | | public: |
77 | | explicit CountRunnable(Atomic<uint32_t>& aCounter) |
78 | | : Runnable("CountRunnable") |
79 | | , mCounter(aCounter) |
80 | 0 | { |
81 | 0 | } |
82 | | |
83 | | NS_IMETHODIMP Run() |
84 | 0 | { |
85 | 0 | mCounter++; |
86 | 0 | return NS_OK; |
87 | 0 | } |
88 | | |
89 | | private: |
90 | | Atomic<uint32_t>& mCounter; |
91 | | }; |
92 | | |
93 | | TEST(ThreadManager, SpinEventLoopUntilSuccess) |
94 | 0 | { |
95 | 0 | const uint32_t kRunnablesToDispatch = 100; |
96 | 0 | nsresult rv; |
97 | 0 | mozilla::Atomic<uint32_t> count(0); |
98 | 0 |
|
99 | 0 | nsCOMPtr<nsINestedEventLoopCondition> condition = |
100 | 0 | new WaitCondition(count, kRunnablesToDispatch); |
101 | 0 | RefPtr<SpinRunnable> spinner = new SpinRunnable(condition); |
102 | 0 | nsCOMPtr<nsIThread> thread; |
103 | 0 | rv = NS_NewNamedThread("SpinEventLoop", getter_AddRefs(thread), spinner); |
104 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
105 | 0 |
|
106 | 0 | nsCOMPtr<nsIRunnable> counter = new CountRunnable(count); |
107 | 0 | for (uint32_t i = 0; i < kRunnablesToDispatch; ++i) { |
108 | 0 | rv = thread->Dispatch(counter, NS_DISPATCH_NORMAL); |
109 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
110 | 0 | } |
111 | 0 |
|
112 | 0 | rv = thread->Shutdown(); |
113 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
114 | 0 | ASSERT_TRUE(NS_SUCCEEDED(spinner->SpinLoopResult())); |
115 | 0 | } |
116 | | |
117 | | class ErrorCondition final : public nsINestedEventLoopCondition |
118 | | { |
119 | | public: |
120 | | NS_DECL_THREADSAFE_ISUPPORTS |
121 | | |
122 | | ErrorCondition(Atomic<uint32_t>& aCounter, uint32_t aMaxCount) |
123 | | : mCounter(aCounter) |
124 | | , mMaxCount(aMaxCount) |
125 | 0 | { |
126 | 0 | } |
127 | | |
128 | | NS_IMETHODIMP IsDone(bool* aDone) override |
129 | 0 | { |
130 | 0 | if (mCounter == mMaxCount) { |
131 | 0 | return NS_ERROR_ILLEGAL_VALUE; |
132 | 0 | } |
133 | 0 | return NS_OK; |
134 | 0 | } |
135 | | |
136 | | private: |
137 | | ~ErrorCondition() = default; |
138 | | |
139 | | Atomic<uint32_t>& mCounter; |
140 | | const uint32_t mMaxCount; |
141 | | }; |
142 | | |
143 | | NS_IMPL_ISUPPORTS(ErrorCondition, nsINestedEventLoopCondition) |
144 | | |
145 | | TEST(ThreadManager, SpinEventLoopUntilError) |
146 | 0 | { |
147 | 0 | const uint32_t kRunnablesToDispatch = 100; |
148 | 0 | nsresult rv; |
149 | 0 | mozilla::Atomic<uint32_t> count(0); |
150 | 0 |
|
151 | 0 | nsCOMPtr<nsINestedEventLoopCondition> condition = |
152 | 0 | new ErrorCondition(count, kRunnablesToDispatch); |
153 | 0 | RefPtr<SpinRunnable> spinner = new SpinRunnable(condition); |
154 | 0 | nsCOMPtr<nsIThread> thread; |
155 | 0 | rv = NS_NewNamedThread("SpinEventLoop", getter_AddRefs(thread), spinner); |
156 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
157 | 0 |
|
158 | 0 | nsCOMPtr<nsIRunnable> counter = new CountRunnable(count); |
159 | 0 | for (uint32_t i = 0; i < kRunnablesToDispatch; ++i) { |
160 | 0 | rv = thread->Dispatch(counter, NS_DISPATCH_NORMAL); |
161 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
162 | 0 | } |
163 | 0 |
|
164 | 0 | rv = thread->Shutdown(); |
165 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
166 | 0 | ASSERT_TRUE(NS_FAILED(spinner->SpinLoopResult())); |
167 | 0 | } |