| 1 | // Thread.java - Thread class.
|
|---|
| 2 |
|
|---|
| 3 | /* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation
|
|---|
| 4 |
|
|---|
| 5 | This file is part of libgcj.
|
|---|
| 6 |
|
|---|
| 7 | This software is copyrighted work licensed under the terms of the
|
|---|
| 8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|---|
| 9 | details. */
|
|---|
| 10 |
|
|---|
| 11 | package java.lang;
|
|---|
| 12 |
|
|---|
| 13 | /**
|
|---|
| 14 | * @author Tom Tromey <[email protected]>
|
|---|
| 15 | * @date August 24, 1998
|
|---|
| 16 | */
|
|---|
| 17 |
|
|---|
| 18 | /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
|
|---|
| 19 | * "The Java Language Specification", ISBN 0-201-63451-1
|
|---|
| 20 | * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
|
|---|
| 21 | * Status: Believed complete to version 1.3, with caveats. We do not
|
|---|
| 22 | * implement the deprecated (and dangerous) stop, suspend, and resume
|
|---|
| 23 | * methods. Security implementation is not complete.
|
|---|
| 24 | */
|
|---|
| 25 |
|
|---|
| 26 | public class Thread implements Runnable
|
|---|
| 27 | {
|
|---|
| 28 | public final static int MAX_PRIORITY = 10;
|
|---|
| 29 | public final static int MIN_PRIORITY = 1;
|
|---|
| 30 | public final static int NORM_PRIORITY = 5;
|
|---|
| 31 |
|
|---|
| 32 | public static int activeCount ()
|
|---|
| 33 | {
|
|---|
| 34 | return currentThread().getThreadGroup().activeCount();
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | public final void checkAccess ()
|
|---|
| 38 | {
|
|---|
| 39 | SecurityManager s = System.getSecurityManager();
|
|---|
| 40 | if (s != null)
|
|---|
| 41 | s.checkAccess(this);
|
|---|
| 42 | }
|
|---|
| 43 |
|
|---|
| 44 | public native int countStackFrames ();
|
|---|
| 45 | public static native Thread currentThread ();
|
|---|
| 46 | public native void destroy ();
|
|---|
| 47 |
|
|---|
| 48 | public static void dumpStack ()
|
|---|
| 49 | {
|
|---|
| 50 | (new Exception ("Stack trace")).printStackTrace ();
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | public static int enumerate (Thread[] threads)
|
|---|
| 54 | {
|
|---|
| 55 | return currentThread().group.enumerate(threads);
|
|---|
| 56 | }
|
|---|
| 57 |
|
|---|
| 58 | public final String getName ()
|
|---|
| 59 | {
|
|---|
| 60 | return name;
|
|---|
| 61 | }
|
|---|
| 62 |
|
|---|
| 63 | public final int getPriority ()
|
|---|
| 64 | {
|
|---|
| 65 | return priority;
|
|---|
| 66 | }
|
|---|
| 67 |
|
|---|
| 68 | public final ThreadGroup getThreadGroup ()
|
|---|
| 69 | {
|
|---|
| 70 | return group;
|
|---|
| 71 | }
|
|---|
| 72 |
|
|---|
| 73 | public native void interrupt ();
|
|---|
| 74 |
|
|---|
| 75 | public static boolean interrupted ()
|
|---|
| 76 | {
|
|---|
| 77 | return currentThread().isInterrupted (true);
|
|---|
| 78 | }
|
|---|
| 79 |
|
|---|
| 80 | // Check the threads interrupted status. Note that this does not clear the
|
|---|
| 81 | // thread's interrupted status (per JDK 1.2 online API documentation).
|
|---|
| 82 | public boolean isInterrupted ()
|
|---|
| 83 | {
|
|---|
| 84 | return interrupt_flag;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | public final boolean isAlive ()
|
|---|
| 88 | {
|
|---|
| 89 | return alive_flag;
|
|---|
| 90 | }
|
|---|
| 91 |
|
|---|
| 92 | public final boolean isDaemon ()
|
|---|
| 93 | {
|
|---|
| 94 | return daemon_flag;
|
|---|
| 95 | }
|
|---|
| 96 |
|
|---|
| 97 | public final void join () throws InterruptedException
|
|---|
| 98 | {
|
|---|
| 99 | join (0, 0);
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | public final void join (long timeout) throws InterruptedException
|
|---|
| 103 | {
|
|---|
| 104 | join (timeout, 0);
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | public final native void join (long timeout, int nanos)
|
|---|
| 108 | throws InterruptedException;
|
|---|
| 109 |
|
|---|
| 110 | public final native void resume ();
|
|---|
| 111 |
|
|---|
| 112 | private final native void finish_ ();
|
|---|
| 113 |
|
|---|
| 114 | // Check the thread's interrupted status. If clear_flag is true, the
|
|---|
| 115 | // thread's interrupted status is also cleared.
|
|---|
| 116 | private boolean isInterrupted (boolean clear_flag)
|
|---|
| 117 | {
|
|---|
| 118 | boolean r = interrupt_flag;
|
|---|
| 119 | if (clear_flag && r)
|
|---|
| 120 | {
|
|---|
| 121 | // Only clear the flag if we saw it as set. Otherwise this could
|
|---|
| 122 | // potentially cause us to miss an interrupt in a race condition,
|
|---|
| 123 | // because this method is not synchronized.
|
|---|
| 124 | interrupt_flag = false;
|
|---|
| 125 | }
|
|---|
| 126 | return r;
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | public void run ()
|
|---|
| 130 | {
|
|---|
| 131 | if (runnable != null)
|
|---|
| 132 | runnable.run();
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 | public final void setDaemon (boolean status)
|
|---|
| 136 | {
|
|---|
| 137 | checkAccess ();
|
|---|
| 138 | if (isAlive ())
|
|---|
| 139 | throw new IllegalThreadStateException ();
|
|---|
| 140 | daemon_flag = status;
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | public synchronized ClassLoader getContextClassLoader()
|
|---|
| 144 | {
|
|---|
| 145 | if (context_class_loader == null)
|
|---|
| 146 | context_class_loader = ClassLoader.getSystemClassLoader ();
|
|---|
| 147 |
|
|---|
| 148 | SecurityManager s = System.getSecurityManager();
|
|---|
| 149 | // FIXME: we can't currently find the caller's class loader.
|
|---|
| 150 | ClassLoader callers = null;
|
|---|
| 151 | if (s != null && callers != null)
|
|---|
| 152 | {
|
|---|
| 153 | // See if the caller's class loader is the same as or an
|
|---|
| 154 | // ancestor of this thread's class loader.
|
|---|
| 155 | while (callers != null && callers != context_class_loader)
|
|---|
| 156 | {
|
|---|
| 157 | // FIXME: should use some internal version of getParent
|
|---|
| 158 | // that avoids security checks.
|
|---|
| 159 | callers = callers.getParent ();
|
|---|
| 160 | }
|
|---|
| 161 |
|
|---|
| 162 | if (callers != context_class_loader)
|
|---|
| 163 | s.checkPermission (new RuntimePermission ("getClassLoader"));
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | return context_class_loader;
|
|---|
| 167 | }
|
|---|
| 168 |
|
|---|
| 169 | public synchronized void setContextClassLoader(ClassLoader cl)
|
|---|
| 170 | {
|
|---|
| 171 | SecurityManager s = System.getSecurityManager ();
|
|---|
| 172 | if (s != null)
|
|---|
| 173 | s.checkPermission (new RuntimePermission ("setContextClassLoader"));
|
|---|
| 174 | context_class_loader = cl;
|
|---|
| 175 | }
|
|---|
| 176 |
|
|---|
| 177 | public final void setName (String n)
|
|---|
| 178 | {
|
|---|
| 179 | checkAccess ();
|
|---|
| 180 | // The Class Libraries book says ``threadName cannot be null''. I
|
|---|
| 181 | // take this to mean NullPointerException.
|
|---|
| 182 | if (n == null)
|
|---|
| 183 | throw new NullPointerException ();
|
|---|
| 184 | name = n;
|
|---|
| 185 | }
|
|---|
| 186 |
|
|---|
| 187 | public final native void setPriority (int newPriority);
|
|---|
| 188 |
|
|---|
| 189 | public static void sleep (long timeout) throws InterruptedException
|
|---|
| 190 | {
|
|---|
| 191 | sleep (timeout, 0);
|
|---|
| 192 | }
|
|---|
| 193 |
|
|---|
| 194 | public static native void sleep (long timeout, int nanos)
|
|---|
| 195 | throws InterruptedException;
|
|---|
| 196 | public native void start ();
|
|---|
| 197 |
|
|---|
| 198 | public final void stop ()
|
|---|
| 199 | {
|
|---|
| 200 | // Argument doesn't matter, because this is no longer
|
|---|
| 201 | // supported.
|
|---|
| 202 | stop (null);
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | public final native void stop (Throwable e);
|
|---|
| 206 | public final native void suspend ();
|
|---|
| 207 |
|
|---|
| 208 | private final native void initialize_native ();
|
|---|
| 209 |
|
|---|
| 210 | private final native static String gen_name ();
|
|---|
| 211 |
|
|---|
| 212 | public Thread (ThreadGroup g, Runnable r, String n)
|
|---|
| 213 | {
|
|---|
| 214 | this (currentThread (), g, r, n);
|
|---|
| 215 |
|
|---|
| 216 | // The Class Libraries book says ``threadName cannot be null''. I
|
|---|
| 217 | // take this to mean NullPointerException.
|
|---|
| 218 | if (n == null)
|
|---|
| 219 | throw new NullPointerException ();
|
|---|
| 220 | }
|
|---|
| 221 |
|
|---|
| 222 | private Thread (Thread current, ThreadGroup g, Runnable r, String n)
|
|---|
| 223 | {
|
|---|
| 224 | if (g == null)
|
|---|
| 225 | {
|
|---|
| 226 | // If CURRENT is null, then we are bootstrapping the first thread.
|
|---|
| 227 | // Use ThreadGroup.root, the main threadgroup.
|
|---|
| 228 | if (current == null)
|
|---|
| 229 | group = ThreadGroup.root;
|
|---|
| 230 | else
|
|---|
| 231 | group = current.getThreadGroup();
|
|---|
| 232 | }
|
|---|
| 233 | else
|
|---|
| 234 | group = g;
|
|---|
| 235 |
|
|---|
| 236 | data = null;
|
|---|
| 237 | interrupt_flag = false;
|
|---|
| 238 | alive_flag = false;
|
|---|
| 239 | startable_flag = true;
|
|---|
| 240 |
|
|---|
| 241 | if (current != null)
|
|---|
| 242 | {
|
|---|
| 243 | group.checkAccess();
|
|---|
| 244 |
|
|---|
| 245 | daemon_flag = current.isDaemon();
|
|---|
| 246 | int gmax = group.getMaxPriority();
|
|---|
| 247 | int pri = current.getPriority();
|
|---|
| 248 | priority = (gmax < pri ? gmax : pri);
|
|---|
| 249 | context_class_loader = current.context_class_loader;
|
|---|
| 250 | InheritableThreadLocal.newChildThread(this);
|
|---|
| 251 | }
|
|---|
| 252 | else
|
|---|
| 253 | {
|
|---|
| 254 | daemon_flag = false;
|
|---|
| 255 | priority = NORM_PRIORITY;
|
|---|
| 256 | }
|
|---|
| 257 |
|
|---|
| 258 | name = n;
|
|---|
| 259 | group.addThread(this);
|
|---|
| 260 | runnable = r;
|
|---|
| 261 |
|
|---|
| 262 | initialize_native ();
|
|---|
| 263 | }
|
|---|
| 264 |
|
|---|
| 265 | public Thread ()
|
|---|
| 266 | {
|
|---|
| 267 | this (null, null, gen_name ());
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | public Thread (Runnable r)
|
|---|
| 271 | {
|
|---|
| 272 | this (null, r, gen_name ());
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | public Thread (String n)
|
|---|
| 276 | {
|
|---|
| 277 | this (null, null, n);
|
|---|
| 278 | }
|
|---|
| 279 |
|
|---|
| 280 | public Thread (ThreadGroup g, Runnable r)
|
|---|
| 281 | {
|
|---|
| 282 | this (g, r, gen_name ());
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | public Thread (ThreadGroup g, String n)
|
|---|
| 286 | {
|
|---|
| 287 | this (g, null, n);
|
|---|
| 288 | }
|
|---|
| 289 |
|
|---|
| 290 | public Thread (Runnable r, String n)
|
|---|
| 291 | {
|
|---|
| 292 | this (null, r, n);
|
|---|
| 293 | }
|
|---|
| 294 |
|
|---|
| 295 | public String toString ()
|
|---|
| 296 | {
|
|---|
| 297 | return "Thread[" + name + "," + priority + "," +
|
|---|
| 298 | (group == null ? "" : group.getName()) + "]";
|
|---|
| 299 | }
|
|---|
| 300 |
|
|---|
| 301 | public static native void yield ();
|
|---|
| 302 |
|
|---|
| 303 | // Private data.
|
|---|
| 304 | private ThreadGroup group;
|
|---|
| 305 | private String name;
|
|---|
| 306 | private Runnable runnable;
|
|---|
| 307 | private int priority;
|
|---|
| 308 | private boolean daemon_flag;
|
|---|
| 309 | boolean interrupt_flag;
|
|---|
| 310 | private boolean alive_flag;
|
|---|
| 311 | private boolean startable_flag;
|
|---|
| 312 | private ClassLoader context_class_loader;
|
|---|
| 313 |
|
|---|
| 314 | // Our native data - points to an instance of struct natThread.
|
|---|
| 315 | private Object data;
|
|---|
| 316 | }
|
|---|