// Thread.java - Thread class. /* Copyright (C) 1998, 1999 Cygnus Solutions This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package java.lang; /** * @author Tom Tromey * @date August 24, 1998 */ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * "The Java Language Specification", ISBN 0-201-63451-1 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. * Status: Complete to version 1.1, with caveats * Known problems: * No attempt was made to implement suspend/resume * (this could be done in some cases) * Various methods which assume a VM are likewise unimplemented * We do implement stop() even though it is deprecated. */ public class Thread implements Runnable { public final static int MAX_PRIORITY = 10; public final static int MIN_PRIORITY = 1; public final static int NORM_PRIORITY = 5; public static int activeCount () { return currentThread().getThreadGroup().activeCount(); } public void checkAccess () { SecurityManager s = System.getSecurityManager(); if (s != null) s.checkAccess(this); } public native int countStackFrames (); public static native Thread currentThread (); public native void destroy (); public static native void dumpStack (); public static int enumerate (Thread[] threads) { return currentThread().group.enumerate(threads); } public final String getName () { return name; } public final int getPriority () { return priority; } public final ThreadGroup getThreadGroup () { return group; } public native void interrupt (); public static boolean interrupted () { return currentThread().isInterrupted(); } // FIXME: it seems to me that this should be synchronized. public boolean isInterrupted () { boolean r = interrupt_flag; interrupt_flag = false; return r; } public final boolean isAlive () { return alive_flag; } public final boolean isDaemon () { return daemon_flag; } public final void join () throws InterruptedException { join (0, 0); } public final void join (long timeout) throws InterruptedException { join (timeout, 0); } public final native void join (long timeout, int nanos) throws InterruptedException; public final native void resume (); // This method exists only to avoid a warning from the C++ compiler. private static final native void run__ (Object obj); private native final void finish_ (); private final void run_ () { try { run (); } catch (Throwable e) { // Uncaught exceptions are forwarded to the ThreadGroup. If // this results in an uncaught exception, that is ignored. try { group.uncaughtException(this, e); } catch (Throwable f) { // Nothing. } } finish_ (); } public void run () { if (runnable != null) runnable.run(); } public final void setDaemon (boolean status) { checkAccess (); if (isAlive ()) throw new IllegalThreadStateException (); daemon_flag = status; } // TODO12: // public ClassLoader getContextClassLoader() // { // } // TODO12: // public void setContextClassLoader(ClassLoader cl) // { // } public final void setName (String n) { checkAccess (); // The Class Libraries book says ``threadName cannot be null''. I // take this to mean NullPointerException. if (n == null) throw new NullPointerException (); name = n; } public final native void setPriority (int newPriority); public static void sleep (long timeout) throws InterruptedException { sleep (timeout, 0); } public static native void sleep (long timeout, int nanos) throws InterruptedException; public synchronized native void start (); public final void stop () { stop (new ThreadDeath ()); } public final synchronized native void stop (Throwable e); public final native void suspend (); private final native void initialize_native (); private final synchronized static String gen_name () { String n; n = "Thread-" + nextThreadNumber; ++nextThreadNumber; return n; } public Thread (ThreadGroup g, Runnable r, String n) { // Note that CURRENT can be null when we are creating the very // first thread. That's why we check it below. Thread current = currentThread (); if (g != null) { // If CURRENT is null, then we are creating the first thread. // In this case we don't do the security check. if (current != null) g.checkAccess(); } else g = current.getThreadGroup(); // The Class Libraries book says ``threadName cannot be null''. I // take this to mean NullPointerException. if (n == null) throw new NullPointerException (); name = n; group = g; g.add(this); runnable = r; data = null; interrupt_flag = false; alive_flag = false; if (current != null) { daemon_flag = current.isDaemon(); priority = current.getPriority(); } else { daemon_flag = false; priority = NORM_PRIORITY; } initialize_native (); } public Thread () { this (null, null, gen_name ()); } public Thread (Runnable r) { this (null, r, gen_name ()); } public Thread (String n) { this (null, null, n); } public Thread (ThreadGroup g, Runnable r) { this (g, r, gen_name ()); } public Thread (ThreadGroup g, String n) { this (g, null, n); } public Thread (Runnable r, String n) { this (null, r, n); } public String toString () { return "Thread[" + name + "," + priority + "," + group.getName() + "]"; } public static native void yield (); // Private data. private ThreadGroup group; private String name; private Runnable runnable; private int priority; private boolean daemon_flag; private boolean interrupt_flag; private boolean alive_flag; // This is a bit odd. We need a way to represent some data that is // manipulated only by the native side of this class. We represent // it as a Java object reference. However, it is not actually a // Java object. private Object data; // Next thread number to assign. private static int nextThreadNumber = 0; }