| // Thread.java - Thread class. |
| |
| /* Copyright (C) 1998, 1999, 2000 Free Software Foundation |
| |
| 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: Believed complete to version 1.3, with caveats. We do not |
| * implement the deprecated (and dangerous) stop, suspend, and resume |
| * methods. Security implementation is not complete. |
| */ |
| |
| 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 final 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 void dumpStack () |
| { |
| (new Exception ("Stack trace")).printStackTrace (); |
| } |
| |
| 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 (true); |
| } |
| |
| // Check the threads interrupted status. Note that this does not clear the |
| // thread's interrupted status (per JDK 1.2 online API documentation). |
| public boolean isInterrupted () |
| { |
| return interrupt_flag; |
| } |
| |
| 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 final native void finish_ (); |
| |
| // Check the thread's interrupted status. If clear_flag is true, the |
| // thread's interrupted status is also cleared. |
| private boolean isInterrupted (boolean clear_flag) |
| { |
| boolean r = interrupt_flag; |
| if (clear_flag && r) |
| { |
| // Only clear the flag if we saw it as set. Otherwise this could |
| // potentially cause us to miss an interrupt in a race condition, |
| // because this method is not synchronized. |
| interrupt_flag = false; |
| } |
| return r; |
| } |
| |
| public void run () |
| { |
| if (runnable != null) |
| runnable.run(); |
| } |
| |
| public final void setDaemon (boolean status) |
| { |
| checkAccess (); |
| if (isAlive ()) |
| throw new IllegalThreadStateException (); |
| daemon_flag = status; |
| } |
| |
| public synchronized ClassLoader getContextClassLoader() |
| { |
| if (context_class_loader == null) |
| context_class_loader = ClassLoader.getSystemClassLoader (); |
| |
| SecurityManager s = System.getSecurityManager(); |
| // FIXME: we can't currently find the caller's class loader. |
| ClassLoader callers = null; |
| if (s != null && callers != null) |
| { |
| // See if the caller's class loader is the same as or an |
| // ancestor of this thread's class loader. |
| while (callers != null && callers != context_class_loader) |
| { |
| // FIXME: should use some internal version of getParent |
| // that avoids security checks. |
| callers = callers.getParent (); |
| } |
| |
| if (callers != context_class_loader) |
| s.checkPermission (new RuntimePermission ("getClassLoader")); |
| } |
| |
| return context_class_loader; |
| } |
| |
| public synchronized void setContextClassLoader(ClassLoader cl) |
| { |
| SecurityManager s = System.getSecurityManager (); |
| if (s != null) |
| s.checkPermission (new RuntimePermission ("setContextClassLoader")); |
| context_class_loader = 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 () |
| { |
| // Argument doesn't matter, because this is no longer |
| // supported. |
| stop (null); |
| } |
| |
| 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) |
| { |
| Thread current = currentThread (); |
| |
| if (g == null) |
| { |
| // If CURRENT is null, then we are bootstrapping the first thread. |
| // Use ThreadGroup.root, the main threadgroup. |
| if (current == null) |
| group = ThreadGroup.root; |
| else |
| group = current.getThreadGroup(); |
| } |
| else |
| group = g; |
| |
| group.checkAccess(); |
| |
| // The Class Libraries book says ``threadName cannot be null''. I |
| // take this to mean NullPointerException. |
| if (n == null) |
| throw new NullPointerException (); |
| |
| name = n; |
| group.addThread(this); |
| runnable = r; |
| |
| data = null; |
| interrupt_flag = false; |
| alive_flag = false; |
| startable_flag = true; |
| |
| if (current != null) |
| { |
| daemon_flag = current.isDaemon(); |
| int gmax = group.getMaxPriority(); |
| int pri = current.getPriority(); |
| priority = (gmax < pri ? gmax : pri); |
| context_class_loader = current.context_class_loader; |
| } |
| 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 == null ? "" : 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; |
| boolean interrupt_flag; |
| private boolean alive_flag; |
| private boolean startable_flag; |
| private ClassLoader context_class_loader; |
| |
| // Our native data. |
| private Object data; |
| |
| // Next thread number to assign. |
| private static int nextThreadNumber = 0; |
| } |