blob: d1704fb7e07b46421b1983368e16bdf7f40a2eb9 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package libcore.java.lang;
import junit.framework.TestCase;
public class OldAndroidMonitorTest extends TestCase {
public void testWaitArgumentsTest() throws Exception {
/* Try some valid arguments. These should all
* return very quickly.
*/
try {
synchronized (this) {
/* millisecond version */
wait(1);
wait(10);
/* millisecond + nanosecond version */
wait(0, 1);
wait(0, 999999);
wait(1, 1);
wait(1, 999999);
}
} catch (InterruptedException ex) {
throw new RuntimeException("good Object.wait() interrupted",
ex);
} catch (Exception ex) {
throw new RuntimeException("Unexpected exception when calling" +
"Object.wait() with good arguments", ex);
}
/* Try some invalid arguments.
*/
boolean sawException = false;
try {
synchronized (this) {
wait(-1);
}
} catch (InterruptedException ex) {
throw new RuntimeException("bad Object.wait() interrupted", ex);
} catch (IllegalArgumentException ex) {
sawException = true;
} catch (Exception ex) {
throw new RuntimeException("Unexpected exception when calling" +
"Object.wait() with bad arguments", ex);
}
if (!sawException) {
throw new RuntimeException("bad call to Object.wait() should " +
"have thrown IllegalArgumentException");
}
sawException = false;
try {
synchronized (this) {
wait(0, -1);
}
} catch (InterruptedException ex) {
throw new RuntimeException("bad Object.wait() interrupted", ex);
} catch (IllegalArgumentException ex) {
sawException = true;
} catch (Exception ex) {
throw new RuntimeException("Unexpected exception when calling" +
"Object.wait() with bad arguments", ex);
}
if (!sawException) {
throw new RuntimeException("bad call to Object.wait() should " +
"have thrown IllegalArgumentException");
}
sawException = false;
try {
synchronized (this) {
/* The legal range of nanos is 0-999999. */
wait(0, 1000000);
}
} catch (InterruptedException ex) {
throw new RuntimeException("bad Object.wait() interrupted", ex);
} catch (IllegalArgumentException ex) {
sawException = true;
} catch (Exception ex) {
throw new RuntimeException("Unexpected exception when calling" +
"Object.wait() with bad arguments", ex);
}
if (!sawException) {
throw new RuntimeException("bad call to Object.wait() should " +
"have thrown IllegalArgumentException");
}
}
private class Interrupter extends Thread {
Waiter waiter;
Interrupter(String name, Waiter waiter) {
super(name);
this.waiter = waiter;
}
public void run() {
try {
run_inner();
} catch (Throwable t) {
OldAndroidMonitorTest.errorException = t;
OldAndroidMonitorTest.testThread.interrupt();
}
}
void run_inner() {
waiter.spin = true;
// System.out.println("InterruptTest: starting waiter");
waiter.start();
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException ex) {
throw new RuntimeException("Test sleep interrupted.", ex);
}
/* Waiter is spinning, and its monitor should still be thin.
*/
// System.out.println("Test interrupting waiter");
waiter.interrupt();
waiter.spin = false;
for (int i = 0; i < 3; i++) {
/* Wait for the waiter to start waiting.
*/
synchronized (waiter.interrupterLock) {
try {
waiter.interrupterLock.wait();
} catch (InterruptedException ex) {
throw new RuntimeException("Test wait interrupted.", ex);
}
}
/* Before interrupting, grab the waiter lock, which
* guarantees that the waiter is already sitting in wait().
*/
synchronized (waiter) {
//System.out.println("Test interrupting waiter (" + i + ")");
waiter.interrupt();
}
}
// System.out.println("Test waiting for waiter to die.");
try {
waiter.join();
} catch (InterruptedException ex) {
throw new RuntimeException("Test join interrupted.", ex);
}
// System.out.println("InterruptTest done.");
}
}
private class Waiter extends Thread {
Object interrupterLock = new Object();
Boolean spin = false;
Waiter(String name) {
super(name);
}
public void run() {
try {
run_inner();
} catch (Throwable t) {
OldAndroidMonitorTest.errorException = t;
OldAndroidMonitorTest.testThread.interrupt();
}
}
void run_inner() {
// System.out.println("Waiter spinning");
while (spin) {
// We're going to get interrupted while we spin.
}
if (interrupted()) {
// System.out.println("Waiter done spinning; interrupted.");
} else {
throw new RuntimeException("Thread not interrupted " +
"during spin");
}
synchronized (this) {
Boolean sawEx = false;
try {
synchronized (interrupterLock) {
interrupterLock.notify();
}
// System.out.println("Waiter calling wait()");
this.wait();
} catch (InterruptedException ex) {
sawEx = true;
// System.out.println("wait(): Waiter caught " + ex);
}
// System.out.println("wait() finished");
if (!sawEx) {
throw new RuntimeException("Thread not interrupted " +
"during wait()");
}
}
synchronized (this) {
Boolean sawEx = false;
try {
synchronized (interrupterLock) {
interrupterLock.notify();
}
// System.out.println("Waiter calling wait(1000)");
this.wait(1000);
} catch (InterruptedException ex) {
sawEx = true;
// System.out.println("wait(1000): Waiter caught " + ex);
}
// System.out.println("wait(1000) finished");
if (!sawEx) {
throw new RuntimeException("Thread not interrupted " +
"during wait(1000)");
}
}
synchronized (this) {
Boolean sawEx = false;
try {
synchronized (interrupterLock) {
interrupterLock.notify();
}
// System.out.println("Waiter calling wait(1000, 5000)");
this.wait(1000, 5000);
} catch (InterruptedException ex) {
sawEx = true;
// System.out.println("wait(1000, 5000): Waiter caught " + ex);
}
// System.out.println("wait(1000, 5000) finished");
if (!sawEx) {
throw new RuntimeException("Thread not interrupted " +
"during wait(1000, 5000)");
}
}
// System.out.println("Waiter returning");
}
}
private static Throwable errorException;
private static Thread testThread;
// TODO: Flaky test. Add back MediumTest annotation once fixed
public void testInterruptTest() throws Exception {
testThread = Thread.currentThread();
errorException = null;
Waiter waiter = new Waiter("InterruptTest Waiter");
Interrupter interrupter =
new Interrupter("InterruptTest Interrupter", waiter);
interrupter.start();
try {
interrupter.join();
waiter.join();
} catch (InterruptedException ex) {
throw new RuntimeException("Test join interrupted.", ex);
}
if (errorException != null) {
throw new RuntimeException("InterruptTest failed",
errorException);
}
}
private static void deepWait(int depth, Object lock) {
synchronized (lock) {
if (depth > 0) {
deepWait(depth - 1, lock);
} else {
String threadName = Thread.currentThread().getName();
try {
// System.out.println(threadName + " waiting");
lock.wait();
// System.out.println(threadName + " done waiting");
} catch (InterruptedException ex) {
// System.out.println(threadName + " interrupted.");
}
}
}
}
private class Worker extends Thread {
Object lock;
int id;
Worker(int id, Object lock) {
super("Worker(" + id + ")");
this.id = id;
this.lock = lock;
}
public void run() {
int iterations = 0;
while (OldAndroidMonitorTest.running) {
OldAndroidMonitorTest.deepWait(id, lock);
iterations++;
}
// System.out.println(getName() + " done after " + iterations + " iterations.");
}
}
private static Object commonLock = new Object();
private static Boolean running = false;
public void testNestedMonitors() throws Exception {
final int NUM_WORKERS = 5;
Worker w[] = new Worker[NUM_WORKERS];
int i;
for (i = 0; i < NUM_WORKERS; i++) {
w[i] = new Worker(i * 2 - 1, new Object());
}
running = true;
// System.out.println("NestedMonitors: starting workers");
for (i = 0; i < NUM_WORKERS; i++) {
w[i].start();
}
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException ex) {
// System.out.println("Test sleep interrupted.");
}
for (i = 0; i < 100; i++) {
for (int j = 0; j < NUM_WORKERS; j++) {
synchronized (w[j].lock) {
w[j].lock.notify();
}
}
}
// System.out.println("NesterMonitors: stopping workers");
running = false;
for (i = 0; i < NUM_WORKERS; i++) {
synchronized (w[i].lock) {
w[i].lock.notifyAll();
}
}
}
private static class CompareAndExchange extends Thread {
static Object toggleLock = null;
static int toggle = -1;
static Boolean running = false;
public void run() {
toggleLock = new Object();
toggle = -1;
Worker w1 = new Worker(0, 1);
Worker w2 = new Worker(2, 3);
Worker w3 = new Worker(4, 5);
Worker w4 = new Worker(6, 7);
running = true;
// System.out.println("CompareAndExchange: starting workers");
w1.start();
w2.start();
w3.start();
w4.start();
try {
this.sleep(10000);
} catch (InterruptedException ex) {
// System.out.println(getName() + " interrupted.");
}
// System.out.println("MonitorTest: stopping workers");
running = false;
toggleLock = null;
}
class Worker extends Thread {
int i1;
int i2;
Worker(int i1, int i2) {
super("Worker(" + i1 + ", " + i2 + ")");
this.i1 = i1;
this.i2 = i2;
}
public void run() {
int iterations = 0;
/* Latch this because run() may set the static field to
* null at some point.
*/
Object toggleLock = CompareAndExchange.toggleLock;
// System.out.println(getName() + " running");
try {
while (CompareAndExchange.running) {
synchronized (toggleLock) {
int test;
int check;
if (CompareAndExchange.toggle == i1) {
this.sleep(5 + i2);
CompareAndExchange.toggle = test = i2;
} else {
this.sleep(5 + i1);
CompareAndExchange.toggle = test = i1;
}
if ((check = CompareAndExchange.toggle) != test) {
// System.out.println("Worker(" + i1 + ", " +
// i2 + ") " + "test " + test +
// " != toggle " + check);
throw new RuntimeException(
"locked value changed");
}
}
iterations++;
}
} catch (InterruptedException ex) {
// System.out.println(getName() + " interrupted.");
}
// System.out.println(getName() + " done after " +
// iterations + " iterations.");
}
}
}
}