Bug 1883861 - Part 1: Move visitMemoryBarrier into the common CodeGenerator file...
[gecko.git] / xpcom / tests / gtest / TestThreadManager.cpp
blob41279e104ca95f05ea443a11e4eefad7e25efe45
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"
8 #include "nsCOMPtr.h"
9 #include "nsIThread.h"
10 #include "nsXPCOM.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 {
21 public:
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);
29 return NS_OK;
32 private:
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 {
42 public:
43 explicit SpinRunnable(nsINestedEventLoopCondition* aCondition)
44 : Runnable("SpinRunnable"), mCondition(aCondition), mResult(NS_OK) {}
46 NS_IMETHODIMP Run() {
47 nsCOMPtr<nsIThreadManager> threadMan =
48 do_GetService("@mozilla.org/thread-manager;1");
50 mResult = threadMan->SpinEventLoopUntil(
51 "xpcom:TestThreadManager.cpp:SpinRunnable->Run()"_ns, mCondition);
52 return NS_OK;
55 nsresult SpinLoopResult() { return mResult; }
57 private:
58 ~SpinRunnable() = default;
60 nsCOMPtr<nsINestedEventLoopCondition> mCondition;
61 Atomic<nsresult> mResult;
64 class CountRunnable final : public Runnable {
65 public:
66 explicit CountRunnable(Atomic<uint32_t>& aCounter)
67 : Runnable("CountRunnable"), mCounter(aCounter) {}
69 NS_IMETHODIMP Run() {
70 mCounter++;
71 return NS_OK;
74 private:
75 Atomic<uint32_t>& mCounter;
78 TEST(ThreadManager, SpinEventLoopUntilSuccess)
80 const uint32_t kRunnablesToDispatch = 100;
81 nsresult rv;
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 {
103 public:
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;
113 return NS_OK;
116 private:
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;
128 nsresult rv;
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());