Coverage Report

Created: 2018-09-25 14:53

/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
}