import java.util.*;
import java.io.*;

public class ThreadState extends Thread {
  public final static int DEFAULT_NUMTHREADS = 10;
  boolean childRunning;
  static PrintStream p;

  // Test thread states
  public static void main(String args[]) throws Exception {
    int numThreads;
    int index = 0;

    if (args.length > 0 && args[0].equals("-v")) {
      p = System.out;
      index = 1;
    }

    try {
      numThreads = Integer.parseInt(args[index]);
    } catch (Exception e) {
      numThreads = DEFAULT_NUMTHREADS;
    }

    Thread[] threads = new Thread[numThreads];
    for (int i = 0; i < numThreads; i++) {
      threads[i] = new ThreadState();
      verbose("main starting " + threads[i].getName());
      threads[i].start();
    }
    for (int i = 0; i < numThreads; i++) {
      try {
	verbose("main joining " + threads[i].getName());
	threads[i].join();
      } catch (InterruptedException e) {
	assert(false, "main " + e);
      }
    }
  }

  public void run() {
    verbose(getName() + " running");

    // Create child thread
    Thread t = new Thread() {
      public synchronized void run() {
	childRunning = true;
	verbose(ThreadState.this.getName() + " child running [child]");
	try {
	  wait(0);
	} catch (InterruptedException e) {
	  assert(false, "thread " + e);
	}
	verbose(ThreadState.this.getName() + " child thread exiting");
      }
    };

    // Check state
    assert(!t.isAlive(), "alive before start()");
    verbose(getName() + " starting child thread");
    t.start();
    assert(t.isAlive(), "dead after start()");

    // Check double start()
    try {
      t.start();
      assert(false, "start() while alive");
    } catch (IllegalThreadStateException e) {
    }

    // Wait for thread to be running
    while (!childRunning) {
      Thread.yield();
    }
    verbose(getName() + " child thread running [parent]");

    // Notify child he can exit
    synchronized (t) {
      t.notify();
    }

    verbose(getName() + " joining my child thread");
    try {
      t.join();
    } catch (InterruptedException e) {
      assert(false, "join: " + e);
    }
    assert(!t.isAlive(), "alive after join()");

    // Check double start()
    try {
      t.start();
      assert(false, "start() after dead");
    } catch (IllegalThreadStateException e) {
    }

    // OK
    synchronized (ThreadState.class) {
      System.out.println("Success.");
    }
    verbose(getName() + " exiting");
  }

  public static void assert(boolean that, String msg) {
    if (!that) {
      System.err.println("Failure: " + msg);
      System.exit(1);
    }
  }

  public static void verbose(String msg) {
    if (p != null) {
      p.println(msg);
      p.flush();
    }
  }
}

/* Expected Output:
Success.
Success.
Success.
Success.
Success.
Success.
Success.
Success.
Success.
Success.
*/

@@ -1212,16 +1212,21 @@
 ry %7B%0A%09  
+this.
 wait(0);
@@ -1557,24 +1557,198 @@
 start()%22);%0A%0A
+    // Check setDaemon after start()%0A    try %7B%0A      t.setDaemon(false);%0A      assert(false, %22setDaemon() after start%22);%0A    %7D catch (IllegalThreadStateException e) %7B%0A    %7D%0A%0A
     // Check

Check for setDaemon after start() (which is illegal).