1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 /**
18 * @author Roman S. Bushmanov
19 */
20
21 package java.lang;
22
23 import java.security.AccessController;
24 import java.util.HashMap;
25 import java.util.IdentityHashMap;
26 import java.util.Iterator;
27 import java.util.Map;
28
29 import org.apache.harmony.lang.RuntimePermissionCollection;
30 import org.apache.harmony.security.fortress.SecurityUtils;
31 import org.apache.harmony.vm.VMStack;
32
33 /**
34 * @com.intel.drl.spec_ref
35 */
36 public class Thread implements Runnable {
37
38 /**
39 * @com.intel.drl.spec_ref
40 */
41 public static final int MAX_PRIORITY = 10;
42
43 /**
44 * @com.intel.drl.spec_ref
45 */
46 public static final int MIN_PRIORITY = 1;
47
48 /**
49 * @com.intel.drl.spec_ref
50 */
51 public static final int NORM_PRIORITY = 5;
52
53 /**
54 * Indent string used to print stack trace
55 */
56 private static final String STACK_TRACE_INDENT = " ";
57
58 /**
59 * This thread's thread group
60 */
61 ThreadGroup group;
62
63 /**
64 * This thread's context class loader
65 */
66 private ClassLoader contextClassLoader;
67
68 /**
69 * Indicates whether this thread was marked as daemon
70 */
71 private boolean daemon;
72
73 /**
74 * Thread's name
75 */
76 private String name;
77
78 /**
79 * Thread's priority
80 */
81 private int priority;
82
83 /**
84 * Stack size to be passed to VM for thread execution
85 */
86 private long stackSize;
87
88 /**
89 * Indicates if the thread was already started
90 */
91 boolean started = false;
92
93
94 /**
95 * Indicates if the thread is alive.
96 */
97 boolean isAlive = false;
98
99 /**
100 * Thread's target - a <code>Runnable</code> object whose <code>run</code>
101 * method should be invoked
102 */
103 private Runnable target;
104
105
106 /**
107 * Uncaught exception handler for this thread
108 */
109 private UncaughtExceptionHandler exceptionHandler = null;
110
111 /**
112 * Default uncaught exception handler
113 */
114 private static UncaughtExceptionHandler defaultExceptionHandler = null;
115
116 /**
117 * Thread's ID
118 */
119 private long threadId;
120
121 /**
122 * Counter used to generate thread's ID
123 */
124 private static long threadOrdinalNum = 0;
125
126 /**
127 * Synchronization is done using internal lock.
128 */
129 Object lock = new Object();
130
131 /**
132 * used to generate a default thread name
133 */
134 private static final String THREAD = "Thread-";
135
136 /**
137 * System thread group for keeping helper threads.
138 */
139 static ThreadGroup systemThreadGroup = null;
140
141 /**
142 * Main thread group.
143 */
144 static ThreadGroup mainThreadGroup = null;
145
146 /*
147 * Number of threads that was created w/o garbage collection.
148 */
149 private static int currentGCWatermarkCount = 0;
150
151 /*
152 * Max number of threads to be created w/o GC, required collect dead Thread
153 * references.
154 */
155 private static final int GC_WATERMARK_MAX_COUNT = 700;
156
157 /*
158 * ThreadLocal values: local and inheritable
159 *
160 */
161 ThreadLocal.Values localValues;
162 ThreadLocal.Values inheritableValues;
163
164 /**
165 * @com.intel.drl.spec_ref
166 */
167 public Thread() {
168 this(null, null, THREAD, 0);
169 }
170
171 /**
172 * @com.intel.drl.spec_ref
173 */
174 public Thread(Runnable target) {
175 this(null, target, THREAD, 0);
176 }
177
178 /**
179 * @com.intel.drl.spec_ref
180 */
181 public Thread(Runnable target, String name) {
182 this(null, target, name, 0);
183 }
184
185 /**
186 * @com.intel.drl.spec_ref
187 */
188 public Thread(String name) {
189 this(null, null, name, 0);
190 }
191
192 /**
193 * @com.intel.drl.spec_ref
194 */
195 public Thread(ThreadGroup group, Runnable target) {
196 this(group, target, THREAD, 0);
197 }
198
199 /**
200 * @com.intel.drl.spec_ref
201 */
202 public Thread(ThreadGroup group, Runnable target, String name) {
203 this(group, target, name, 0);
204 }
205
206 /**
207 * Creates a new thread object for the thread attached to VM.
208 * The first attached thread is the main thread.
209 *
210 * @param group determines the thread group to place the thread in
211 * @param name thread's name
212 * @param nativeAddr address of the attached native thread
213 * @param stackeSize size of the thread's stack
214 * @param priority thread's priority
215 * @param daemon true if the thread is daemon, false otherwise
216 */
217 Thread(ThreadGroup group, String name, long nativeAddr,
218 long stackSize, int priority, boolean daemon) {
219
220 ClassLoader contextLoader = null;
221
222 if (group == null) {
223 if (systemThreadGroup == null) {
224 // This is main thread.
225 systemThreadGroup = new ThreadGroup();
226 mainThreadGroup = new ThreadGroup(systemThreadGroup, "main");
227 group = mainThreadGroup;
228 } else {
229 group = mainThreadGroup;
230 }
231 }
232
233 this.group = group;
234 this.stackSize = stackSize;
235 this.priority = priority;
236 this.daemon = daemon;
237 this.threadId = getNextThreadId();
238 this.name = (name != null) ? name : THREAD + threadId;
239 // Each thread created from JNI has bootstrap class loader as
240 // its context class loader. The only exception is the main thread
241 // which has system class loader as its context class loader.
242 this.contextClassLoader = contextLoader;
243 this.target = null;
244 // The thread is actually running.
245 this.isAlive = true;
246 this.started = true;
247
248 ThreadWeakRef newRef = new ThreadWeakRef(this);
249 newRef.setNativeAddr(nativeAddr);
250
251 SecurityUtils.putContext(this, AccessController.getContext());
252 // adding the thread to the thread group should be the last action
253 group.add(this);
254
255 Thread parent = currentThread();
256 if (parent != null && parent.inheritableValues != null) {
257 inheritableValues = new ThreadLocal.Values(parent.inheritableValues);
258 }
259
260 }
261
262 /**
263 * @com.intel.drl.spec_ref
264 */
265 public Thread(ThreadGroup group, Runnable target, String name,
266 long stackSize) {
267
268 Thread currentThread = VMThreadManager.currentThread();
269 SecurityManager securityManager = System.getSecurityManager();
270
271 ThreadGroup threadGroup = null;
272 if (group != null) {
273 if (securityManager != null) {
274 securityManager.checkAccess(group);
275 }
276 threadGroup = group;
277 } else if (securityManager != null) {
278 threadGroup = securityManager.getThreadGroup();
279 }
280 if (threadGroup == null) {
281 threadGroup = currentThread.group;
282 }
283
284 threadGroup.checkGroup();
285
286 this.group = threadGroup;
287 this.daemon = currentThread.daemon;
288 this.contextClassLoader = currentThread.contextClassLoader;
289 this.target = target;
290 this.stackSize = stackSize;
291 this.priority = currentThread.priority;
292 this.threadId = getNextThreadId();
293 // throws NullPointerException if the given name is null
294 this.name = (name != THREAD) ? this.name = name.toString() :
295 THREAD + threadId;
296
297
298
299 checkGCWatermark();
300
301 ThreadWeakRef oldRef = ThreadWeakRef.poll();
302 ThreadWeakRef newRef = new ThreadWeakRef(this);
303
304 long oldPointer = (oldRef == null) ? 0 : oldRef.getNativeAddr();
305 long newPointer = VMThreadManager.init(this, newRef, oldPointer);
306 if (newPointer == 0) {
307 throw new OutOfMemoryError("Failed to create new thread");
308 }
309 newRef.setNativeAddr(newPointer);
310
311 SecurityUtils.putContext(this, AccessController.getContext());
312 checkAccess();
313
314 Thread parent = currentThread();
315 if (parent != null && parent.inheritableValues != null) {
316 inheritableValues = new ThreadLocal.Values(parent.inheritableValues);
317 }
318
319 }
320
321 /**
322 * @com.intel.drl.spec_ref
323 */
324 public Thread(ThreadGroup group, String name) {
325 this(group, null, name, 0);
326 }
327
328 /**
329 * @com.intel.drl.spec_ref
330 */
331 public static int activeCount() {
332 return currentThread().group.activeCount();
333 }
334
335 /**
336 * @com.intel.drl.spec_ref
337 */
338 public static Thread currentThread() {
339 return VMThreadManager.currentThread();
340 }
341
342 /**
343 * @com.intel.drl.spec_ref
344 */
345 public static void dumpStack() {
346 StackTraceElement[] stack = (new Throwable()).getStackTrace();
347 System.err.println("Stack trace");
348 for (int i = 0; i < stack.length; i++) {
349 System.err.println(STACK_TRACE_INDENT + stack[i]);
350 }
351 }
352
353 /**
354 * @com.intel.drl.spec_ref
355 */
356 public static int enumerate(Thread[] list) {
357 return currentThread().group.enumerate(list);
358 }
359
360 /**
361 * @com.intel.drl.spec_ref
362 */
363 public static boolean holdsLock(Object object) {
364 if (object == null) {
365 throw new NullPointerException();
366 }
367 return VMThreadManager.holdsLock(object);
368 }
369
370 /**
371 * @com.intel.drl.spec_ref
372 */
373 public static boolean interrupted() {
374 return VMThreadManager.isInterrupted();
375 }
376
377 /**
378 * @com.intel.drl.spec_ref
379 */
380 public static void sleep(long millis) throws InterruptedException {
381 sleep(millis, 0);
382 }
383
384 /**
385 * @com.intel.drl.spec_ref
386 */
387 public static void sleep(long millis, int nanos)
388 throws InterruptedException {
389 if (millis < 0 || nanos < 0 || nanos > 999999) {
390 throw new IllegalArgumentException(
391 "Arguments don't match the expected range!");
392 }
393 int status = VMThreadManager.sleep(millis, nanos);
394 if (status == VMThreadManager.TM_ERROR_INTERRUPT) {
395 throw new InterruptedException();
396 } else if (status != VMThreadManager.TM_ERROR_NONE) {
397 throw new InternalError(
398 "Thread Manager internal error " + status);
399 }
400 }
401
402 /**
403 * @com.intel.drl.spec_ref
404 */
405 public static void yield() {
406 int status = VMThreadManager.yield();
407 if (status != VMThreadManager.TM_ERROR_NONE) {
408 throw new InternalError(
409 "Thread Manager internal error " + status);
410 }
411 }
412
413 /**
414 * @com.intel.drl.spec_ref
415 */
416 public final void checkAccess() {
417 SecurityManager securityManager = System.getSecurityManager();
418 if (securityManager != null) {
419 securityManager.checkAccess(this);
420 }
421 }
422
423 /**
424 * @com.intel.drl.spec_ref
425 * @deprecated
426 */
427 public int countStackFrames() {
428 return 0; //deprecated
429 }
430
431 /**
432 * @com.intel.drl.spec_ref
433 * @deprecated
434 */
435 public void destroy() {
436 // this method is not implemented
437 throw new NoSuchMethodError();
438 }
439
440 /**
441 * @com.intel.drl.spec_ref
442 */
443 public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
444 SecurityManager securityManager = System.getSecurityManager();
445 if (securityManager != null) {
446 securityManager
447 .checkPermission(RuntimePermissionCollection.GET_STACK_TRACE_PERMISSION);
448 securityManager
449 .checkPermission(RuntimePermissionCollection.MODIFY_THREAD_GROUP_PERMISSION);
450 }
451
452 // find the initial ThreadGroup in the tree
453 ThreadGroup parent = new ThreadGroup(currentThread().getThreadGroup(), "Temporary");
454 ThreadGroup newParent = parent.getParent();
455 parent.destroy();
456 while (newParent != null) {
457 parent = newParent;
458 newParent = parent.getParent();
459 }
460 int threadsCount = parent.activeCount() + 1;
461 int count;
462 Thread[] liveThreads;
463 while (true) {
464 liveThreads = new Thread[threadsCount];
465 count = parent.enumerate(liveThreads);
466 if (count == threadsCount) {
467 threadsCount *= 2;
468 } else {
469 break;
470 }
471 }
472 Map<Thread, StackTraceElement[]> map = new HashMap<Thread, StackTraceElement[]>(count + 1);
473 for (int i = 0; i < count; i++) {
474 StackTraceElement[] ste = liveThreads[i].getStackTrace();
475 if (ste.length != 0) {
476 map.put(liveThreads[i], ste);
477 }
478 }
479 return map;
480 }
481
482 /**
483 * @com.intel.drl.spec_ref
484 */
485 public ClassLoader getContextClassLoader() {
486 synchronized (lock) {
487 // First, if the conditions
488 // 1) there is a security manager
489 // 2) the caller's class loader is not null
490 // 3) the caller's class loader is not the same as or an
491 // ancestor of contextClassLoader
492 // are satisfied we should perform a security check.
493 SecurityManager securityManager = System.getSecurityManager();
494 if (securityManager != null) {
495 //the first condition is satisfied
496 ClassLoader callerClassLoader = VMClassRegistry
497 .getClassLoader(VMStack.getCallerClass(0));
498 if (callerClassLoader != null) {
499 //the second condition is satisfied
500 ClassLoader classLoader = contextClassLoader;
501 while (classLoader != null) {
502 if (classLoader == callerClassLoader) {
503 //the third condition is not satisfied
504 return contextClassLoader;
505 }
506 classLoader = classLoader.getParent();
507 }
508 //the third condition is satisfied
509 securityManager
510 .checkPermission(RuntimePermissionCollection.GET_CLASS_LOADER_PERMISSION);
511 }
512 }
513 return contextClassLoader;
514 }
515 }
516
517 /**
518 * @com.intel.drl.spec_ref
519 */
520 public final String getName() {
521 return name;
522 }
523
524 /**
525 * @com.intel.drl.spec_ref
526 */
527 public final int getPriority() {
528 return priority;
529 }
530
531 /**
532 * @com.intel.drl.spec_ref
533 */
534 public StackTraceElement[] getStackTrace() {
535 if (currentThread() != this) {
536 SecurityManager securityManager = System.getSecurityManager();
537 if (securityManager != null) {
538 securityManager
539 .checkPermission(RuntimePermissionCollection.GET_STACK_TRACE_PERMISSION);
540 }
541 }
542 StackTraceElement ste[] = VMStack.getThreadStackTrace(this);
543 return ste != null ? ste : new StackTraceElement[0];
544 }
545
546 /**
547 * @com.intel.drl.spec_ref
548 */
549 public final ThreadGroup getThreadGroup() {
550 return group;
551 }
552
553 /**
554 * @com.intel.drl.spec_ref
555 */
556 public long getId() {
557 return threadId;
558 }
559
560 /**
561 * @com.intel.drl.spec_ref
562 */
563 public void interrupt() {
564 synchronized (lock) {
565 checkAccess();
566 int status = VMThreadManager.interrupt(this);
567 if (status != VMThreadManager.TM_ERROR_NONE) {
568 throw new InternalError(
569 "Thread Manager internal error " + status);
570 }
571 }
572 }
573
574 /**
575 * @com.intel.drl.spec_ref
576 */
577 public final boolean isAlive() {
578 synchronized (lock) {
579 return this.isAlive;
580 }
581 }
582
583
584 /**
585 * @com.intel.drl.spec_ref
586 */
587 public final boolean isDaemon() {
588 return daemon;
589 }
590
591 /**
592 * @com.intel.drl.spec_ref
593 */
594 public boolean isInterrupted() {
595 return VMThreadManager.isInterrupted(this);
596 }
597
598 /**
599 * @com.intel.drl.spec_ref
600 */
601 public final synchronized void join() throws InterruptedException {
602 while (isAlive()) {
603 wait();
604 }
605 }
606
607 /**
608 * @com.intel.drl.spec_ref
609 */
610 public final synchronized void join(long millis) throws InterruptedException {
611 if (millis == 0) {
612 join();
613 } else {
614 long end = System.currentTimeMillis() + millis;
615 while(isAlive()) {
616 wait(millis);
617 millis = end - System.currentTimeMillis();
618 if (millis <= 0) {
619 break;
620 }
621 }
622 }
623 }
624
625 /**
626 * @com.intel.drl.spec_ref
627 */
628 public final synchronized void join(long millis, int nanos)
629 throws InterruptedException {
630 if (millis < 0 || nanos < 0 || nanos > 999999) {
631 throw new IllegalArgumentException();
632 } else if (millis == 0 && nanos == 0) {
633 join();
634 } else {
635 long end = System.nanoTime() + 1000000*millis + (long)nanos;
636 long rest;
637 while (isAlive()) {
638 wait(millis, nanos);
639 rest = end - System.nanoTime();
640 if (rest <= 0)
641 break;
642 nanos = (int)(rest % 1000000);
643 millis = rest / 1000000;
644 }
645 }
646 }
647
648 /**
649 * Note that this is unsnchronized - the assumption is that
650 * hythread does the synchronization for us
651 *
652 * @com.intel.drl.spec_ref
653 * @deprecated
654 */
655 public final void resume() {
656 checkAccess();
657 int status = VMThreadManager.resume(this);
658 if (status != VMThreadManager.TM_ERROR_NONE) {
659 throw new InternalError(
660 "Thread Manager internal error " + status);
661 }
662 }
663
664 /**
665 * @com.intel.drl.spec_ref
666 */
667 public void run() {
668 if (target != null) {
669 target.run();
670 }
671 }
672
673 void runImpl() {
674 synchronized (lock) {
675 this.isAlive = true;
676 this.started = true;
677 lock.notifyAll();
678 }
679
680 run();
681 }
682
683 /**
684 * @com.intel.drl.spec_ref
685 */
686 public void setContextClassLoader(ClassLoader classLoader) {
687 synchronized (lock) {
688 SecurityManager securityManager = System.getSecurityManager();
689 if (securityManager != null) {
690 securityManager
691 .checkPermission(RuntimePermissionCollection.SET_CONTEXT_CLASS_LOADER_PERMISSION);
692 }
693 contextClassLoader = classLoader;
694 }
695 }
696
697 /**
698 * @com.intel.drl.spec_ref We assume that 'active thread' means the same as
699 * 'alive thread'.
700 */
701 public final void setDaemon(boolean daemon) {
702 synchronized (lock) {
703 checkAccess();
704 if (isAlive()) {
705 throw new IllegalThreadStateException();
706 }
707 this.daemon = daemon;
708 }
709 }
710
711 /**
712 * @com.intel.drl.spec_ref New name should not be <code>null</code>.
713 * @throws NullPointerException if new name is <code>null</code>
714 */
715 public final void setName(String name) {
716 checkAccess();
717 // throws NullPointerException if the given name is null
718 this.name = name.toString();
719 }
720
721 /**
722 * @com.intel.drl.spec_ref
723 */
724 public final void setPriority(int priority) {
725 checkAccess();
726 if (priority > MAX_PRIORITY || priority < MIN_PRIORITY) {
727 throw new IllegalArgumentException("Wrong Thread priority value");
728 }
729 ThreadGroup threadGroup = group;
730 this.priority = (priority > threadGroup.maxPriority)
731 ? threadGroup.maxPriority : priority;
732 int status = VMThreadManager.setPriority(this, this.priority);
733 if (status != VMThreadManager.TM_ERROR_NONE) {
734 //throw new InternalError("Thread Manager internal error " + status);
735 }
736 }
737
738 /**
739 * @com.intel.drl.spec_ref
740 */
741 public synchronized void start() {
742 synchronized (lock) {
743 if (started) {
744 //this thread was started
745 throw new IllegalThreadStateException(
746 "This thread was already started!");
747 }
748
749 // adding the thread to the thread group
750 group.add(this);
751
752
753 if (VMThreadManager.start(this, stackSize, daemon, priority) != 0) {
754 throw new OutOfMemoryError("Failed to create new thread");
755 }
756
757
758 // wjw -- why are we *waiting* for a child thread to actually start running?
759 // this *guarantees* two context switches
760 // nothing in j.l.Thread spec says we have to do this
761 // my guess is that this actually masks an underlying race condition that we need to fix.
762
763 boolean interrupted = false;
764 while(!this.started) {
765 try {
766 lock.wait();
767 } catch (InterruptedException e) {
768 interrupted = true;
769 }
770 }
771
772 if (interrupted) {
773 Thread.currentThread().interrupt();
774 }
775 }
776 }
777
778 /**
779 * Performs premortal actions. First it processes uncaught exception if any.
780 * Second removes current thread from its thread group.
781 * VM calls this method when current thread is detaching from VM.
782 *
783 * @param uncaughtException uncaught exception or null
784 */
785 void detach(Throwable uncaughtException) {
786 try {
787 if (uncaughtException != null) {
788 getUncaughtExceptionHandler().uncaughtException(this, uncaughtException);
789 }
790 } finally {
791 group.remove(this);
792 synchronized(this) {
793 isAlive = false;
794 notifyAll();
795 }
796 }
797 }
798
799 public enum State {
800 NEW,
801 RUNNABLE,
802 BLOCKED,
803 WAITING,
804 TIMED_WAITING,
805 TERMINATED
806 }
807
808 /**
809 * @com.intel.drl.spec_ref
810 */
811 public Thread.State getState() {
812
813 boolean dead = false;
814 synchronized(lock) {
815 if(started && !isAlive() ) dead = true;
816 }
817 if (dead) return State.TERMINATED;
818
819 int state = (VMThreadManager.getState(this));
820
821 if (0 != (state & VMThreadManager.TM_THREAD_STATE_TERMINATED)) {
822 return State.TERMINATED;
823 } else if (0 != (state & VMThreadManager.TM_THREAD_STATE_WAITING_WITH_TIMEOUT)) {
824 return State.TIMED_WAITING;
825 } else if (0 != (state & VMThreadManager.TM_THREAD_STATE_WAITING)
826 || 0 != (state & VMThreadManager.TM_THREAD_STATE_PARKED)) {
827 return State.WAITING;
828 } else if (0 != (state & VMThreadManager.TM_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER)) {
829 return State.BLOCKED;
830
831 } else if (0 != (state & VMThreadManager.TM_THREAD_STATE_RUNNABLE)) {
832 return State.RUNNABLE;
833
834 //TODO track down all situations where a thread is really in RUNNABLE state
835 // but TM_THREAD_STATE_RUNNABLE is not set. In the meantime, leave the following
836 // TM_THREAD_STATE_ALIVE test as it is.
837 } else if (0 != (state & VMThreadManager.TM_THREAD_STATE_ALIVE)) {
838 return State.RUNNABLE;
839 } else {
840 return State.NEW; // by deduction, if its none of the above
841 }
842 }
843
844 /**
845 * @com.intel.drl.spec_ref
846 * @deprecated
847 */
848 public final void stop() {
849 synchronized (lock) {
850 if (isAlive()) {
851 stop(new ThreadDeath());
852 }
853 }
854 }
855
856 /**
857 * @com.intel.drl.spec_ref
858 * @deprecated
859 */
860 public final void stop(Throwable throwable) {
861 SecurityManager securityManager = System.getSecurityManager();
862 if (securityManager != null) {
863 securityManager.checkAccess(this);
864 if (currentThread() != this || !(throwable instanceof ThreadDeath)) {
865 securityManager.checkPermission(
866 RuntimePermissionCollection.STOP_THREAD_PERMISSION);
867 }
868 }
869 if (throwable == null) {
870 throw new NullPointerException("The argument is null!");
871 }
872 synchronized (lock) {
873 if (isAlive()) {
874 int status = VMThreadManager.stop(this, throwable);
875 if (status != VMThreadManager.TM_ERROR_NONE) {
876 throw new InternalError(
877 "Thread Manager internal error " + status);
878 }
879 }
880 }
881 }
882
883 /**
884 * Note that this is unsnchronized - the assumption is that
885 * hythread does the synchronization for us
886 *
887 * @com.intel.drl.spec_ref
888 * @deprecated
889 */
890 public final void suspend() {
891 checkAccess();
892
893 int status = VMThreadManager.suspend(this);
894 if (status != VMThreadManager.TM_ERROR_NONE) {
895 throw new InternalError("Thread Manager internal error " + status);
896 }
897 }
898
899 /**
900 * @com.intel.drl.spec_ref
901 */
902 public String toString() {
903 ThreadGroup threadGroup = group;
904 return "Thread[" + name + "," + priority + ","
905 + ( (threadGroup == null) ? "" : threadGroup.name) + "]";
906 }
907
908 /**
909 * @com.intel.drl.spec_ref
910 */
911 public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
912 return defaultExceptionHandler;
913 }
914
915 /**
916 * @com.intel.drl.spec_ref
917 */
918 public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
919 SecurityManager sm = System.getSecurityManager();
920 if (sm != null) {
921 sm.checkPermission(RuntimePermissionCollection.SET_DEFAULT_UNCAUGHT_EXCEPTION_HANDLER_PERMISSION);
922 }
923 defaultExceptionHandler = eh;
924 }
925
926 /**
927 * @com.intel.drl.spec_ref
928 */
929 public UncaughtExceptionHandler getUncaughtExceptionHandler() {
930 if (exceptionHandler != null) {
931 return exceptionHandler;
932 }
933 return getThreadGroup();
934 }
935
936 /**
937 * @com.intel.drl.spec_ref
938 */
939 public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
940 SecurityManager sm = System.getSecurityManager();
941 if (sm != null) {
942 sm.checkPermission(RuntimePermissionCollection.MODIFY_THREAD_PERMISSION);
943 }
944 exceptionHandler = eh;
945 }
946
947 /**
948 * generates a unique thread ID
949 */
950 private static synchronized long getNextThreadId()
951 {
952 return ++threadOrdinalNum;
953 }
954
955 /*
956 * Checks if more then GC_WATERMARK_MAX_COUNT threads was created and calls
957 * System.gc() to ensure that dead thread references was collected.
958 */
959 private void checkGCWatermark()
960 {
961 if (++currentGCWatermarkCount % GC_WATERMARK_MAX_COUNT == 0)
962 {
963 System.gc();
964 }
965 }
966
967 /**
968 * @com.intel.drl.spec_ref
969 */
970 public static interface UncaughtExceptionHandler
971 {
972
973 /**
974 * @com.intel.drl.spec_ref
975 */
976 void uncaughtException(Thread t, Throwable e);
977 }
978 }