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/. */
7 #include "nsIThreadManager.h"
11 #include "nsThreadUtils.h"
12 #include "nsServiceManagerUtils.h"
13 #include "mozilla/Atomics.h"
14 #include "gtest/gtest.h"
15 #include "mozilla/gtest/MozAssertions.h"
17 using mozilla::Atomic
;
18 using mozilla::Runnable
;
20 class WaitCondition final
: public nsINestedEventLoopCondition
{
22 NS_DECL_THREADSAFE_ISUPPORTS
24 WaitCondition(Atomic
<uint32_t>& aCounter
, uint32_t aMaxCount
)
25 : mCounter(aCounter
), mMaxCount(aMaxCount
) {}
27 NS_IMETHODIMP
IsDone(bool* aDone
) override
{
28 *aDone
= (mCounter
== mMaxCount
);
33 ~WaitCondition() = default;
35 Atomic
<uint32_t>& mCounter
;
36 const uint32_t mMaxCount
;
39 NS_IMPL_ISUPPORTS(WaitCondition
, nsINestedEventLoopCondition
)
41 class SpinRunnable final
: public Runnable
{
43 explicit SpinRunnable(nsINestedEventLoopCondition
* aCondition
)
44 : Runnable("SpinRunnable"), mCondition(aCondition
), mResult(NS_OK
) {}
47 nsCOMPtr
<nsIThreadManager
> threadMan
=
48 do_GetService("@mozilla.org/thread-manager;1");
50 mResult
= threadMan
->SpinEventLoopUntil(
51 "xpcom:TestThreadManager.cpp:SpinRunnable->Run()"_ns
, mCondition
);
55 nsresult
SpinLoopResult() { return mResult
; }
58 ~SpinRunnable() = default;
60 nsCOMPtr
<nsINestedEventLoopCondition
> mCondition
;
61 Atomic
<nsresult
> mResult
;
64 class CountRunnable final
: public Runnable
{
66 explicit CountRunnable(Atomic
<uint32_t>& aCounter
)
67 : Runnable("CountRunnable"), mCounter(aCounter
) {}
75 Atomic
<uint32_t>& mCounter
;
78 TEST(ThreadManager
, SpinEventLoopUntilSuccess
)
80 const uint32_t kRunnablesToDispatch
= 100;
82 mozilla::Atomic
<uint32_t> count(0);
84 nsCOMPtr
<nsINestedEventLoopCondition
> condition
=
85 new WaitCondition(count
, kRunnablesToDispatch
);
86 RefPtr
<SpinRunnable
> spinner
= new SpinRunnable(condition
);
87 nsCOMPtr
<nsIThread
> thread
;
88 rv
= NS_NewNamedThread("SpinEventLoop", getter_AddRefs(thread
), spinner
);
89 ASSERT_NS_SUCCEEDED(rv
);
91 nsCOMPtr
<nsIRunnable
> counter
= new CountRunnable(count
);
92 for (uint32_t i
= 0; i
< kRunnablesToDispatch
; ++i
) {
93 rv
= thread
->Dispatch(counter
, NS_DISPATCH_NORMAL
);
94 ASSERT_NS_SUCCEEDED(rv
);
97 rv
= thread
->Shutdown();
98 ASSERT_NS_SUCCEEDED(rv
);
99 ASSERT_NS_SUCCEEDED(spinner
->SpinLoopResult());
102 class ErrorCondition final
: public nsINestedEventLoopCondition
{
104 NS_DECL_THREADSAFE_ISUPPORTS
106 ErrorCondition(Atomic
<uint32_t>& aCounter
, uint32_t aMaxCount
)
107 : mCounter(aCounter
), mMaxCount(aMaxCount
) {}
109 NS_IMETHODIMP
IsDone(bool* aDone
) override
{
110 if (mCounter
== mMaxCount
) {
111 return NS_ERROR_ILLEGAL_VALUE
;
117 ~ErrorCondition() = default;
119 Atomic
<uint32_t>& mCounter
;
120 const uint32_t mMaxCount
;
123 NS_IMPL_ISUPPORTS(ErrorCondition
, nsINestedEventLoopCondition
)
125 TEST(ThreadManager
, SpinEventLoopUntilError
)
127 const uint32_t kRunnablesToDispatch
= 100;
129 mozilla::Atomic
<uint32_t> count(0);
131 nsCOMPtr
<nsINestedEventLoopCondition
> condition
=
132 new ErrorCondition(count
, kRunnablesToDispatch
);
133 RefPtr
<SpinRunnable
> spinner
= new SpinRunnable(condition
);
134 nsCOMPtr
<nsIThread
> thread
;
135 rv
= NS_NewNamedThread("SpinEventLoop", getter_AddRefs(thread
), spinner
);
136 ASSERT_NS_SUCCEEDED(rv
);
138 nsCOMPtr
<nsIRunnable
> counter
= new CountRunnable(count
);
139 for (uint32_t i
= 0; i
< kRunnablesToDispatch
; ++i
) {
140 rv
= thread
->Dispatch(counter
, NS_DISPATCH_NORMAL
);
141 ASSERT_NS_SUCCEEDED(rv
);
144 rv
= thread
->Shutdown();
145 ASSERT_NS_SUCCEEDED(rv
);
146 ASSERT_NS_FAILED(spinner
->SpinLoopResult());