source: trunk/src/gcc/libjava/java/lang/ThreadGroup.java@ 1389

Last change on this file since 1389 was 2, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 19.6 KB
Line 
1/* java.lang.ThreadGroup
2 Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
3
4This file is part of GNU Classpath.
5
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1902111-1307 USA.
20
21Linking this library statically or dynamically with other modules is
22making a combined work based on this library. Thus, the terms and
23conditions of the GNU General Public License cover the whole
24combination.
25
26As a special exception, the copyright holders of this library give you
27permission to link this library with independent modules to produce an
28executable, regardless of the license terms of these independent
29modules, and to copy and distribute the resulting executable under
30terms of your choice, provided that you also meet, for each linked
31independent module, the terms and conditions of the license of that
32module. An independent module is a module which is not derived from
33or based on this library. If you modify this library, you may extend
34this exception to your version of the library, but you are not
35obligated to do so. If you do not wish to do so, delete this
36exception statement from your version. */
37
38package java.lang;
39
40import java.util.Vector;
41import java.util.Enumeration;
42
43/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
44 * "The Java Language Specification", ISBN 0-201-63451-1
45 * plus online API docs for JDK 1.2 from http://www.javasoft.com.
46 * Status: Complete for 1.2. Some parts from the JDK 1.0 spec only are
47 * not implemented.
48 */
49
50/**
51 * ThreadGroup allows you to group Threads together. There is a
52 * hierarchy of ThreadGroups, and only the initial ThreadGroup has
53 * no parent. A Thread may access information about its own
54 * ThreadGroup, but not its parents or others outside the tree.
55 *
56 * @author John Keiser
57 * @author Tom Tromey
58 * @author Bryce McKinlay
59 * @version 1.2.0
60 * @since JDK1.0
61 */
62
63public class ThreadGroup
64{
65 /* The Initial, top-level ThreadGroup. */
66 static ThreadGroup root = new ThreadGroup();
67 /* This flag is set if an uncaught exception occurs. The runtime should
68 check this and exit with an error status if it is set. */
69 static boolean had_uncaught_exception = false;
70
71 private ThreadGroup parent;
72 private String name;
73 private Vector threads = new Vector();
74 private Vector groups = new Vector();
75 private boolean daemon_flag = false;
76 private int maxpri = Thread.MAX_PRIORITY;
77
78 private ThreadGroup()
79 {
80 name = "main";
81 }
82
83 /** Create a new ThreadGroup using the given name and the
84 * current thread's ThreadGroup as a parent.
85 * @param name the name to use for the ThreadGroup.
86 */
87 public ThreadGroup(String name)
88 {
89 this (Thread.currentThread().getThreadGroup(), name);
90 }
91
92 /** Create a new ThreadGroup using the given name and
93 * parent group.
94 * @param name the name to use for the ThreadGroup.
95 * @param parent the ThreadGroup to use as a parent.
96 * @exception NullPointerException if parent is null.
97 * @exception SecurityException if you cannot change
98 * the intended parent group.
99 */
100 public ThreadGroup(ThreadGroup parent, String name)
101 {
102 parent.checkAccess();
103 this.parent = parent;
104 if (parent.isDestroyed())
105 throw new IllegalArgumentException ();
106 this.name = name;
107 maxpri = parent.maxpri;
108 daemon_flag = parent.daemon_flag;
109 parent.addGroup(this);
110 }
111
112 /** Get the name of this ThreadGroup.
113 * @return the name of this ThreadGroup.
114 */
115 public final String getName()
116 {
117 return name;
118 }
119
120 /** Get the parent of this ThreadGroup.
121 * @return the parent of this ThreadGroup.
122 */
123 public final ThreadGroup getParent()
124 {
125 return parent;
126 }
127
128 /** Set the maximum priority for Threads in this ThreadGroup. setMaxPriority
129 * can only be used to reduce the current maximum. If maxpri
130 * is greater than the current Maximum, the current value is not changed.
131 * Calling this does not effect threads already in this ThreadGroup.
132 * @param maxpri the new maximum priority for this ThreadGroup.
133 * @exception SecurityException if you cannoy modify this ThreadGroup.
134 */
135 public final synchronized void setMaxPriority(int maxpri)
136 {
137 checkAccess();
138 if (maxpri < this.maxpri
139 && maxpri >= Thread.MIN_PRIORITY
140 && maxpri <= Thread.MAX_PRIORITY)
141 {
142 this.maxpri = maxpri;
143 }
144 }
145
146 /** Get the maximum priority of Threads in this ThreadGroup.
147 * @return the maximum priority of Threads in this ThreadGroup.
148 */
149 public final int getMaxPriority()
150 {
151 return maxpri;
152 }
153
154 /** Set whether this ThreadGroup is a daemon group. A daemon
155 * group will be destroyed when its last thread is stopped and
156 * its last thread group is destroyed.
157 * @specnote The Java API docs indicate that the group is destroyed
158 * when either of those happen, but that doesn't make
159 * sense.
160 * @param daemon whether this ThreadGroup should be a daemon group.
161 * @exception SecurityException if you cannoy modify this ThreadGroup.
162 */
163 public final void setDaemon (boolean daemon)
164 {
165 checkAccess();
166 daemon_flag = daemon;
167 }
168
169 /** Tell whether this ThreadGroup is a daemon group. A daemon
170 * group will be destroyed when its last thread is stopped and
171 * its last thread group is destroyed.
172 * @specnote The Java API docs indicate that the group is destroyed
173 * when either of those happen, but that doesn't make
174 * sense.
175 * @return whether this ThreadGroup is a daemon group.
176 */
177 public final boolean isDaemon()
178 {
179 return daemon_flag;
180 }
181
182 /** Tell whether this ThreadGroup has been destroyed or not.
183 * @return whether this ThreadGroup has been destroyed or not.
184 */
185 public synchronized boolean isDestroyed()
186 {
187 return parent == null && this != root;
188 }
189
190 /** Check whether this ThreadGroup is an ancestor of the
191 * specified ThreadGroup, or if they are the same.
192 *
193 * @param g the group to test on.
194 * @return whether this ThreadGroup is a parent of the
195 * specified group.
196 */
197 public final boolean parentOf(ThreadGroup tg)
198 {
199 while (tg != null)
200 {
201 if (tg == this)
202 return true;
203 tg = tg.parent;
204 }
205 return false;
206 }
207
208 /** Return the total number of active threads in this ThreadGroup
209 * and all its descendants.<P>
210 *
211 * This cannot return an exact number, since the status of threads
212 * may change after they were counted. But it should be pretty
213 * close.<P>
214 *
215 * @return the number of active threads in this ThreadGroup and
216 * its descendants.
217 * @specnote it isn't clear what the definition of an "Active" thread is.
218 * Current JDKs regard a thread as active if has been
219 * started and not finished. We implement this behaviour.
220 * There is a JDC bug, <A HREF="http://developer.java.sun.com/developer/bugParade/bugs/4089701.html">
221 * 4089701</A>, regarding this issue.
222 *
223 */
224 public synchronized int activeCount()
225 {
226 int total = 0;
227 for (int i = 0; i < threads.size(); ++i)
228 {
229 if (((Thread) threads.elementAt(i)).isAlive ())
230 ++total;
231 }
232
233 for (int i=0; i < groups.size(); i++)
234 {
235 ThreadGroup g = (ThreadGroup) groups.elementAt(i);
236 total += g.activeCount();
237 }
238 return total;
239 }
240
241 /** Get the number of active groups in this ThreadGroup. This group
242 * itself is not included in the count.
243 * @specnote it is unclear what exactly constitutes an
244 * active ThreadGroup. Currently we assume that
245 * all sub-groups are active, per current JDKs.
246 * @return the number of active groups in this ThreadGroup.
247 */
248 public synchronized int activeGroupCount()
249 {
250 int total = groups.size();
251 for (int i=0; i < groups.size(); i++)
252 {
253 ThreadGroup g = (ThreadGroup) groups.elementAt(i);
254 total += g.activeGroupCount();
255 }
256 return total;
257 }
258
259 /** Copy all of the active Threads from this ThreadGroup and
260 * its descendants into the specified array. If the array is
261 * not big enough to hold all the Threads, extra Threads will
262 * simply not be copied.
263 *
264 * @param threads the array to put the threads into.
265 * @return the number of threads put into the array.
266 */
267 public int enumerate(Thread[] threads)
268 {
269 return enumerate(threads, 0, true);
270 }
271
272 /** Copy all of the active Threads from this ThreadGroup and,
273 * if desired, from its descendants, into the specified array.
274 * If the array is not big enough to hold all the Threads,
275 * extra Threads will simply not be copied.
276 *
277 * @param threads the array to put the threads into.
278 * @param useDescendants whether to count Threads in this
279 * ThreadGroup's descendants or not.
280 * @return the number of threads put into the array.
281 */
282 public int enumerate(Thread[] threads, boolean useDescendants)
283 {
284 return enumerate(threads, 0, useDescendants);
285 }
286
287 // This actually implements enumerate.
288 private synchronized int enumerate(Thread[] list, int next_index,
289 boolean recurse)
290 {
291 Enumeration e = threads.elements();
292 while (e.hasMoreElements() && next_index < list.length)
293 {
294 Thread t = (Thread) e.nextElement();
295 if (t.isAlive ())
296 list[next_index++] = t;
297 }
298 if (recurse && next_index != list.length)
299 {
300 e = groups.elements();
301 while (e.hasMoreElements() && next_index < list.length)
302 {
303 ThreadGroup g = (ThreadGroup) e.nextElement();
304 next_index = g.enumerate(list, next_index, true);
305 }
306 }
307 return next_index;
308 }
309
310 /** Copy all active ThreadGroups that are descendants of this
311 * ThreadGroup into the specified array. If the array is not
312 * large enough to hold all active ThreadGroups, extra
313 * ThreadGroups simply will not be copied.
314 *
315 * @param groups the array to put the ThreadGroups into.
316 * @return the number of ThreadGroups copied into the array.
317 */
318 public int enumerate(ThreadGroup[] groups)
319 {
320 return enumerate(groups, 0, true);
321 }
322
323 /** Copy all active ThreadGroups that are children of this
324 * ThreadGroup into the specified array, and if desired, also
325 * copy all active descendants into the array. If the array
326 * is not large enough to hold all active ThreadGroups, extra
327 * ThreadGroups simply will not be copied.
328 *
329 * @param groups the array to put the ThreadGroups into.
330 * @param recurse whether to include all descendants
331 * of this ThreadGroup's children in determining
332 * activeness.
333 * @return the number of ThreadGroups copied into the array.
334 */
335 public int enumerate(ThreadGroup[] groups, boolean recurse)
336 {
337 return enumerate(groups, 0, recurse);
338 }
339
340 // This actually implements enumerate.
341 private synchronized int enumerate (ThreadGroup[] list, int next_index,
342 boolean recurse)
343 {
344 Enumeration e = groups.elements();
345 while (e.hasMoreElements() && next_index < list.length)
346 {
347 ThreadGroup g = (ThreadGroup) e.nextElement();
348 list[next_index++] = g;
349 if (recurse && next_index != list.length)
350 next_index = g.enumerate(list, next_index, true);
351 }
352 return next_index;
353 }
354
355 /** Interrupt all Threads in this ThreadGroup and its sub-groups.
356 * @exception SecurityException if you cannot modify this
357 * ThreadGroup or any of its Threads or children
358 * ThreadGroups.
359 * @since JDK1.2
360 */
361 public final synchronized void interrupt()
362 {
363 checkAccess();
364 for (int i=0; i < threads.size(); i++)
365 {
366 Thread t = (Thread) threads.elementAt(i);
367 t.interrupt();
368 }
369 for (int i=0; i < groups.size(); i++)
370 {
371 ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
372 tg.interrupt();
373 }
374 }
375
376 /** Stop all Threads in this ThreadGroup and its descendants.
377 * @exception SecurityException if you cannot modify this
378 * ThreadGroup or any of its Threads or children
379 * ThreadGroups.
380 * @deprecated This method calls Thread.stop(), which is dangerous.
381 */
382 public final synchronized void stop()
383 {
384 checkAccess();
385 for (int i=0; i<threads.size(); i++)
386 {
387 Thread t = (Thread) threads.elementAt(i);
388 t.stop();
389 }
390 for (int i=0; i < groups.size(); i++)
391 {
392 ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
393 tg.stop();
394 }
395 }
396
397 /** Suspend all Threads in this ThreadGroup and its descendants.
398 * @exception SecurityException if you cannot modify this
399 * ThreadGroup or any of its Threads or children
400 * ThreadGroups.
401 * @deprecated This method calls Thread.suspend(), which is dangerous.
402 */
403 public final synchronized void suspend()
404 {
405 checkAccess();
406 for (int i=0; i<threads.size(); i++)
407 {
408 Thread t = (Thread) threads.elementAt(i);
409 t.suspend();
410 }
411 for (int i=0; i < groups.size(); i++)
412 {
413 ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
414 tg.suspend();
415 }
416 }
417
418 /** Resume all Threads in this ThreadGroup and its descendants.
419 * @exception SecurityException if you cannot modify this
420 * ThreadGroup or any of its Threads or children
421 * ThreadGroups.
422 * @deprecated This method relies on Thread.suspend(), which is dangerous.
423 */
424 public final synchronized void resume()
425 {
426 checkAccess();
427 for (int i=0; i < threads.size(); i++)
428 {
429 Thread t = (Thread) threads.elementAt(i);
430 t.resume();
431 }
432 for (int i=0; i < groups.size(); i++)
433 {
434 ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
435 tg.resume();
436 }
437 }
438
439 // This is a helper that is used to implement the destroy method.
440 private synchronized void checkDestroy ()
441 {
442 if (! threads.isEmpty())
443 throw new IllegalThreadStateException ("ThreadGroup has threads");
444 for (int i=0; i < groups.size(); i++)
445 {
446 ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
447 tg.checkDestroy();
448 }
449 }
450
451 /** Destroy this ThreadGroup. There can be no Threads in it,
452 * and none of its descendants (sub-groups) may have Threads in them.
453 * All its descendants will be destroyed as well.
454 * @exception IllegalThreadStateException if the ThreadGroup or
455 * its descendants have Threads remaining in them, or
456 * if the ThreadGroup in question is already destroyed.
457 * @exception SecurityException if you cannot modify this
458 * ThreadGroup or any of its descendants.
459 */
460 public final synchronized void destroy()
461 {
462 checkAccess();
463 if (isDestroyed())
464 throw new IllegalThreadStateException("Already destroyed.");
465 checkDestroy ();
466 if (parent != null)
467 parent.removeGroup(this);
468 parent = null;
469
470 for (int i=0; i < groups.size(); i++)
471 {
472 ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
473 tg.destroy();
474 }
475 }
476
477 /** Print out information about this ThreadGroup to System.out.
478 */
479 public void list()
480 {
481 list("");
482 }
483
484 private synchronized void list(String indentation)
485 {
486 System.out.print(indentation);
487 System.out.println(toString ());
488 String sub = indentation + " ";
489 for (int i=0; i < threads.size(); i++)
490 {
491 Thread t = (Thread) threads.elementAt(i);
492 System.out.print(sub);
493 System.out.println(t.toString());
494 }
495 for (int i=0; i < groups.size(); i++)
496 {
497 ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
498 tg.list(sub);
499 }
500 }
501
502 /** When a Thread in this ThreadGroup does not catch an exception,
503 * this method of the ThreadGroup is called.<P>
504 *
505 * ThreadGroup's implementation does the following:<BR>
506 * <OL>
507 * <LI>If there is a parent ThreadGroup, call uncaughtException()
508 * in the parent.</LI>
509 * <LI>If the Throwable passed is a ThreadDeath, don't do
510 * anything.</LI>
511 * <LI>Otherwise, call <CODE>exception.printStackTrace().</CODE></LI>
512 * </OL>
513 *
514 * @param thread the thread that exited.
515 * @param exception the uncaught exception.
516 */
517 public void uncaughtException(Thread thread, Throwable t)
518 {
519 if (parent != null)
520 parent.uncaughtException (thread, t);
521 else if (! (t instanceof ThreadDeath))
522 {
523 if (thread != null)
524 System.err.print ("Exception in thread \""
525 + thread.getName() + "\" ");
526 try
527 {
528 t.printStackTrace(System.err);
529 }
530 catch (Throwable x)
531 {
532 // This means that something is badly screwed up with the runtime,
533 // or perhaps someone is messing with the SecurityManager. In any
534 // case, try to deal with it gracefully.
535 System.err.println(t);
536 System.err.println("*** Got " + x.toString() +
537 " while trying to print stack trace");
538 }
539 had_uncaught_exception = true;
540 }
541 }
542
543 /** Tell the VM whether it may suspend Threads in low memory
544 * situations.
545 * @deprecated This method is unimplemented, because it would rely on
546 * suspend(), which is deprecated. There is no way for a Java
547 * program to determine whether this has any effect whatsoever,
548 * so we don't need it.
549 * @return false
550 */
551 public boolean allowThreadSuspension(boolean allow)
552 {
553 return false;
554 }
555
556 /** Get a human-readable representation of this ThreadGroup.
557 * @return a String representing this ThreadGroup.
558 * @specnote Language Spec and Class Libraries book disagree a bit here.
559 * We follow the Spec, but add "ThreadGroup" per the book. We
560 * include "java.lang" based on the list() example in the Class
561 * Libraries book.
562 */
563 public String toString ()
564 {
565 return "java.lang.ThreadGroup[name=" + name +
566 ",maxpri=" + maxpri + "]";
567 }
568
569 /** Find out if the current Thread can modify this ThreadGroup.
570 * Calls the current SecurityManager's checkAccess() method to
571 * find out. If there is none, it assumes everything's OK.
572 * @exception SecurityException if the current Thread cannot
573 * modify this ThreadGroup.
574 */
575 public final void checkAccess()
576 {
577 SecurityManager sm = System.getSecurityManager();
578 if (sm != null)
579 sm.checkAccess(this);
580 }
581
582 // This is called to add a Thread to our internal list.
583 final synchronized void addThread(Thread t)
584 {
585 if (isDestroyed())
586 throw new IllegalThreadStateException ("ThreadGroup is destroyed");
587
588 threads.addElement(t);
589 }
590
591 // This is called to remove a Thread from our internal list.
592 final synchronized void removeThread(Thread t)
593 {
594 if (isDestroyed())
595 throw new IllegalThreadStateException ();
596
597 threads.removeElement(t);
598 // Daemon groups are automatically destroyed when all their threads die.
599 if (daemon_flag && groups.size() == 0 && threads.size() == 0)
600 {
601 // We inline destroy to avoid the access check.
602 if (parent != null)
603 parent.removeGroup(this);
604 parent = null;
605 }
606 }
607
608 // This is called to add a ThreadGroup to our internal list.
609 final synchronized void addGroup(ThreadGroup g)
610 {
611 groups.addElement(g);
612 }
613
614 // This is called to remove a ThreadGroup from our internal list.
615 final synchronized void removeGroup(ThreadGroup g)
616 {
617 groups.removeElement(g);
618 // Daemon groups are automatically destroyed when all their threads die.
619 if (daemon_flag && groups.size() == 0 && threads.size() == 0)
620 {
621 // We inline destroy to avoid the access check.
622 if (parent != null)
623 parent.removeGroup(this);
624 parent = null;
625 }
626 }
627}
Note: See TracBrowser for help on using the repository browser.