Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/tests/gtest/TestSynchronization.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 "mozilla/CondVar.h"
8
#include "mozilla/Monitor.h"
9
#include "mozilla/ReentrantMonitor.h"
10
#include "mozilla/Mutex.h"
11
#include "gtest/gtest.h"
12
13
using namespace mozilla;
14
15
static PRThread*
16
spawn(void (*run)(void*), void* arg)
17
0
{
18
0
  return PR_CreateThread(PR_SYSTEM_THREAD,
19
0
                         run,
20
0
                         arg,
21
0
                         PR_PRIORITY_NORMAL,
22
0
                         PR_GLOBAL_THREAD,
23
0
                         PR_JOINABLE_THREAD,
24
0
                         0);
25
0
}
26
27
//-----------------------------------------------------------------------------
28
// Sanity check: tests that can be done on a single thread
29
//
30
TEST(Synchronization, Sanity)
31
0
{
32
0
  Mutex lock("sanity::lock");
33
0
  lock.Lock();
34
0
  lock.AssertCurrentThreadOwns();
35
0
  lock.Unlock();
36
0
37
0
  {
38
0
    MutexAutoLock autolock(lock);
39
0
    lock.AssertCurrentThreadOwns();
40
0
  }
41
0
42
0
  lock.Lock();
43
0
  lock.AssertCurrentThreadOwns();
44
0
  {
45
0
    MutexAutoUnlock autounlock(lock);
46
0
  }
47
0
  lock.AssertCurrentThreadOwns();
48
0
  lock.Unlock();
49
0
50
0
  ReentrantMonitor mon("sanity::monitor");
51
0
  mon.Enter();
52
0
  mon.AssertCurrentThreadIn();
53
0
  mon.Enter();
54
0
  mon.AssertCurrentThreadIn();
55
0
  mon.Exit();
56
0
  mon.AssertCurrentThreadIn();
57
0
  mon.Exit();
58
0
59
0
  {
60
0
    ReentrantMonitorAutoEnter automon(mon);
61
0
    mon.AssertCurrentThreadIn();
62
0
  }
63
0
}
64
65
//-----------------------------------------------------------------------------
66
// Mutex contention tests
67
//
68
static Mutex* gLock1;
69
70
static void
71
MutexContention_thread(void* /*arg*/)
72
0
{
73
0
  for (int i = 0; i < 100000; ++i) {
74
0
    gLock1->Lock();
75
0
    gLock1->AssertCurrentThreadOwns();
76
0
    gLock1->Unlock();
77
0
  }
78
0
}
79
80
TEST(Synchronization, MutexContention)
81
0
{
82
0
  gLock1 = new Mutex("lock1");
83
0
  // PURPOSELY not checking for OOM.  YAY!
84
0
85
0
  PRThread* t1 = spawn(MutexContention_thread, nullptr);
86
0
  PRThread* t2 = spawn(MutexContention_thread, nullptr);
87
0
  PRThread* t3 = spawn(MutexContention_thread, nullptr);
88
0
89
0
  PR_JoinThread(t1);
90
0
  PR_JoinThread(t2);
91
0
  PR_JoinThread(t3);
92
0
93
0
  delete gLock1;
94
0
}
95
96
//-----------------------------------------------------------------------------
97
// Monitor tests
98
//
99
static Monitor* gMon1;
100
101
static void
102
MonitorContention_thread(void* /*arg*/)
103
0
{
104
0
  for (int i = 0; i < 100000; ++i) {
105
0
    gMon1->Lock();
106
0
    gMon1->AssertCurrentThreadOwns();
107
0
    gMon1->Unlock();
108
0
  }
109
0
}
110
111
TEST(Synchronization, MonitorContention)
112
0
{
113
0
  gMon1 = new Monitor("mon1");
114
0
115
0
  PRThread* t1 = spawn(MonitorContention_thread, nullptr);
116
0
  PRThread* t2 = spawn(MonitorContention_thread, nullptr);
117
0
  PRThread* t3 = spawn(MonitorContention_thread, nullptr);
118
0
119
0
  PR_JoinThread(t1);
120
0
  PR_JoinThread(t2);
121
0
  PR_JoinThread(t3);
122
0
123
0
  delete gMon1;
124
0
}
125
126
127
static ReentrantMonitor* gMon2;
128
129
static void
130
MonitorContention2_thread(void* /*arg*/)
131
0
{
132
0
  for (int i = 0; i < 100000; ++i) {
133
0
    gMon2->Enter();
134
0
    gMon2->AssertCurrentThreadIn();
135
0
    {
136
0
      gMon2->Enter();
137
0
      gMon2->AssertCurrentThreadIn();
138
0
      gMon2->Exit();
139
0
    }
140
0
    gMon2->AssertCurrentThreadIn();
141
0
    gMon2->Exit();
142
0
  }
143
0
}
144
145
TEST(Synchronization, MonitorContention2)
146
0
{
147
0
  gMon2 = new ReentrantMonitor("mon1");
148
0
149
0
  PRThread* t1 = spawn(MonitorContention2_thread, nullptr);
150
0
  PRThread* t2 = spawn(MonitorContention2_thread, nullptr);
151
0
  PRThread* t3 = spawn(MonitorContention2_thread, nullptr);
152
0
153
0
  PR_JoinThread(t1);
154
0
  PR_JoinThread(t2);
155
0
  PR_JoinThread(t3);
156
0
157
0
  delete gMon2;
158
0
}
159
160
161
static ReentrantMonitor* gMon3;
162
static int32_t gMonFirst;
163
164
static void
165
MonitorSyncSanity_thread(void* /*arg*/)
166
0
{
167
0
  gMon3->Enter();
168
0
  gMon3->AssertCurrentThreadIn();
169
0
  if (gMonFirst) {
170
0
    gMonFirst = 0;
171
0
    gMon3->Wait();
172
0
    gMon3->Enter();
173
0
  } else {
174
0
    gMon3->Notify();
175
0
    gMon3->Enter();
176
0
  }
177
0
  gMon3->AssertCurrentThreadIn();
178
0
  gMon3->Exit();
179
0
  gMon3->AssertCurrentThreadIn();
180
0
  gMon3->Exit();
181
0
}
182
183
TEST(Synchronization, MonitorSyncSanity)
184
0
{
185
0
  gMon3 = new ReentrantMonitor("monitor::syncsanity");
186
0
187
0
  for (int32_t i = 0; i < 10000; ++i) {
188
0
    gMonFirst = 1;
189
0
    PRThread* ping = spawn(MonitorSyncSanity_thread, nullptr);
190
0
    PRThread* pong = spawn(MonitorSyncSanity_thread, nullptr);
191
0
    PR_JoinThread(ping);
192
0
    PR_JoinThread(pong);
193
0
  }
194
0
195
0
  delete gMon3;
196
0
}
197
198
//-----------------------------------------------------------------------------
199
// Condvar tests
200
//
201
static Mutex* gCvlock1;
202
static CondVar* gCv1;
203
static int32_t gCvFirst;
204
205
static void
206
CondVarSanity_thread(void* /*arg*/)
207
0
{
208
0
  gCvlock1->Lock();
209
0
  gCvlock1->AssertCurrentThreadOwns();
210
0
  if (gCvFirst) {
211
0
    gCvFirst = 0;
212
0
    gCv1->Wait();
213
0
  } else {
214
0
    gCv1->Notify();
215
0
  }
216
0
  gCvlock1->AssertCurrentThreadOwns();
217
0
  gCvlock1->Unlock();
218
0
}
219
220
TEST(Synchronization, CondVarSanity)
221
0
{
222
0
  gCvlock1 = new Mutex("cvlock1");
223
0
  gCv1 = new CondVar(*gCvlock1, "cvlock1");
224
0
225
0
  for (int32_t i = 0; i < 10000; ++i) {
226
0
    gCvFirst = 1;
227
0
    PRThread* ping = spawn(CondVarSanity_thread, nullptr);
228
0
    PRThread* pong = spawn(CondVarSanity_thread, nullptr);
229
0
    PR_JoinThread(ping);
230
0
    PR_JoinThread(pong);
231
0
  }
232
0
233
0
  delete gCv1;
234
0
  delete gCvlock1;
235
0
}
236
237
//-----------------------------------------------------------------------------
238
// AutoLock tests
239
//
240
TEST(Synchronization, AutoLock)
241
0
{
242
0
  Mutex l1("autolock");
243
0
  MutexAutoLock autol1(l1);
244
0
245
0
  l1.AssertCurrentThreadOwns();
246
0
247
0
  {
248
0
    Mutex l2("autolock2");
249
0
    MutexAutoLock autol2(l2);
250
0
251
0
    l1.AssertCurrentThreadOwns();
252
0
    l2.AssertCurrentThreadOwns();
253
0
  }
254
0
255
0
  l1.AssertCurrentThreadOwns();
256
0
}
257
258
//-----------------------------------------------------------------------------
259
// AutoUnlock tests
260
//
261
TEST(Synchronization, AutoUnlock)
262
0
{
263
0
  Mutex l1("autounlock");
264
0
  Mutex l2("autounlock2");
265
0
266
0
  l1.Lock();
267
0
  l1.AssertCurrentThreadOwns();
268
0
269
0
  {
270
0
    MutexAutoUnlock autol1(l1);
271
0
    {
272
0
      l2.Lock();
273
0
      l2.AssertCurrentThreadOwns();
274
0
275
0
      MutexAutoUnlock autol2(l2);
276
0
    }
277
0
    l2.AssertCurrentThreadOwns();
278
0
    l2.Unlock();
279
0
  }
280
0
  l1.AssertCurrentThreadOwns();
281
0
282
0
  l1.Unlock();
283
0
}
284
285
//-----------------------------------------------------------------------------
286
// AutoMonitor tests
287
//
288
TEST(Synchronization, AutoMonitor)
289
0
{
290
0
  ReentrantMonitor m1("automonitor");
291
0
  ReentrantMonitor m2("automonitor2");
292
0
293
0
  m1.Enter();
294
0
  m1.AssertCurrentThreadIn();
295
0
  {
296
0
    ReentrantMonitorAutoEnter autom1(m1);
297
0
    m1.AssertCurrentThreadIn();
298
0
299
0
    m2.Enter();
300
0
    m2.AssertCurrentThreadIn();
301
0
    {
302
0
      ReentrantMonitorAutoEnter autom2(m2);
303
0
      m1.AssertCurrentThreadIn();
304
0
      m2.AssertCurrentThreadIn();
305
0
    }
306
0
    m2.AssertCurrentThreadIn();
307
0
    m2.Exit();
308
0
309
0
    m1.AssertCurrentThreadIn();
310
0
  }
311
0
  m1.AssertCurrentThreadIn();
312
0
  m1.Exit();
313
0
}