+// This test grew a bit more elaborate than anticipated...
+// It verifies that the JVM handles properly the case of a thread being
+// interrupted and notified at the same time.
+
+public class waitAndInterrupt {
+ private class semaphore {
+ private int v;
+ public semaphore(int v) {
+ this.v = v;
+ }
+ public synchronized void semwait() {
+ while (v == 0)
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ v--;
+ }
+ public synchronized void sempost() {
+ if (v == 0)
+ notify();
+ v++;
+ }
+ }
+
+ public static class firstthread implements Runnable {
+ private waitAndInterrupt s;
+
+ public firstthread(waitAndInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ boolean iAmFirst = Thread.currentThread() == s.t1;
+ try {
+ int i = 0;
+ int count_not = 0;
+ int count_int = 0;
+ for (;;) {
+ if (iAmFirst) {
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running, notified " + Integer.toString(count_not) + ", interrupted " + Integer.toString(count_int));
+ }
+ synchronized (s) {
+ s.sem1.sempost();
+ try {
+ while (!s.notified)
+ s.wait();
+ try {
+ s.wait();
+ } catch (InterruptedException e) {
+ s.notify(); // wake t2
+ }
+ count_not++;
+ } catch (InterruptedException e) {
+ count_int++;
+ }
+ }
+
+ s.sem5.sempost();
+ s.sem8.semwait();
+ } else {
+ s.sem1.semwait();
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running");
+ }
+ synchronized (s) {
+ s.sem2.sempost();
+ try {
+ while (!s.notified)
+ s.wait();
+ s.notified = false;
+ count_not++;
+ } catch (InterruptedException e) {
+ count_int++;
+ }
+ }
+
+ s.sem6.sempost();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static class otherthread implements Runnable {
+ private waitAndInterrupt s;
+
+ public otherthread(waitAndInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ boolean iAmFirst = Thread.currentThread() == s.t3;
+ try {
+ int i = 0;
+ for (;;) {
+ if (iAmFirst) {
+ s.sem3.semwait();
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running");
+ }
+ synchronized (s) {
+ s.sem4.sempost();
+ }
+ s.t1.interrupt();
+ s.sem5.semwait();
+ } else {
+ s.sem4.semwait();
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running");
+ }
+ synchronized (s) {
+ if (s.notified)
+ System.out.println("shouldn't happen (1)");
+ s.notified = true;
+ s.notify();
+ }
+ s.sem6.semwait();
+ }
+ s.sem7.sempost();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static class controlthread implements Runnable {
+ private waitAndInterrupt s;
+
+ public controlthread(waitAndInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ try {
+ for (;;) {
+ s.sem2.semwait();
+ synchronized (s) {
+ }
+ s.sem3.sempost();
+ s.sem7.semwait();
+ s.sem7.semwait();
+ s.sem8.sempost(); // wake first
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public Thread t1 = null;
+ public Thread t2 = null;
+ public Thread t3 = null;
+ public Thread t4 = null;
+ public semaphore sem1 = new semaphore(0);
+ public semaphore sem2 = new semaphore(0);
+ public semaphore sem3 = new semaphore(0);
+ public semaphore sem4 = new semaphore(0);
+ public semaphore sem5 = new semaphore(0);
+ public semaphore sem6 = new semaphore(0);
+ public semaphore sem7 = new semaphore(0);
+ public semaphore sem8 = new semaphore(0);
+ public boolean notified = false;
+
+ public static void main(String args[]) {
+ waitAndInterrupt s = new waitAndInterrupt();
+ firstthread r1 = new firstthread(s);
+ firstthread r2 = new firstthread(s);
+ otherthread r3 = new otherthread(s);
+ controlthread r5 = new controlthread(s);
+
+ s.t1 = new Thread(r1, "a");
+ s.t2 = new Thread(r2, "b");
+ s.t3 = new Thread(r3, "c");
+ s.t4 = new Thread(r3, "d");
+ Thread t5 = new Thread(r5, "e");
+ s.t1.start();
+ s.t2.start();
+ s.t3.start();
+ s.t4.start();
+ t5.start();
+ }
+}
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: java
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */