зеркало из https://github.com/mozilla/pjs.git
344 строки
8.3 KiB
Java
344 строки
8.3 KiB
Java
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.0 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS"
|
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
* the License for the specific language governing rights and limitations
|
|
* under the License.
|
|
*
|
|
* The Original Code is the Grendel mail/news client.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
|
* Netscape Communications Corporation. All Rights Reserved.
|
|
*/
|
|
|
|
package calypso.util;
|
|
|
|
class SelfTestRWLock {
|
|
static void simpleReadTest(RWLock aLock)
|
|
throws InterruptedException
|
|
{
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.enterReadLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.exitReadLock();
|
|
}
|
|
}
|
|
|
|
static void simpleReadWriteTest(RWLock aLock)
|
|
throws InterruptedException
|
|
{
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.enterReadLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.enterWriteLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.exitWriteLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.exitReadLock();
|
|
}
|
|
}
|
|
|
|
static void simpleInvariantReadTest(RWLock aLock)
|
|
throws InterruptedException
|
|
{
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.enterInvariantReadLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.exitInvariantReadLock();
|
|
}
|
|
}
|
|
|
|
static void simpleInvariantReadWriteTest(RWLock aLock)
|
|
throws InterruptedException
|
|
{
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.enterInvariantReadLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.enterWriteLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.exitWriteLock();
|
|
}
|
|
for (int i = 0; i < 5; i++) {
|
|
aLock.exitInvariantReadLock();
|
|
}
|
|
}
|
|
|
|
// Verify that an out of order exit throws an error
|
|
static void outOfOrderExit0(RWLock aLock)
|
|
throws InterruptedException, SelfTestException
|
|
{
|
|
aLock.enterReadLock();
|
|
try {
|
|
aLock.exitWriteLock();
|
|
} catch (Error e) {
|
|
return;
|
|
}
|
|
throw new SelfTestException("whoops");
|
|
}
|
|
|
|
// Verify that an out of order exit throws an error
|
|
static void outOfOrderExit1(RWLock aLock)
|
|
throws InterruptedException, SelfTestException
|
|
{
|
|
aLock.enterReadLock();
|
|
try {
|
|
aLock.exitInvariantReadLock();
|
|
} catch (Error e) {
|
|
return;
|
|
}
|
|
throw new SelfTestException("whoops");
|
|
}
|
|
|
|
static void outOfOrderExit2(RWLock aLock)
|
|
throws InterruptedException, SelfTestException
|
|
{
|
|
aLock.enterInvariantReadLock();
|
|
try {
|
|
aLock.exitReadLock();
|
|
} catch (Error e) {
|
|
return;
|
|
}
|
|
throw new SelfTestException("whoops");
|
|
}
|
|
|
|
static void outOfOrderExit3(RWLock aLock)
|
|
throws InterruptedException, SelfTestException
|
|
{
|
|
aLock.enterInvariantReadLock();
|
|
try {
|
|
aLock.exitWriteLock();
|
|
} catch (Error e) {
|
|
return;
|
|
}
|
|
throw new SelfTestException("whoops");
|
|
}
|
|
|
|
static void outOfOrderExit4(RWLock aLock)
|
|
throws InterruptedException, SelfTestException
|
|
{
|
|
aLock.enterWriteLock();
|
|
try {
|
|
aLock.exitReadLock();
|
|
} catch (Error e) {
|
|
return;
|
|
}
|
|
throw new SelfTestException("whoops");
|
|
}
|
|
|
|
static void outOfOrderExit5(RWLock aLock)
|
|
throws InterruptedException, SelfTestException
|
|
{
|
|
aLock.enterWriteLock();
|
|
try {
|
|
aLock.exitInvariantReadLock();
|
|
} catch (Error e) {
|
|
return;
|
|
}
|
|
throw new SelfTestException("whoops");
|
|
}
|
|
|
|
public static void run()
|
|
throws SelfTestException
|
|
{
|
|
// Perform simple tests that have no contention with another thread
|
|
try {
|
|
simpleReadTest(new RWLock());
|
|
simpleReadWriteTest(new RWLock());
|
|
simpleInvariantReadTest(new RWLock());
|
|
simpleInvariantReadWriteTest(new RWLock());
|
|
|
|
outOfOrderExit0(new RWLock());
|
|
outOfOrderExit1(new RWLock());
|
|
outOfOrderExit2(new RWLock());
|
|
outOfOrderExit3(new RWLock());
|
|
outOfOrderExit4(new RWLock());
|
|
outOfOrderExit5(new RWLock());
|
|
|
|
verifyBlocking(new RWLock(), kRead, kWrite);
|
|
verifyBlocking(new RWLock(), kInvariantRead, kWrite);
|
|
verifyBlocking(new RWLock(), kWrite, kRead);
|
|
verifyBlocking(new RWLock(), kWrite, kInvariantRead);
|
|
|
|
stressTestContention(new RWLock());
|
|
} catch (InterruptedException e) {
|
|
// Test was interrupted
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
static final int kRead = 0;
|
|
static final int kWrite = 1;
|
|
static final int kInvariantRead = 2;
|
|
static String[] kStateToString = {
|
|
"read-lock", "write-lock", "invariant-read-lock"
|
|
};
|
|
|
|
// Verify that blocking is occuring by using the RWLock to
|
|
// protect the helper.fValue and guarantee a correct ordering
|
|
// of evaluation.
|
|
static void verifyBlocking(RWLock aLock, int aMe, int aHelper)
|
|
throws SelfTestException, InterruptedException
|
|
{
|
|
Enter(aLock, aMe);
|
|
|
|
RWTestHelper helper = new RWTestHelper(aLock, aHelper, 1, 1, 0);
|
|
Thread t1 = new Thread(helper);
|
|
t1.start();
|
|
|
|
// Make sure RWTestHelper is waiting to get the write-lock
|
|
Thread.sleep(500);
|
|
if (helper.fValue != 1) {
|
|
throw new SelfTestException("write-lock didn't block");
|
|
}
|
|
|
|
// Give RWTestHelper the lock; set value to 2 before it gets
|
|
// the lock
|
|
helper.fValue = 2;
|
|
Exit(aLock, aMe);
|
|
|
|
// make sure RWTestHelper is done
|
|
Thread.sleep(500);
|
|
if (helper.fValue != 0) {
|
|
throw new SelfTestException("helper didn't finish");
|
|
}
|
|
}
|
|
|
|
static void stressTestContention(RWLock aLock)
|
|
throws SelfTestException, InterruptedException
|
|
{
|
|
int count = 500000;
|
|
int delay = 123;
|
|
|
|
long start = System.currentTimeMillis();
|
|
|
|
// Fire up a bunch of threads
|
|
for (int i = 0; i < 3*100; i++) {
|
|
RWTestHelper helper = new RWTestHelper(aLock, i % 3, 1, count, delay);
|
|
Thread t = new Thread(helper);
|
|
t.start();
|
|
ThreadEnter();
|
|
}
|
|
|
|
ThreadWait();
|
|
long end = System.currentTimeMillis();
|
|
System.out.println("Stress test: duration=" + (end - start) + "ms");
|
|
}
|
|
|
|
static Object gThreadCounterLock = new Object();
|
|
static int gThreadCounter;
|
|
|
|
static void ThreadEnter()
|
|
throws InterruptedException
|
|
{
|
|
synchronized (gThreadCounterLock) {
|
|
gThreadCounter++;
|
|
}
|
|
}
|
|
|
|
static void ThreadExit()
|
|
throws InterruptedException
|
|
{
|
|
synchronized (gThreadCounterLock) {
|
|
if (--gThreadCounter == 0) {
|
|
gThreadCounterLock.notify();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ThreadWait()
|
|
throws InterruptedException
|
|
{
|
|
synchronized (gThreadCounterLock) {
|
|
while (gThreadCounter > 0) {
|
|
gThreadCounterLock.wait();
|
|
}
|
|
}
|
|
}
|
|
|
|
static final boolean noisy = false;
|
|
|
|
static void Enter(RWLock aLock, int aHow)
|
|
throws InterruptedException
|
|
{
|
|
if (noisy) {
|
|
System.out.println(Thread.currentThread() + ": enter " +
|
|
kStateToString[aHow]);
|
|
}
|
|
switch (aHow) {
|
|
case kRead:
|
|
aLock.enterReadLock();
|
|
break;
|
|
case kWrite:
|
|
aLock.enterWriteLock();
|
|
break;
|
|
case kInvariantRead:
|
|
aLock.enterInvariantReadLock();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void Exit(RWLock aLock, int aHow)
|
|
throws InterruptedException
|
|
{
|
|
if (noisy) {
|
|
System.out.println(Thread.currentThread() + ": exit " +
|
|
kStateToString[aHow]);
|
|
}
|
|
switch (aHow) {
|
|
case kRead:
|
|
aLock.exitReadLock();
|
|
break;
|
|
case kWrite:
|
|
aLock.exitWriteLock();
|
|
break;
|
|
case kInvariantRead:
|
|
aLock.exitInvariantReadLock();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static class RWTestHelper implements Runnable {
|
|
RWLock fLock;
|
|
int fHow;
|
|
int fValue;
|
|
int fCount;
|
|
int fDelay;
|
|
|
|
RWTestHelper(RWLock aLock, int aHow, int aValue, int aCount, int aDelay) {
|
|
fLock = aLock;
|
|
fHow = aHow;
|
|
fValue = aValue;
|
|
fCount = aCount;
|
|
fDelay = aDelay;
|
|
}
|
|
|
|
public void run() {
|
|
try {
|
|
for (int i = 0; i < fCount; i++) {
|
|
SelfTestRWLock.Enter(fLock, fHow);
|
|
fValue /= 4;
|
|
SelfTestRWLock.Exit(fLock, fHow);
|
|
if ((i % 1000) == 0) {
|
|
Thread.sleep(fDelay);
|
|
}
|
|
}
|
|
SelfTestRWLock.ThreadExit();
|
|
} catch (InterruptedException e) {
|
|
}
|
|
}
|
|
}
|
|
}
|