]>
code.delx.au - gnu-emacs/blob - test/etags/java-src/TG.java
2 * @(#)ThreadGroup.java 1.31 97/01/20
4 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
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
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.
19 * CopyrightVersion 1.1_beta
25 import java
.io
.PrintStream
;
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
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.
39 * @version 1.31, 20 Jan 1997
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.
60 boolean vmAllowSuspension
;
69 * Creates an empty Thread group that is not in any Thread group.
70 * This method is used to create the system Thread group.
72 private ThreadGroup() { // called from C code
74 this.maxPriority
= Thread
.MAX_PRIORITY
;
78 * Constructs a new thread group. The parent of this new group is
79 * the thread group of the currently running thread.
81 * @param name the name of the new thread group.
84 public ThreadGroup(String name
) {
85 this(Thread
.currentThread().getThreadGroup(), name
);
89 * Creates a new thread group. The parent of this new group is the
90 * specified thread group.
92 * The <code>checkAccess</code> method of the parent thread group is
93 * called with no arguments; this may result in a security exception.
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
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()
105 public ThreadGroup(ThreadGroup parent
, String name
) {
106 if (parent
== null) {
107 throw new NullPointerException();
109 parent
.checkAccess();
111 this.maxPriority
= parent
.maxPriority
;
112 this.daemon
= parent
.daemon
;
113 this.vmAllowSuspension
= parent
.vmAllowSuspension
;
114 this.parent
= parent
;
119 * Returns the name of this thread group.
121 * @return the name of this thread group.
124 public final String
getName() {
129 * Returns the parent of this thread group.
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>.
135 public final ThreadGroup
getParent() {
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
144 * @return the maximum priority that a thread in this thread group
148 public final int getMaxPriority() {
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.
157 * @return <code>true</code> if this thread group is a daemon thread group;
158 * <code>false</code> otherwise.
161 public final boolean isDaemon() {
166 * Tests if this thread group has not been destroyed.
170 public synchronized boolean isDestroyed() {
175 * Changes the daemon status of this thread group.
177 * First, the <code>checkAccess</code> method of this thread group is
178 * called with no arguments; this may result in a security exception.
180 * A daemon thread group is automatically destroyed when its last
181 * thread is stopped or its last thread group is destroyed.
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
188 * @see java.lang.SecurityException
189 * @see java.lang.ThreadGroup#checkAccess()
192 public final void setDaemon(boolean daemon
) {
194 this.daemon
= daemon
;
198 * Sets the maximum priority of the group.
200 * First, the <code>checkAccess</code> method of this thread group is
201 * called with no arguments; this may result in a security exception.
203 * Threads in the thread group that already have a higher priority
206 * @param pri the new priority of the thread group.
207 * @exception SecurityException if the current thread cannot modify
209 * @see java.lang.SecurityException
210 * @see java.lang.ThreadGroup#checkAccess()
213 public final void setMaxPriority(int pri
) {
215 ThreadGroup
[] groupsSnapshot
;
216 synchronized (this) {
218 if (pri
< Thread
.MIN_PRIORITY
) {
219 maxPriority
= Thread
.MIN_PRIORITY
;
220 } else if (pri
< maxPriority
) {
223 ngroupsSnapshot
= ngroups
;
224 if (groups
!= null) {
225 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
226 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
228 groupsSnapshot
= null;
231 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
232 groupsSnapshot
[i
].setMaxPriority(pri
);
237 * Tests if this thread group is either the thread group
238 * argument or one of its ancestor thread groups.
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.
246 public final boolean parentOf(ThreadGroup g
) {
247 for (; g
!= null ; g
= g
.parent
) {
256 * Determines if the currently running thread has permission to
257 * modify this thread group.
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>.
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)
268 public final void checkAccess() {
269 SecurityManager security
= System
.getSecurityManager();
270 if (security
!= null) {
271 security
.checkAccess(this);
276 * Returns an estimate of the number of active threads in this
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.
283 public int activeCount() {
285 // Snapshot sub-group data so we don't hold this lock
286 // while our children are computing.
288 ThreadGroup
[] groupsSnapshot
;
289 synchronized (this) {
294 ngroupsSnapshot
= ngroups
;
295 if (groups
!= null) {
296 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
297 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
299 groupsSnapshot
= null;
302 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
303 result
+= groupsSnapshot
[i
].activeCount();
309 * Copies into the specified array every active thread in this
310 * thread group and its subgroups.
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
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()
322 public int enumerate(Thread list
[]) {
323 return enumerate(list
, 0, true);
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.
333 * An application should use the <code>activeCount</code> method to
334 * get an estimate of how big the array should be.
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
340 * @return the number of threads placed into the array.
341 * @see java.lang.ThreadGroup#activeCount()
344 public int enumerate(Thread list
[], boolean recurse
) {
345 return enumerate(list
, 0, recurse
);
348 private int enumerate(Thread list
[], int n
, boolean recurse
) {
349 int ngroupsSnapshot
= 0;
350 ThreadGroup
[] groupsSnapshot
= null;
351 synchronized (this) {
356 if (nt
> list
.length
- n
) {
357 nt
= list
.length
- n
;
360 System
.arraycopy(threads
, 0, list
, n
, nt
);
364 ngroupsSnapshot
= ngroups
;
365 if (groups
!= null) {
366 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
367 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
369 groupsSnapshot
= null;
374 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
375 n
= groupsSnapshot
[i
].enumerate(list
, n
, true);
382 * Returns an estimate of the number of active groups in this
385 * @return the number of active thread groups with this thread group as
389 public int activeGroupCount() {
391 ThreadGroup
[] groupsSnapshot
;
392 synchronized (this) {
396 ngroupsSnapshot
= ngroups
;
397 if (groups
!= null) {
398 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
399 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
401 groupsSnapshot
= null;
404 int n
= ngroupsSnapshot
;
405 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
406 n
+= groupsSnapshot
[i
].activeGroupCount();
412 * Copies into the specified array references to every active
413 * subgroup in this thread group.
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.
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()
425 public int enumerate(ThreadGroup list
[]) {
426 return enumerate(list
, 0, true);
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.
435 * An application should use the <code>activeGroupCount</code>
436 * method to get an estimate of how big the array should be.
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()
445 public int enumerate(ThreadGroup list
[], boolean recurse
) {
446 return enumerate(list
, 0, recurse
);
449 private int enumerate(ThreadGroup list
[], int n
, boolean recurse
) {
450 int ngroupsSnapshot
= 0;
451 ThreadGroup
[] groupsSnapshot
= null;
452 synchronized (this) {
457 if (ng
> list
.length
- n
) {
458 ng
= list
.length
- n
;
461 System
.arraycopy(groups
, 0, list
, n
, ng
);
465 ngroupsSnapshot
= ngroups
;
466 if (groups
!= null) {
467 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
468 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
470 groupsSnapshot
= null;
475 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
476 n
= groupsSnapshot
[i
].enumerate(list
, n
, true);
483 * Stops all processes in this thread group.
485 * First, the <code>checkAccess</code> method of this thread group is
486 * called with no arguments; this may result in a security exception.
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.
491 * @exception SecurityException if the current thread is not allowed
492 * to access this thread group or any of the threads in
494 * @see java.lang.SecurityException
495 * @see java.lang.Thread#stop()
496 * @see java.lang.ThreadGroup#checkAccess()
499 public final void stop() {
501 ThreadGroup
[] groupsSnapshot
;
502 synchronized (this) {
504 for (int i
= 0 ; i
< nthreads
; i
++) {
507 ngroupsSnapshot
= ngroups
;
508 if (groups
!= null) {
509 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
510 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
512 groupsSnapshot
= null;
515 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
516 groupsSnapshot
[i
].stop();
521 * Suspends all processes in this thread group.
523 * First, the <code>checkAccess</code> method of this thread group is
524 * called with no arguments; this may result in a security exception.
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.
529 * @exception SecurityException if the current thread is not allowed
530 * to access this thread group or any of the threads in
532 * @see java.lang.SecurityException
533 * @see java.lang.Thread#suspend()
534 * @see java.lang.ThreadGroup#checkAccess()
537 public final void suspend() {
539 ThreadGroup
[] groupsSnapshot
;
540 synchronized (this) {
542 for (int i
= 0 ; i
< nthreads
; i
++) {
543 threads
[i
].suspend();
545 ngroupsSnapshot
= ngroups
;
546 if (groups
!= null) {
547 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
548 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
550 groupsSnapshot
= null;
553 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
554 groupsSnapshot
[i
].suspend();
559 * Resumes all processes in this thread group.
561 * First, the <code>checkAccess</code> method of this thread group is
562 * called with no arguments; this may result in a security exception.
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.
567 * @exception SecurityException if the current thread is not allowed to
568 * access this thread group or any of the threads in the
570 * @see java.lang.SecurityException
571 * @see java.lang.Thread#resume()
572 * @see java.lang.ThreadGroup#checkAccess()
575 public final void resume() {
577 ThreadGroup
[] groupsSnapshot
;
578 synchronized (this) {
580 for (int i
= 0 ; i
< nthreads
; i
++) {
583 ngroupsSnapshot
= ngroups
;
584 if (groups
!= null) {
585 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
586 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
588 groupsSnapshot
= null;
591 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
592 groupsSnapshot
[i
].resume();
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.
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
607 public final void destroy() {
609 ThreadGroup
[] groupsSnapshot
;
610 synchronized (this) {
612 if (destroyed
|| (nthreads
> 0)) {
613 throw new IllegalThreadStateException();
615 ngroupsSnapshot
= ngroups
;
616 if (groups
!= null) {
617 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
618 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
620 groupsSnapshot
= null;
622 if (parent
!= null) {
630 for (int i
= 0 ; i
< ngroupsSnapshot
; i
+= 1) {
631 groupsSnapshot
[i
].destroy();
633 if (parent
!= null) {
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.
643 private final void add(ThreadGroup g
){
644 synchronized (this) {
646 throw new IllegalThreadStateException();
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
);
657 // This is done last so it doesn't matter in case the
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.
668 private void remove(ThreadGroup g
) {
669 synchronized (this) {
673 for (int i
= 0 ; i
< ngroups
; i
++) {
674 if (groups
[i
] == g
) {
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;
686 if (daemon
&& (nthreads
== 0) && (ngroups
== 0)) {
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.
698 synchronized (this) {
700 throw new IllegalThreadStateException();
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
;
709 threads
[nthreads
] = t
;
711 // This is done last so it doesn't matter in case the
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.
722 void remove(Thread t
) {
723 synchronized (this) {
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;
739 if (daemon
&& (nthreads
== 0) && (ngroups
== 0)) {
746 * Prints information about this thread group to the standard
747 * output. This method is useful only for debugging.
754 void list(PrintStream out
, int indent
) {
756 ThreadGroup
[] groupsSnapshot
;
757 synchronized (this) {
758 for (int j
= 0 ; j
< indent
; j
++) {
763 for (int i
= 0 ; i
< nthreads
; i
++) {
764 for (int j
= 0 ; j
< indent
; j
++) {
767 out
.println(threads
[i
]);
769 ngroupsSnapshot
= ngroups
;
770 if (groups
!= null) {
771 groupsSnapshot
= new ThreadGroup
[ngroupsSnapshot
];
772 System
.arraycopy(groups
, 0, groupsSnapshot
, 0, ngroupsSnapshot
);
774 groupsSnapshot
= null;
777 for (int i
= 0 ; i
< ngroupsSnapshot
; i
++) {
778 groupsSnapshot
[i
].list(out
, indent
);
783 * Called by the Java Virtual Machine when a thread in this
784 * thread group stops because of an uncaught exception.
786 * The <code>uncaughtException</code> method of
787 * <code>ThreadGroup</code> does the following:
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.
799 * Applications can override this method in subclasses of
800 * <code>ThreadGroup</code> to provide alternative handling of
801 * uncaught exceptions.
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)
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
);
819 * Used by VM to control lowmem implicit suspension.
823 public boolean allowThreadSuspension(boolean b
) {
824 this.vmAllowSuspension
= b
;
826 VM
.unsuspendSomeThreads();
832 * Returns a string representation of this Thread group.
834 * @return a string representation of this thread group.
837 public String
toString() {
838 return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority
+ "]";