gecko-dev/xpcom/tests/TestSynchronization.cpp

388 строки
8.1 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TestHarness.h"
#include "mozilla/CondVar.h"
#include "mozilla/Monitor.h"
#include "mozilla/Mutex.h"
#include "nsAutoLock.h"
using namespace mozilla;
static PRThread*
spawn(void (*run)(void*), void* arg)
{
return PR_CreateThread(PR_SYSTEM_THREAD,
run,
arg,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0);
}
#define PASS() \
do { \
passed(__FUNCTION__); \
return NS_OK; \
} while (0)
#define FAIL(why) \
do { \
fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \
return NS_ERROR_FAILURE; \
} while (0)
//-----------------------------------------------------------------------------
// Sanity check: tests that can be done on a single thread
//
static nsresult
Sanity()
{
Mutex lock("sanity::lock");
lock.Lock();
lock.AssertCurrentThreadOwns();
lock.Unlock();
{
MutexAutoLock autolock(lock);
lock.AssertCurrentThreadOwns();
}
lock.Lock();
lock.AssertCurrentThreadOwns();
{
MutexAutoUnlock autounlock(lock);
}
lock.AssertCurrentThreadOwns();
lock.Unlock();
Monitor mon("sanity::monitor");
mon.Enter();
mon.AssertCurrentThreadIn();
mon.Enter();
mon.AssertCurrentThreadIn();
mon.Exit();
mon.AssertCurrentThreadIn();
mon.Exit();
{
MonitorAutoEnter automon(mon);
mon.AssertCurrentThreadIn();
}
PASS();
}
//-----------------------------------------------------------------------------
// Mutex contention tests
//
static Mutex* gLock1;
static void
MutexContention_thread(void* /*arg*/)
{
for (int i = 0; i < 100000; ++i) {
gLock1->Lock();
gLock1->AssertCurrentThreadOwns();
gLock1->Unlock();
}
}
static nsresult
MutexContention()
{
gLock1 = new Mutex("lock1");
// PURPOSELY not checking for OOM. YAY!
PRThread* t1 = spawn(MutexContention_thread, nullptr);
PRThread* t2 = spawn(MutexContention_thread, nullptr);
PRThread* t3 = spawn(MutexContention_thread, nullptr);
PR_JoinThread(t1);
PR_JoinThread(t2);
PR_JoinThread(t3);
delete gLock1;
PASS();
}
//-----------------------------------------------------------------------------
// Monitor tests
//
static Monitor* gMon1;
static void
MonitorContention_thread(void* /*arg*/)
{
for (int i = 0; i < 100000; ++i) {
gMon1->Enter();
gMon1->AssertCurrentThreadIn();
gMon1->Exit();
}
}
static nsresult
MonitorContention()
{
gMon1 = new Monitor("mon1");
PRThread* t1 = spawn(MonitorContention_thread, nullptr);
PRThread* t2 = spawn(MonitorContention_thread, nullptr);
PRThread* t3 = spawn(MonitorContention_thread, nullptr);
PR_JoinThread(t1);
PR_JoinThread(t2);
PR_JoinThread(t3);
delete gMon1;
PASS();
}
static Monitor* gMon2;
static void
MonitorContention2_thread(void* /*arg*/)
{
for (int i = 0; i < 100000; ++i) {
gMon2->Enter();
gMon2->AssertCurrentThreadIn();
{
gMon2->Enter();
gMon2->AssertCurrentThreadIn();
gMon2->Exit();
}
gMon2->AssertCurrentThreadIn();
gMon2->Exit();
}
}
static nsresult
MonitorContention2()
{
gMon2 = new Monitor("mon1");
PRThread* t1 = spawn(MonitorContention2_thread, nullptr);
PRThread* t2 = spawn(MonitorContention2_thread, nullptr);
PRThread* t3 = spawn(MonitorContention2_thread, nullptr);
PR_JoinThread(t1);
PR_JoinThread(t2);
PR_JoinThread(t3);
delete gMon2;
PASS();
}
static Monitor* gMon3;
static int32_t gMonFirst;
static void
MonitorSyncSanity_thread(void* /*arg*/)
{
gMon3->Enter();
gMon3->AssertCurrentThreadIn();
if (gMonFirst) {
gMonFirst = 0;
gMon3->Wait();
gMon3->Enter();
} else {
gMon3->Notify();
gMon3->Enter();
}
gMon3->AssertCurrentThreadIn();
gMon3->Exit();
gMon3->AssertCurrentThreadIn();
gMon3->Exit();
}
static nsresult
MonitorSyncSanity()
{
gMon3 = new Monitor("monitor::syncsanity");
for (int32_t i = 0; i < 10000; ++i) {
gMonFirst = 1;
PRThread* ping = spawn(MonitorSyncSanity_thread, nullptr);
PRThread* pong = spawn(MonitorSyncSanity_thread, nullptr);
PR_JoinThread(ping);
PR_JoinThread(pong);
}
delete gMon3;
PASS();
}
//-----------------------------------------------------------------------------
// Condvar tests
//
static Mutex* gCvlock1;
static CondVar* gCv1;
static int32_t gCvFirst;
static void
CondVarSanity_thread(void* /*arg*/)
{
gCvlock1->Lock();
gCvlock1->AssertCurrentThreadOwns();
if (gCvFirst) {
gCvFirst = 0;
gCv1->Wait();
} else {
gCv1->Notify();
}
gCvlock1->AssertCurrentThreadOwns();
gCvlock1->Unlock();
}
static nsresult
CondVarSanity()
{
gCvlock1 = new Mutex("cvlock1");
gCv1 = new CondVar(*gCvlock1, "cvlock1");
for (int32_t i = 0; i < 10000; ++i) {
gCvFirst = 1;
PRThread* ping = spawn(CondVarSanity_thread, nullptr);
PRThread* pong = spawn(CondVarSanity_thread, nullptr);
PR_JoinThread(ping);
PR_JoinThread(pong);
}
delete gCv1;
delete gCvlock1;
PASS();
}
//-----------------------------------------------------------------------------
// AutoLock tests
//
static nsresult
AutoLock()
{
Mutex l1("autolock");
MutexAutoLock autol1(l1);
l1.AssertCurrentThreadOwns();
{
Mutex l2("autolock2");
MutexAutoLock autol2(l2);
l1.AssertCurrentThreadOwns();
l2.AssertCurrentThreadOwns();
}
l1.AssertCurrentThreadOwns();
PASS();
}
//-----------------------------------------------------------------------------
// AutoUnlock tests
//
static nsresult
AutoUnlock()
{
Mutex l1("autounlock");
Mutex l2("autounlock2");
l1.Lock();
l1.AssertCurrentThreadOwns();
{
MutexAutoUnlock autol1(l1);
{
l2.Lock();
l2.AssertCurrentThreadOwns();
MutexAutoUnlock autol2(l2);
}
l2.AssertCurrentThreadOwns();
l2.Unlock();
}
l1.AssertCurrentThreadOwns();
l1.Unlock();
PASS();
}
//-----------------------------------------------------------------------------
// AutoMonitor tests
//
static nsresult
AutoMonitor()
{
Monitor m1("automonitor");
Monitor m2("automonitor2");
m1.Enter();
m1.AssertCurrentThreadIn();
{
MonitorAutoEnter autom1(m1);
m1.AssertCurrentThreadIn();
m2.Enter();
m2.AssertCurrentThreadIn();
{
MonitorAutoEnter autom2(m2);
m1.AssertCurrentThreadIn();
m2.AssertCurrentThreadIn();
}
m2.AssertCurrentThreadIn();
m2.Exit();
m1.AssertCurrentThreadIn();
}
m1.AssertCurrentThreadIn();
m1.Exit();
PASS();
}
//-----------------------------------------------------------------------------
int
main(int argc, char** argv)
{
ScopedXPCOM xpcom("Synchronization (" __FILE__ ")");
if (xpcom.failed())
return 1;
int rv = 0;
if (NS_FAILED(Sanity()))
rv = 1;
if (NS_FAILED(MutexContention()))
rv = 1;
if (NS_FAILED(MonitorContention()))
rv = 1;
if (NS_FAILED(MonitorContention2()))
rv = 1;
if (NS_FAILED(MonitorSyncSanity()))
rv = 1;
if (NS_FAILED(CondVarSanity()))
rv = 1;
if (NS_FAILED(AutoLock()))
rv = 1;
if (NS_FAILED(AutoUnlock()))
rv = 1;
if (NS_FAILED(AutoMonitor()))
rv = 1;
return rv;
}