298 lines
6.3 KiB
Java
298 lines
6.3 KiB
Java
|
// 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 <tromey@cygnus.com>
|
||
|
* @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;
|
||
|
}
|