]> code.delx.au - gnu-emacs/blob - test/etags/java-src/TG.java
Add a test suite for etags
[gnu-emacs] / test / etags / java-src / TG.java
1 /*
2 * @(#)ThreadGroup.java 1.31 97/01/20
3 *
4 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
5 *
6 * This software is the confidential and proprietary information of Sun
7 * Microsystems, Inc. ("Confidential Information"). You shall not
8 * disclose such Confidential Information and shall use it only in
9 * accordance with the terms of the license agreement you entered into
10 * with Sun.
11 *
12 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
13 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
15 * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
16 * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
17 * THIS SOFTWARE OR ITS DERIVATIVES.
18 *
19 * CopyrightVersion 1.1_beta
20 *
21 */
22
23 package java.lang;
24
25 import java.io.PrintStream;
26 import sun.misc.VM;
27
28 /**
29 * A thread group represents a set of threads. In addition, a thread
30 * group can also include other thread groups. The thread groups form
31 * a tree in which every thread group except the initial thread group
32 * has a parent.
33 * <p>
34 * A thread is allowed to access information about its own thread
35 * group, but not to access information about its thread group's
36 * parent thread group or any other thread groups.
37 *
38 * @author unascribed
39 * @version 1.31, 20 Jan 1997
40 * @since JDK1.0
41 */
42 /* The locking strategy for this code is to try to lock only one level of the
43 * tree wherever possible, but otherwise to lock from the bottom up.
44 * That is, from child thread groups to parents.
45 * This has the advantage of limiting the number of locks that need to be held
46 * and in particular avoids having to grab the lock for the root thread group,
47 * (or a global lock) which would be a source of contention on a
48 * multi-processor system with many thread groups.
49 * This policy often leads to taking a snapshot of the state of a thread group
50 * and working off of that snapshot, rather than holding the thread group locked
51 * while we work on the children.
52 */
53 public
54 class ThreadGroup {
55 ThreadGroup parent;
56 String name;
57 int maxPriority;
58 boolean destroyed;
59 boolean daemon;
60 boolean vmAllowSuspension;
61
62 int nthreads;
63 Thread threads[];
64
65 int ngroups;
66 ThreadGroup groups[];
67
68 /**
69 * Creates an empty Thread group that is not in any Thread group.
70 * This method is used to create the system Thread group.
71 */
72 private ThreadGroup() { // called from C code
73 this.name = "system";
74 this.maxPriority = Thread.MAX_PRIORITY;
75 }
76
77 /**
78 * Constructs a new thread group. The parent of this new group is
79 * the thread group of the currently running thread.
80 *
81 * @param name the name of the new thread group.
82 * @since JDK1.0
83 */
84 public ThreadGroup(String name) {
85 this(Thread.currentThread().getThreadGroup(), name);
86 }
87
88 /**
89 * Creates a new thread group. The parent of this new group is the
90 * specified thread group.
91 * <p>
92 * The <code>checkAccess</code> method of the parent thread group is
93 * called with no arguments; this may result in a security exception.
94 *
95 * @param parent the parent thread group.
96 * @param name the name of the new thread group.
97 * @exception NullPointerException if the thread group argument is
98 * <code>null</code>.
99 * @exception SecurityException if the current thread cannot create a
100 * thread in the specified thread group.
101 * @see java.lang.SecurityException
102 * @see java.lang.ThreadGroup#checkAccess()
103 * @since JDK1.0
104 */
105 public ThreadGroup(ThreadGroup parent, String name) {
106 if (parent == null) {
107 throw new NullPointerException();
108 }
109 parent.checkAccess();
110 this.name = name;
111 this.maxPriority = parent.maxPriority;
112 this.daemon = parent.daemon;
113 this.vmAllowSuspension = parent.vmAllowSuspension;
114 this.parent = parent;
115 parent.add(this);
116 }
117
118 /**
119 * Returns the name of this thread group.
120 *
121 * @return the name of this thread group.
122 * @since JDK1.0
123 */
124 public final String getName() {
125 return name;
126 }
127
128 /**
129 * Returns the parent of this thread group.
130 *
131 * @return the parent of this thread group. The top-level thread group
132 * is the only thread group whose parent is <code>null</code>.
133 * @since JDK1.0
134 */
135 public final ThreadGroup getParent() {
136 return parent;
137 }
138
139 /**
140 * Returns the maximum priority of this thread group. Threads that are
141 * part of this group cannot have a higher priority than the maximum
142 * priority.
143 *
144 * @return the maximum priority that a thread in this thread group
145 * can have.
146 * @since JDK1.0
147 */
148 public final int getMaxPriority() {
149 return maxPriority;
150 }
151
152 /**
153 * Tests if this thread group is a daemon thread group. A
154 * daemon thread group is automatically destroyed when its last
155 * thread is stopped or its last thread group is destroyed.
156 *
157 * @return <code>true</code> if this thread group is a daemon thread group;
158 * <code>false</code> otherwise.
159 * @since JDK1.0
160 */
161 public final boolean isDaemon() {
162 return daemon;
163 }
164
165 /**
166 * Tests if this thread group has not been destroyed.
167 *
168 * @since JDK1.1
169 */
170 public synchronized boolean isDestroyed() {
171 return destroyed;
172 }
173
174 /**
175 * Changes the daemon status of this thread group.
176 * <p>
177 * First, the <code>checkAccess</code> method of this thread group is
178 * called with no arguments; this may result in a security exception.
179 * <p>
180 * A daemon thread group is automatically destroyed when its last
181 * thread is stopped or its last thread group is destroyed.
182 *
183 * @param daemon if <code>true</code>, marks this thread group as
184 * a daemon thread group; otherwise, marks this
185 * thread group as normal.
186 * @exception SecurityException if the current thread cannot modify
187 * this thread.
188 * @see java.lang.SecurityException
189 * @see java.lang.ThreadGroup#checkAccess()
190 * @since JDK1.0
191 */
192 public final void setDaemon(boolean daemon) {
193 checkAccess();
194 this.daemon = daemon;
195 }
196
197 /**
198 * Sets the maximum priority of the group.
199 * <p>
200 * First, the <code>checkAccess</code> method of this thread group is
201 * called with no arguments; this may result in a security exception.
202 * <p>
203 * Threads in the thread group that already have a higher priority
204 * are not affected.
205 *
206 * @param pri the new priority of the thread group.
207 * @exception SecurityException if the current thread cannot modify
208 * this thread group.
209 * @see java.lang.SecurityException
210 * @see java.lang.ThreadGroup#checkAccess()
211 * @since JDK1.0
212 */
213 public final void setMaxPriority(int pri) {
214 int ngroupsSnapshot;
215 ThreadGroup[] groupsSnapshot;
216 synchronized (this) {
217 checkAccess();
218 if (pri < Thread.MIN_PRIORITY) {
219 maxPriority = Thread.MIN_PRIORITY;
220 } else if (pri < maxPriority) {
221 maxPriority = pri;
222 }
223 ngroupsSnapshot = ngroups;
224 if (groups != null) {
225 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
226 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
227 } else {
228 groupsSnapshot = null;
229 }
230 }
231 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
232 groupsSnapshot[i].setMaxPriority(pri);
233 }
234 }
235
236 /**
237 * Tests if this thread group is either the thread group
238 * argument or one of its ancestor thread groups.
239 *
240 * @param g a thread group.
241 * @return <code>true</code> if this thread group is the thread group
242 * argument or one of its ancestor thread groups;
243 * <code>false</code> otherwise.
244 * @since JDK1.0
245 */
246 public final boolean parentOf(ThreadGroup g) {
247 for (; g != null ; g = g.parent) {
248 if (g == this) {
249 return true;
250 }
251 }
252 return false;
253 }
254
255 /**
256 * Determines if the currently running thread has permission to
257 * modify this thread group.
258 * <p>
259 * If there is a security manager, its <code>checkAccess</code> method
260 * is called with this thread group as its argument. This may result
261 * in throwing a <code>SecurityException</code>.
262 *
263 * @exception SecurityException if the current thread is not allowed to
264 * access this thread group.
265 * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
266 * @since JDK1.0
267 */
268 public final void checkAccess() {
269 SecurityManager security = System.getSecurityManager();
270 if (security != null) {
271 security.checkAccess(this);
272 }
273 }
274
275 /**
276 * Returns an estimate of the number of active threads in this
277 * thread group.
278 *
279 * @return the number of active threads in this thread group and in any
280 * other thread group that has this thread group as an ancestor.
281 * @since JDK1.0
282 */
283 public int activeCount() {
284 int result;
285 // Snapshot sub-group data so we don't hold this lock
286 // while our children are computing.
287 int ngroupsSnapshot;
288 ThreadGroup[] groupsSnapshot;
289 synchronized (this) {
290 if (destroyed) {
291 return 0;
292 }
293 result = nthreads;
294 ngroupsSnapshot = ngroups;
295 if (groups != null) {
296 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
297 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
298 } else {
299 groupsSnapshot = null;
300 }
301 }
302 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
303 result += groupsSnapshot[i].activeCount();
304 }
305 return result;
306 }
307
308 /**
309 * Copies into the specified array every active thread in this
310 * thread group and its subgroups.
311 * <p>
312 * An application should use the <code>activeCount</code> method to
313 * get an estimate of how big the array should be. If the array is
314 * too short to hold all the threads, the extra threads are silently
315 * ignored.
316 *
317 * @param list an array into which to place the list of threads.
318 * @return the number of threads put into the array.
319 * @see java.lang.ThreadGroup#activeCount()
320 * @since JDK1.0
321 */
322 public int enumerate(Thread list[]) {
323 return enumerate(list, 0, true);
324 }
325
326 /**
327 * Copies into the specified array every active thread in this
328 * thread group. If the <code>recurse</code> flag is
329 * <code>true</code>, references to every active thread in this
330 * thread's subgroups are also included. If the array is too short to
331 * hold all the threads, the extra threads are silently ignored.
332 * <p>
333 * An application should use the <code>activeCount</code> method to
334 * get an estimate of how big the array should be.
335 *
336 * @param list an array into which to place the list of threads.
337 * @param recurse a flag indicating whether also to include threads
338 * in thread groups that are subgroups of this
339 * thread group.
340 * @return the number of threads placed into the array.
341 * @see java.lang.ThreadGroup#activeCount()
342 * @since JDK1.0
343 */
344 public int enumerate(Thread list[], boolean recurse) {
345 return enumerate(list, 0, recurse);
346 }
347
348 private int enumerate(Thread list[], int n, boolean recurse) {
349 int ngroupsSnapshot = 0;
350 ThreadGroup[] groupsSnapshot = null;
351 synchronized (this) {
352 if (destroyed) {
353 return 0;
354 }
355 int nt = nthreads;
356 if (nt > list.length - n) {
357 nt = list.length - n;
358 }
359 if (nt > 0) {
360 System.arraycopy(threads, 0, list, n, nt);
361 n += nt;
362 }
363 if (recurse) {
364 ngroupsSnapshot = ngroups;
365 if (groups != null) {
366 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
367 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
368 } else {
369 groupsSnapshot = null;
370 }
371 }
372 }
373 if (recurse) {
374 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
375 n = groupsSnapshot[i].enumerate(list, n, true);
376 }
377 }
378 return n;
379 }
380
381 /**
382 * Returns an estimate of the number of active groups in this
383 * thread group.
384 *
385 * @return the number of active thread groups with this thread group as
386 * an ancestor.
387 * @since JDK1.0
388 */
389 public int activeGroupCount() {
390 int ngroupsSnapshot;
391 ThreadGroup[] groupsSnapshot;
392 synchronized (this) {
393 if (destroyed) {
394 return 0;
395 }
396 ngroupsSnapshot = ngroups;
397 if (groups != null) {
398 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
399 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
400 } else {
401 groupsSnapshot = null;
402 }
403 }
404 int n = ngroupsSnapshot;
405 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
406 n += groupsSnapshot[i].activeGroupCount();
407 }
408 return n;
409 }
410
411 /**
412 * Copies into the specified array references to every active
413 * subgroup in this thread group.
414 * <p>
415 * An application should use the <code>activeGroupCount</code>
416 * method to get an estimate of how big the array should be. If the
417 * array is too short to hold all the thread groups, the extra thread
418 * groups are silently ignored.
419 *
420 * @param list an array into which to place the list of thread groups.
421 * @return the number of thread groups put into the array.
422 * @see java.lang.ThreadGroup#activeGroupCount()
423 * @since JDK1.0
424 */
425 public int enumerate(ThreadGroup list[]) {
426 return enumerate(list, 0, true);
427 }
428
429 /**
430 * Copies into the specified array references to every active
431 * subgroup in this thread group. If the <code>recurse</code> flag is
432 * <code>true</code>, references to all active subgroups of the
433 * subgroups and so forth are also included.
434 * <p>
435 * An application should use the <code>activeGroupCount</code>
436 * method to get an estimate of how big the array should be.
437 *
438 * @param list an array into which to place the list of threads.
439 * @param recurse a flag indicating whether to recursively enumerate
440 * all included thread groups.
441 * @return the number of thread groups put into the array.
442 * @see java.lang.ThreadGroup#activeGroupCount()
443 * @since JDK1.0
444 */
445 public int enumerate(ThreadGroup list[], boolean recurse) {
446 return enumerate(list, 0, recurse);
447 }
448
449 private int enumerate(ThreadGroup list[], int n, boolean recurse) {
450 int ngroupsSnapshot = 0;
451 ThreadGroup[] groupsSnapshot = null;
452 synchronized (this) {
453 if (destroyed) {
454 return 0;
455 }
456 int ng = ngroups;
457 if (ng > list.length - n) {
458 ng = list.length - n;
459 }
460 if (ng > 0) {
461 System.arraycopy(groups, 0, list, n, ng);
462 n += ng;
463 }
464 if (recurse) {
465 ngroupsSnapshot = ngroups;
466 if (groups != null) {
467 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
468 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
469 } else {
470 groupsSnapshot = null;
471 }
472 }
473 }
474 if (recurse) {
475 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
476 n = groupsSnapshot[i].enumerate(list, n, true);
477 }
478 }
479 return n;
480 }
481
482 /**
483 * Stops all processes in this thread group.
484 * <p>
485 * First, the <code>checkAccess</code> method of this thread group is
486 * called with no arguments; this may result in a security exception.
487 * <p>
488 * This method then calls the <code>stop</code> method on all the
489 * threads in this thread group and in all of its subgroups.
490 *
491 * @exception SecurityException if the current thread is not allowed
492 * to access this thread group or any of the threads in
493 * the thread group.
494 * @see java.lang.SecurityException
495 * @see java.lang.Thread#stop()
496 * @see java.lang.ThreadGroup#checkAccess()
497 * @since JDK1.0
498 */
499 public final void stop() {
500 int ngroupsSnapshot;
501 ThreadGroup[] groupsSnapshot;
502 synchronized (this) {
503 checkAccess();
504 for (int i = 0 ; i < nthreads ; i++) {
505 threads[i].stop();
506 }
507 ngroupsSnapshot = ngroups;
508 if (groups != null) {
509 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
510 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
511 } else {
512 groupsSnapshot = null;
513 }
514 }
515 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
516 groupsSnapshot[i].stop();
517 }
518 }
519
520 /**
521 * Suspends all processes in this thread group.
522 * <p>
523 * First, the <code>checkAccess</code> method of this thread group is
524 * called with no arguments; this may result in a security exception.
525 * <p>
526 * This method then calls the <code>suspend</code> method on all the
527 * threads in this thread group and in all of its subgroups.
528 *
529 * @exception SecurityException if the current thread is not allowed
530 * to access this thread group or any of the threads in
531 * the thread group.
532 * @see java.lang.SecurityException
533 * @see java.lang.Thread#suspend()
534 * @see java.lang.ThreadGroup#checkAccess()
535 * @since JDK1.0
536 */
537 public final void suspend() {
538 int ngroupsSnapshot;
539 ThreadGroup[] groupsSnapshot;
540 synchronized (this) {
541 checkAccess();
542 for (int i = 0 ; i < nthreads ; i++) {
543 threads[i].suspend();
544 }
545 ngroupsSnapshot = ngroups;
546 if (groups != null) {
547 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
548 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
549 } else {
550 groupsSnapshot = null;
551 }
552 }
553 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
554 groupsSnapshot[i].suspend();
555 }
556 }
557
558 /**
559 * Resumes all processes in this thread group.
560 * <p>
561 * First, the <code>checkAccess</code> method of this thread group is
562 * called with no arguments; this may result in a security exception.
563 * <p>
564 * This method then calls the <code>resume</code> method on all the
565 * threads in this thread group and in all of its sub groups.
566 *
567 * @exception SecurityException if the current thread is not allowed to
568 * access this thread group or any of the threads in the
569 * thread group.
570 * @see java.lang.SecurityException
571 * @see java.lang.Thread#resume()
572 * @see java.lang.ThreadGroup#checkAccess()
573 * @since JDK1.0
574 */
575 public final void resume() {
576 int ngroupsSnapshot;
577 ThreadGroup[] groupsSnapshot;
578 synchronized (this) {
579 checkAccess();
580 for (int i = 0 ; i < nthreads ; i++) {
581 threads[i].resume();
582 }
583 ngroupsSnapshot = ngroups;
584 if (groups != null) {
585 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
586 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
587 } else {
588 groupsSnapshot = null;
589 }
590 }
591 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
592 groupsSnapshot[i].resume();
593 }
594 }
595
596 /**
597 * Destroys this thread group and all of its subgroups. This thread
598 * group must be empty, indicating that all threads that had been in
599 * this thread group have since stopped.
600 *
601 * @exception IllegalThreadStateException if the thread group is not
602 * empty or if the thread group has already been destroyed.
603 * @exception SecurityException if the current thread cannot modify this
604 * thread group.
605 * @since JDK1.0
606 */
607 public final void destroy() {
608 int ngroupsSnapshot;
609 ThreadGroup[] groupsSnapshot;
610 synchronized (this) {
611 checkAccess();
612 if (destroyed || (nthreads > 0)) {
613 throw new IllegalThreadStateException();
614 }
615 ngroupsSnapshot = ngroups;
616 if (groups != null) {
617 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
618 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
619 } else {
620 groupsSnapshot = null;
621 }
622 if (parent != null) {
623 destroyed = true;
624 ngroups = 0;
625 groups = null;
626 nthreads = 0;
627 threads = null;
628 }
629 }
630 for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
631 groupsSnapshot[i].destroy();
632 }
633 if (parent != null) {
634 parent.remove(this);
635 }
636 }
637
638 /**
639 * Adds the specified Thread group to this group.
640 * @param g the specified Thread group to be added
641 * @exception IllegalThreadStateException If the Thread group has been destroyed.
642 */
643 private final void add(ThreadGroup g){
644 synchronized (this) {
645 if (destroyed) {
646 throw new IllegalThreadStateException();
647 }
648 if (groups == null) {
649 groups = new ThreadGroup[4];
650 } else if (ngroups == groups.length) {
651 ThreadGroup newgroups[] = new ThreadGroup[ngroups * 2];
652 System.arraycopy(groups, 0, newgroups, 0, ngroups);
653 groups = newgroups;
654 }
655 groups[ngroups] = g;
656
657 // This is done last so it doesn't matter in case the
658 // thread is killed
659 ngroups++;
660 }
661 }
662
663 /**
664 * Removes the specified Thread group from this group.
665 * @param g the Thread group to be removed
666 * @return if this Thread has already been destroyed.
667 */
668 private void remove(ThreadGroup g) {
669 synchronized (this) {
670 if (destroyed) {
671 return;
672 }
673 for (int i = 0 ; i < ngroups ; i++) {
674 if (groups[i] == g) {
675 ngroups -= 1;
676 System.arraycopy(groups, i + 1, groups, i, ngroups - i);
677 // Zap dangling reference to the dead group so that
678 // the garbage collector will collect it.
679 groups[ngroups] = null;
680 break;
681 }
682 }
683 if (nthreads == 0) {
684 notifyAll();
685 }
686 if (daemon && (nthreads == 0) && (ngroups == 0)) {
687 destroy();
688 }
689 }
690 }
691
692 /**
693 * Adds the specified Thread to this group.
694 * @param t the Thread to be added
695 * @exception IllegalThreadStateException If the Thread group has been destroyed.
696 */
697 void add(Thread t) {
698 synchronized (this) {
699 if (destroyed) {
700 throw new IllegalThreadStateException();
701 }
702 if (threads == null) {
703 threads = new Thread[4];
704 } else if (nthreads == threads.length) {
705 Thread newthreads[] = new Thread[nthreads * 2];
706 System.arraycopy(threads, 0, newthreads, 0, nthreads);
707 threads = newthreads;
708 }
709 threads[nthreads] = t;
710
711 // This is done last so it doesn't matter in case the
712 // thread is killed
713 nthreads++;
714 }
715 }
716
717 /**
718 * Removes the specified Thread from this group.
719 * @param t the Thread to be removed
720 * @return if the Thread has already been destroyed.
721 */
722 void remove(Thread t) {
723 synchronized (this) {
724 if (destroyed) {
725 return;
726 }
727 for (int i = 0 ; i < nthreads ; i++) {
728 if (threads[i] == t) {
729 System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
730 // Zap dangling reference to the dead thread so that
731 // the garbage collector will collect it.
732 threads[nthreads] = null;
733 break;
734 }
735 }
736 if (nthreads == 0) {
737 notifyAll();
738 }
739 if (daemon && (nthreads == 0) && (ngroups == 0)) {
740 destroy();
741 }
742 }
743 }
744
745 /**
746 * Prints information about this thread group to the standard
747 * output. This method is useful only for debugging.
748 *
749 * @since JDK1.0
750 */
751 public void list() {
752 list(System.out, 0);
753 }
754 void list(PrintStream out, int indent) {
755 int ngroupsSnapshot;
756 ThreadGroup[] groupsSnapshot;
757 synchronized (this) {
758 for (int j = 0 ; j < indent ; j++) {
759 out.print(" ");
760 }
761 out.println(this);
762 indent += 4;
763 for (int i = 0 ; i < nthreads ; i++) {
764 for (int j = 0 ; j < indent ; j++) {
765 out.print(" ");
766 }
767 out.println(threads[i]);
768 }
769 ngroupsSnapshot = ngroups;
770 if (groups != null) {
771 groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
772 System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
773 } else {
774 groupsSnapshot = null;
775 }
776 }
777 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
778 groupsSnapshot[i].list(out, indent);
779 }
780 }
781
782 /**
783 * Called by the Java Virtual Machine when a thread in this
784 * thread group stops because of an uncaught exception.
785 * <p>
786 * The <code>uncaughtException</code> method of
787 * <code>ThreadGroup</code> does the following:
788 * <ul>
789 * <li>If this thread group has a parent thread group, the
790 * <code>uncaughtException</code> method of that parent is called
791 * with the same two arguments.
792 * <li>Otherwise, this method determines if the <code>Throwable</code>
793 * argument is an instance of <code>ThreadDeath</code>. If so, nothing
794 * special is done. Otherwise, the <code>Throwable</code>'s
795 * <code>printStackTrace</code> method is called to print a stack
796 * backtrace to the standard error stream.
797 * </ul>
798 * <p>
799 * Applications can override this method in subclasses of
800 * <code>ThreadGroup</code> to provide alternative handling of
801 * uncaught exceptions.
802 *
803 * @param t the thread that is about to exit.
804 * @param e the uncaught exception.
805 * @see java.lang.System#err
806 * @see java.lang.ThreadDeath
807 * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
808 * @since JDK1.0
809 */
810 public void uncaughtException(Thread t, Throwable e) {
811 if (parent != null) {
812 parent.uncaughtException(t, e);
813 } else if (!(e instanceof ThreadDeath)) {
814 e.printStackTrace(System.err);
815 }
816 }
817
818 /**
819 * Used by VM to control lowmem implicit suspension.
820 *
821 * @since JDK1.1
822 */
823 public boolean allowThreadSuspension(boolean b) {
824 this.vmAllowSuspension = b;
825 if (!b) {
826 VM.unsuspendSomeThreads();
827 }
828 return true;
829 }
830
831 /**
832 * Returns a string representation of this Thread group.
833 *
834 * @return a string representation of this thread group.
835 * @since JDK1.0
836 */
837 public String toString() {
838 return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
839 }
840 }