001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Roman S. Bushmanov
019: * @version $Revision: 1.1.2.2.4.4 $
020: */package java.lang;
021:
022: import java.util.List;
023: import java.util.ArrayList;
024: import java.util.LinkedList;
025: import java.util.Iterator;
026:
027: /**
028: * @com.intel.drl.spec_ref
029: */
030:
031: public class ThreadGroup implements Thread.UncaughtExceptionHandler {
032:
033: /**
034: * Indent used to print information about thread group
035: */
036: private final static String LISTING_INDENT = " ";
037:
038: /**
039: * ThreadGroup lock object
040: */
041: private static class ThreadGroupLock {
042: };
043:
044: private final static ThreadGroupLock lock = new ThreadGroupLock();
045:
046: /**
047: * This group's max priority
048: */
049: int maxPriority = Thread.MAX_PRIORITY;
050:
051: /**
052: * This group's name
053: */
054: String name;
055:
056: /**
057: * Indicates if this thread group was marked as daemon
058: */
059: private boolean daemon;
060:
061: /**
062: * Indicates if this thread group was already destroyed
063: */
064: private boolean destroyed = false;
065:
066: /**
067: * List of subgroups of this thread group
068: */
069: private LinkedList<ThreadGroup> groups = new LinkedList<ThreadGroup>();
070:
071: /**
072: * Parent thread group of this thread group.
073: *
074: * FIXME: this field must be private. It is changed to package-private
075: * to be accessible from FT SecurityManager class. Both SecurityManager
076: * and ThreadGroup are considered as non-Kernel by FT, but ThreadGroup
077: * is Kernel now in DRL.
078: */
079: ThreadGroup parent;
080:
081: /**
082: * All threads in the group.
083: */
084: private LinkedList<Thread> threads = new LinkedList<Thread>();
085:
086: /**
087: * @com.intel.drl.spec_ref
088: */
089: public ThreadGroup(String name) {
090: this (Thread.currentThread().group, name);
091: }
092:
093: /**
094: * @com.intel.drl.spec_ref
095: */
096: public ThreadGroup(ThreadGroup parent, String name) {
097: if (parent == null) {
098: throw new NullPointerException(
099: "The parent thread group specified is null!");
100: }
101: parent.checkAccess();
102: this .name = name;
103: this .parent = parent;
104: this .daemon = parent.daemon;
105: this .maxPriority = parent.maxPriority;
106: parent.add(this );
107: }
108:
109: /**
110: * This constructor is used to create the system thread group
111: */
112: ThreadGroup() {
113: this .parent = null;
114: this .name = "system";
115: this .daemon = false;
116: }
117:
118: /**
119: * @com.intel.drl.spec_ref Note: A thread is supposed to be active if and
120: * only if it is alive.
121: */
122: public int activeCount() {
123: int count = 0;
124: List groupsCopy = null; // a copy of subgroups list
125: List threadsCopy = null; // a copy of threads list
126: synchronized (lock) {
127: if (destroyed) {
128: return 0;
129: }
130: threadsCopy = (List) threads.clone();
131: groupsCopy = (List) groups.clone();
132: }
133:
134: for (Object thread : threadsCopy) {
135: if (((Thread) thread).isAlive()) {
136: count++;
137: }
138: }
139:
140: for (Object group : groupsCopy) {
141: count += ((ThreadGroup) group).activeCount();
142: }
143: return count;
144: }
145:
146: /**
147: * @com.intel.drl.spec_ref
148: */
149: public int activeGroupCount() {
150: int count;
151: List groupsCopy = null; // a copy of subgroups list
152: synchronized (lock) {
153: if (destroyed) {
154: return 0;
155: }
156: count = groups.size();
157: groupsCopy = (List) groups.clone();
158: }
159: for (Object group : (List) groupsCopy) {
160: count += ((ThreadGroup) group).activeGroupCount();
161: }
162: return count;
163: }
164:
165: /**
166: * @com.intel.drl.spec_ref Note: This implementation always returns
167: * <code>false</code>.
168: * @deprecated
169: */
170: public boolean allowThreadSuspension(boolean b) {
171: return false;
172: }
173:
174: /**
175: * @com.intel.drl.spec_ref
176: */
177: public final void checkAccess() {
178: SecurityManager securityManager = System.getSecurityManager();
179: if (securityManager != null) {
180: securityManager.checkAccess(this );
181: }
182: }
183:
184: /**
185: * @com.intel.drl.spec_ref
186: */
187: public final void destroy() {
188: checkAccess();
189: synchronized (lock) {
190: if (destroyed) {
191: throw new IllegalThreadStateException(
192: "The thread group " + name
193: + " is already destroyed!");
194: }
195: nonsecureDestroy();
196: }
197: }
198:
199: /**
200: * @com.intel.drl.spec_ref
201: */
202: public int enumerate(Thread[] list) {
203: checkAccess();
204: return enumerate(list, 0, true);
205: }
206:
207: /**
208: * @com.intel.drl.spec_ref
209: */
210: public int enumerate(Thread[] list, boolean recurse) {
211: checkAccess();
212: return enumerate(list, 0, recurse);
213: }
214:
215: /**
216: * @com.intel.drl.spec_ref
217: */
218: public int enumerate(ThreadGroup[] list) {
219: checkAccess();
220: return enumerate(list, 0, true);
221: }
222:
223: /**
224: * @com.intel.drl.spec_ref
225: */
226: public int enumerate(ThreadGroup[] list, boolean recurse) {
227: checkAccess();
228: return enumerate(list, 0, recurse);
229: }
230:
231: /**
232: * @com.intel.drl.spec_ref
233: */
234: public final int getMaxPriority() {
235: return maxPriority;
236: }
237:
238: /**
239: * @com.intel.drl.spec_ref
240: */
241: public final String getName() {
242: return name;
243: }
244:
245: /**
246: * @com.intel.drl.spec_ref
247: */
248: public final ThreadGroup getParent() {
249: if (parent != null) {
250: parent.checkAccess();
251: }
252: return parent;
253: }
254:
255: /**
256: * @com.intel.drl.spec_ref
257: */
258: public final void interrupt() {
259: checkAccess();
260: nonsecureInterrupt();
261: }
262:
263: /**
264: * @com.intel.drl.spec_ref
265: */
266: public final boolean isDaemon() {
267: return daemon;
268: }
269:
270: /**
271: * @com.intel.drl.spec_ref
272: */
273: public boolean isDestroyed() {
274: return destroyed;
275: }
276:
277: /**
278: * @com.intel.drl.spec_ref
279: */
280: public void list() {
281: list("");
282: }
283:
284: /**
285: * @com.intel.drl.spec_ref
286: */
287: public final boolean parentOf(ThreadGroup group) {
288: ThreadGroup parent = group;
289: while (parent != null) {
290: if (this == parent) {
291: return true;
292: }
293: parent = parent.parent;
294: }
295: return false;
296: }
297:
298: /**
299: * @com.intel.drl.spec_ref
300: * @deprecated
301: */
302: public final void resume() {
303: checkAccess();
304: nonsecureResume();
305: }
306:
307: /**
308: * @com.intel.drl.spec_ref
309: */
310: public final void setDaemon(boolean daemon) {
311: checkAccess();
312: this .daemon = daemon;
313: }
314:
315: /**
316: * @com.intel.drl.spec_ref
317: */
318: public final void setMaxPriority(int priority) {
319: checkAccess();
320:
321: /*
322: * GMJ : note that this is to match a known bug in the RI
323: * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708197
324: * We agreed to follow bug for now to prevent breaking apps
325: */
326: if (priority > Thread.MAX_PRIORITY) {
327: return;
328: }
329: if (priority < Thread.MIN_PRIORITY) {
330: this .maxPriority = Thread.MIN_PRIORITY;
331: return;
332: }
333: int new_priority = (parent != null && parent.maxPriority < priority) ? parent.maxPriority
334: : priority;
335:
336: nonsecureSetMaxPriority(new_priority);
337: }
338:
339: /**
340: * @com.intel.drl.spec_ref
341: * @deprecated
342: */
343: public final void stop() {
344: checkAccess();
345: nonsecureStop();
346: }
347:
348: /**
349: * @com.intel.drl.spec_ref
350: * @deprecated
351: */
352: public final void suspend() {
353: checkAccess();
354: nonsecureSuspend();
355: }
356:
357: /**
358: * @com.intel.drl.spec_ref
359: */
360: public String toString() {
361: return getClass().getName() + "[name=" + name + ",maxpri="
362: + maxPriority + "]";
363: }
364:
365: /**
366: * @com.intel.drl.spec_ref
367: */
368: public void uncaughtException(Thread thread, Throwable throwable) {
369: if (parent != null) {
370: parent.uncaughtException(thread, throwable);
371: return;
372: }
373: Thread.UncaughtExceptionHandler defaultHandler = Thread
374: .getDefaultUncaughtExceptionHandler();
375: if (defaultHandler != null) {
376: defaultHandler.uncaughtException(thread, throwable);
377: return;
378: }
379: if (throwable instanceof ThreadDeath) {
380: return;
381: }
382: System.err.println("Uncaught exception in " + thread.getName()
383: + ":");
384: throwable.printStackTrace();
385: }
386:
387: /**
388: * Adds a thread to this thread group
389: */
390: void add(Thread thread) {
391: synchronized (lock) {
392: if (destroyed) {
393: throw new IllegalThreadStateException(
394: "The thread group is already destroyed!");
395: }
396: threads.add(thread);
397: }
398: }
399:
400: /**
401: * Checks that group is not destroyed
402: */
403: void checkGroup() {
404: synchronized (lock) {
405: if (destroyed) {
406: throw new IllegalThreadStateException(
407: "The thread group is already destroyed!");
408: }
409: }
410: }
411:
412: /**
413: * Removes a thread from this thread group
414: */
415: void remove(Thread thread) {
416: synchronized (lock) {
417: if (destroyed) {
418: return;
419: }
420: threads.remove(thread);
421: thread.group = null;
422: if (daemon && threads.isEmpty() && groups.isEmpty()) {
423: // destroy this group
424: if (parent != null) {
425: parent.remove(this );
426: destroyed = true;
427: }
428: }
429: }
430: }
431:
432: /**
433: * Adds a subgroup to this thread group
434: */
435: private void add(ThreadGroup group) {
436: synchronized (lock) {
437: if (destroyed) {
438: throw new IllegalThreadStateException(
439: "The thread group is already destroyed!");
440: }
441: groups.add(group);
442: }
443: }
444:
445: /**
446: * Used by GetThreadGroupChildren() jvmti function.
447: * @return Object[] array of 2 elements: first - Object[] array of active
448: * child threads; second - Object[] array of child groups.
449: */
450: @SuppressWarnings("unused")
451: private Object[] getActiveChildren() {
452: ArrayList<Thread> threadsCopy = new ArrayList<Thread>(threads
453: .size());
454: ArrayList<ThreadGroup> groupsCopy = new ArrayList<ThreadGroup>(
455: groups.size());
456:
457: synchronized (lock) {
458: if (destroyed) {
459: return new Object[] { null, null };
460: }
461:
462: for (Thread thread : threads) {
463: threadsCopy.add(thread);
464: }
465:
466: for (ThreadGroup group : groups) {
467: groupsCopy.add(group);
468: }
469: }
470:
471: ArrayList<Thread> activeThreads = new ArrayList<Thread>(
472: threadsCopy.size());
473:
474: // filter out alive threads
475: for (Thread thread : threadsCopy) {
476: if (thread.isAlive()) {
477: activeThreads.add(thread);
478: }
479: }
480:
481: return new Object[] { activeThreads.toArray(),
482: groupsCopy.toArray() };
483: }
484:
485: /**
486: * Copies all the threads contained in the snapshot of this thread group to
487: * the array specified starting from the specified position. <br>
488: * If the specified array is not long enough to take all the threads of this
489: * thread group, the exta threads are silently ignored. <br>
490: *
491: * @param list an array to copy threads to
492: * @param offset position in this array to start copying from
493: * @param recurse indicates if the threads contained in the subgroups of
494: * this thread group should be recursively copied to the array
495: * specified
496: * @return the number of threads in the array after the copying is
497: * done
498: */
499: private int enumerate(Thread[] list, int offset, boolean recurse) {
500: if (list.length == 0) {
501: return 0;
502: }
503: List groupsCopy = null; // a copy of subgroups list
504: List threadsCopy = null; // a copy of threads list
505: synchronized (lock) {
506: if (destroyed) {
507: return offset;
508: }
509: threadsCopy = (List) threads.clone();
510: if (recurse) {
511: groupsCopy = (List) groups.clone();
512: }
513: }
514: for (Object thread : threadsCopy) {
515: if (((Thread) thread).isAlive()) {
516: list[offset++] = ((Thread) thread);
517: if (offset == list.length) {
518: return offset;
519: }
520: }
521: }
522: if (recurse) {
523: for (Iterator it = groupsCopy.iterator(); offset < list.length
524: && it.hasNext();) {
525: offset = ((ThreadGroup) it.next()).enumerate(list,
526: offset, true);
527: }
528: }
529: return offset;
530: }
531:
532: /**
533: * Copies all the subgroups contained in the snapshot of this thread group
534: * to the array specified starting from the specified position. <br>
535: * If the specified array is not long enough to take all the subgroups of
536: * this thread group, the exta subgroups are silently ignored. <br>
537: *
538: * @param list an array to copy subgroups to
539: * @param offset position in this array to start copying from
540: * @param recurse indicates if the subgroups contained in the subgroups of
541: * this thread group should be recursively copied to the array
542: * specified
543: * @return the number of subgroups in the array after the copying
544: * is done
545: */
546: private int enumerate(ThreadGroup[] list, int offset,
547: boolean recurse) {
548: if (destroyed) {
549: return offset;
550: }
551: int firstGroupIdx = offset;
552: synchronized (lock) {
553: for (Object group : groups) {
554: list[offset++] = (ThreadGroup) group;
555: if (offset == list.length) {
556: return offset;
557: }
558: }
559: }
560: if (recurse) {
561: int lastGroupIdx = offset;
562: for (int i = firstGroupIdx; offset < list.length
563: && i < lastGroupIdx; i++) {
564: offset = list[i].enumerate(list, offset, true);
565: }
566: }
567: return offset;
568: }
569:
570: /**
571: * Recursively prints the information about this thread group using
572: * <code>prefix</code> string as indent.
573: */
574: private void list(String prefix) {
575: System.out.println(prefix + toString());
576: prefix += LISTING_INDENT;
577: List groupsCopy = null; // a copy of subgroups list
578: List threadsCopy = null; // a copy of threads list
579: synchronized (lock) {
580: threadsCopy = (List) threads.clone();
581: groupsCopy = (List) groups.clone();
582: }
583: for (Object thread : threadsCopy) {
584: System.out.println(prefix + (Thread) thread);
585: }
586: for (Object group : groupsCopy) {
587: ((ThreadGroup) group).list(prefix);
588: }
589: }
590:
591: /**
592: * Destroys this thread group without any security checks. We add this
593: * method to avoid calls to the checkAccess() method on subgroups.
594: * All non-empty subgroups are removed recursievely.
595: * If at least one subgroup is not empty, IllegalThreadStateException
596: * will be thrown.
597: * @return false if this ThreadGroup is not empty
598: */
599: private void nonsecureDestroy() {
600:
601: List groupsCopy = null;
602:
603: synchronized (lock) {
604: if (threads.size() > 0) {
605: throw new IllegalThreadStateException(
606: "The thread group " + name + " is not empty");
607: }
608: destroyed = true;
609: groupsCopy = (List) groups.clone();
610: }
611:
612: if (parent != null) {
613: parent.remove(this );
614: }
615:
616: for (Object group : groupsCopy) {
617: ((ThreadGroup) group).nonsecureDestroy();
618: }
619: }
620:
621: /**
622: * Interrupts this thread group without any security checks. We add this
623: * method to avoid calls to the checkAccess() method on subgroups
624: */
625: private void nonsecureInterrupt() {
626: synchronized (lock) {
627: for (Object thread : threads) {
628: ((Thread) thread).interrupt();
629: }
630: for (Object group : groups) {
631: ((ThreadGroup) group).nonsecureInterrupt();
632: }
633: }
634: }
635:
636: /**
637: * Resumes this thread group without any security checks. We add this method
638: * to avoid calls to the checkAccess() method on subgroups
639: */
640: private void nonsecureResume() {
641: synchronized (lock) {
642: for (Object thread : threads) {
643: ((Thread) thread).resume();
644: }
645: for (Object group : groups) {
646: ((ThreadGroup) group).nonsecureResume();
647: }
648: }
649: }
650:
651: /**
652: * Sets the maximum priority allowed for this thread group and its subgroups.
653: * We add this method to avoid calls to the checkAccess() method on subgroups
654: */
655: private void nonsecureSetMaxPriority(int priority) {
656: synchronized (lock) {
657: this .maxPriority = priority;
658:
659: for (Object group : groups) {
660: ((ThreadGroup) group).nonsecureSetMaxPriority(priority);
661: }
662: }
663: }
664:
665: /**
666: * Stops this thread group without any security checks.
667: * We add this method to avoid calls to the checkAccess() method on subgroups
668: */
669: private void nonsecureStop() {
670: synchronized (lock) {
671: for (Object thread : threads) {
672: ((Thread) thread).stop();
673: }
674: for (Object group : groups) {
675: ((ThreadGroup) group).nonsecureStop();
676: }
677: }
678: }
679:
680: /**
681: * Suspends this thread group without any security checks.
682: * We add this method to avoid calls to the checkAccess() method on subgroups
683: */
684: private void nonsecureSuspend() {
685: synchronized (lock) {
686: for (Object thread : threads) {
687: ((Thread) thread).suspend();
688: }
689: for (Object group : groups) {
690: ((ThreadGroup) group).nonsecureSuspend();
691: }
692: }
693: }
694:
695: /**
696: * Removes the specified thread group from this group.
697: *
698: * @param group group to be removed from this one
699: */
700: private void remove(ThreadGroup group) {
701: synchronized (lock) {
702: groups.remove(group);
703: if (daemon && threads.isEmpty() && groups.isEmpty()) {
704: // destroy this group
705: if (parent != null) {
706: parent.remove(this );
707: destroyed = true;
708: }
709: }
710: }
711: }
712: }
|