001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.scheduler; 014 015 import java.security.AccessController; 016 import java.security.PrivilegedAction; 017 018 import org.jikesrvm.ArchitectureSpecific.CodeArray; 019 import org.jikesrvm.ArchitectureSpecific.Registers; 020 import org.jikesrvm.ArchitectureSpecificOpt.PostThreadSwitch; 021 import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACK_SIZE_NORMAL; 022 import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.INVISIBLE_METHOD_ID; 023 import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP; 024 import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACK_SIZE_GUARD; 025 import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET; 026 import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_RETURN_ADDRESS_OFFSET; 027 import org.jikesrvm.ArchitectureSpecific.BaselineConstants; 028 import org.jikesrvm.ArchitectureSpecific.ThreadLocalState; 029 import org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants; 030 import org.jikesrvm.ArchitectureSpecific; 031 import org.jikesrvm.Constants; 032 import org.jikesrvm.VM; 033 import org.jikesrvm.Configuration; 034 import org.jikesrvm.Services; 035 import org.jikesrvm.UnimplementedError; 036 import org.jikesrvm.adaptive.OnStackReplacementEvent; 037 import org.jikesrvm.adaptive.measurements.RuntimeMeasurements; 038 import org.jikesrvm.compilers.common.CompiledMethod; 039 import org.jikesrvm.compilers.common.CompiledMethods; 040 import org.jikesrvm.osr.ObjectHolder; 041 import org.jikesrvm.adaptive.OSRListener; 042 import org.jikesrvm.jni.JNIEnvironment; 043 import org.jikesrvm.mm.mminterface.CollectorThread; 044 import org.jikesrvm.mm.mminterface.MemoryManager; 045 import org.jikesrvm.mm.mminterface.ThreadContext; 046 import org.jikesrvm.objectmodel.ObjectModel; 047 import org.jikesrvm.objectmodel.ThinLockConstants; 048 import org.jikesrvm.runtime.Entrypoints; 049 import org.jikesrvm.runtime.Magic; 050 import org.jikesrvm.runtime.Memory; 051 import org.jikesrvm.runtime.RuntimeEntrypoints; 052 import org.jikesrvm.runtime.Time; 053 import org.jikesrvm.runtime.BootRecord; 054 import org.vmmagic.pragma.Inline; 055 import org.vmmagic.pragma.BaselineNoRegisters; 056 import org.vmmagic.pragma.BaselineSaveLSRegisters; 057 import org.vmmagic.pragma.Entrypoint; 058 import org.vmmagic.pragma.Interruptible; 059 import org.vmmagic.pragma.NoInline; 060 import org.vmmagic.pragma.NoOptCompile; 061 import org.vmmagic.pragma.NonMoving; 062 import org.vmmagic.pragma.Uninterruptible; 063 import org.vmmagic.pragma.UninterruptibleNoWarn; 064 import org.vmmagic.pragma.Unpreemptible; 065 import org.vmmagic.pragma.UnpreemptibleNoWarn; 066 import org.vmmagic.pragma.Untraced; 067 import org.vmmagic.pragma.NoCheckStore; 068 import org.vmmagic.unboxed.Address; 069 import org.vmmagic.unboxed.Word; 070 import org.vmmagic.unboxed.Offset; 071 072 import static org.jikesrvm.runtime.SysCall.sysCall; 073 import org.jikesrvm.classloader.RVMMethod; 074 import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod; 075 import org.jikesrvm.compilers.opt.runtimesupport.OptMachineCodeMap; 076 import org.jikesrvm.compilers.opt.runtimesupport.OptEncodedCallSiteTree; 077 import org.jikesrvm.classloader.MemberReference; 078 import org.jikesrvm.classloader.NormalMethod; 079 import org.jikesrvm.tuningfork.TraceEngine; 080 import org.jikesrvm.tuningfork.Feedlet; 081 082 /** 083 * A generic java thread's execution context. 084 * <p> 085 * Threads use a state machine to indicate to other threads, as well as VM 086 * services, how this thread should be treated in the case of an asynchronous 087 * request, for example in the case of GC. The state machine uses the 088 * following states: 089 * <ul> 090 * <li>NEW</li> 091 * <li>IN_JAVA</li> 092 * <li>IN_NATIVE</li> 093 * <li>IN_JNI</li> 094 * <li>IN_JAVA_TO_BLOCK</li> 095 * <li>BLOCKED_IN_NATIVE</li> 096 * <li>BLOCKED_IN_JNI</li> 097 * <li>TERMINATED</li> 098 * </ul> 099 * The following state transitions are legal: 100 * <ul> 101 * <li>NEW to IN_JAVA: occurs when the thread is actually started. At this 102 * point it is safe to expect that the thread will reach a safe point in 103 * some bounded amount of time, at which point it will have a complete 104 * execution context, and this will be able to have its stack traces by GC.</li> 105 * <li>IN_JAVA to IN_JAVA_TO_BLOCK: occurs when an asynchronous request is 106 * made, for example to stop for GC, do a mutator flush, or do an isync on PPC.</li> 107 * <li>IN_JAVA to IN_NATIVE: occurs when the code opts to run in privileged mode, 108 * without synchronizing with GC. This state transition is only performed by 109 * HeavyCondLock, in cases where the thread is about to go idle while waiting 110 * for notifications (such as in the case of park, wait, or sleep).</li> 111 * <li>IN_JAVA to IN_JNI: occurs in response to a JNI downcall, or return from a JNI 112 * upcall.</li> 113 * <li>IN_JAVA_TO_BLOCK to BLOCKED_IN_NATIVE: occurs when a thread that had been 114 * asked to perform an async activity decides to go idle instead. This state 115 * always corresponds to a notification being sent to other threads, letting 116 * them know that this thread is idle. When the thread is idle, any asynchronous 117 * requests (such as mutator flushes) can instead be performed on behalf of this 118 * thread by other threads, since this thread is guaranteed not to be running 119 * any user Java code, and will not be able to return to running Java code without 120 * first blocking, and waiting to be unblocked (see BLOCKED_IN_NATIVE to IN_JAVA 121 * transition.</li> 122 * <li>IN_JAVA_TO_BLOCK to BLOCKED_IN_JNI: occurs when a thread that had been 123 * asked to perform an async activity decides to make a JNI downcall, or return 124 * from a JNI upcall, instead. In all other regards, this is identical to the 125 * IN_JAVA_TO_BLOCK to BLOCKED_IN_NATIVE transition.</li> 126 * <li>IN_NATIVE to IN_JAVA: occurs when a thread returns from idling or running 127 * privileged code to running Java code.</li> 128 * <li>BLOCKED_IN_NATIVE to IN_JAVA: occurs when a thread that had been asked to 129 * perform an async activity while running privileged code or idling decides to 130 * go back to running Java code. The actual transition is preceded by the 131 * thread first performing any requested actions (such as mutator flushes) and 132 * waiting for a notification that it is safe to continue running (for example, 133 * the thread may wait until GC is finished).</li> 134 * <li>IN_JNI to IN_JAVA: occurs when a thread returns from a JNI downcall, or makes 135 * a JNI upcall.</li> 136 * <li>BLOCKED_IN_JNI to IN_JAVA: same as BLOCKED_IN_NATIVE to IN_JAVA, except that 137 * this occurs in response to a return from a JNI downcall, or as the thread 138 * makes a JNI upcall.</li> 139 * <li>IN_JAVA to TERMINATED: the thread has terminated, and will never reach any 140 * more safe points, and thus will not be able to respond to any more requests 141 * for async activities.</li> 142 * </ul> 143 * Observe that the transitions from BLOCKED_IN_NATIVE and BLOCKED_IN_JNI to IN_JAVA 144 * constitute a safe point. Code running in BLOCKED_IN_NATIVE or BLOCKED_IN_JNI is 145 * "GC safe" but is not quite at a safe point; safe points are special in that 146 * they allow the thread to perform async activities (such as mutator flushes or 147 * isyncs), while GC safe code will not necessarily perform either. 148 * 149 * @see org.jikesrvm.mm.mminterface.CollectorThread 150 * @see FinalizerThread 151 * @see org.jikesrvm.adaptive.measurements.organizers.Organizer 152 */ 153 @Uninterruptible 154 @NonMoving 155 public final class RVMThread extends ThreadContext implements Constants { 156 /* 157 * debug and statistics 158 */ 159 /** Trace thread blockage */ 160 protected static final boolean traceBlock = false; 161 162 /** Trace when a thread is really blocked */ 163 protected static final boolean traceReallyBlock = false || traceBlock; 164 165 protected static final boolean traceAboutToTerminate = false; 166 167 protected static final boolean dumpStackOnBlock = false; // DANGEROUS! can lead to crashes! 168 169 protected static final boolean traceBind = false; 170 171 /** Trace thread start/stop */ 172 protected static final boolean traceAcct = false; 173 174 /** Trace execution */ 175 protected static final boolean trace = false; 176 177 /** Trace thread termination */ 178 private static final boolean traceTermination = false; 179 180 /** Trace adjustments to stack size */ 181 private static final boolean traceAdjustments = false; 182 183 /** Never kill threads. Useful for testing bugs related to interaction of 184 thread death with for example MMTk. For production, this should never 185 be set to true. */ 186 private static final boolean neverKillThreads = false; 187 188 /** Generate statistics? */ 189 private static final boolean STATS = Lock.STATS; 190 191 /** Number of wait operations */ 192 static int waitOperations; 193 194 /** Number of timed wait operations */ 195 static int timedWaitOperations; 196 197 /** Number of notify operations */ 198 static int notifyOperations; 199 200 /** Number of notifyAll operations */ 201 static int notifyAllOperations; 202 203 public static final boolean ALWAYS_LOCK_ON_STATE_TRANSITION = false; 204 205 /* 206 * definitions for thread status for interaction of Java-native transitions 207 * and requests for threads to stop. THESE ARE PRIVATE TO THE SCHEDULER, and 208 * are only used deep within the stack. 209 */ 210 /** 211 * Thread has not yet started. This state holds right up until just before we 212 * call pthread_create(). 213 */ 214 public static final int NEW = 0; 215 216 /** Thread is executing "normal" Java bytecode */ 217 public static final int IN_JAVA = 1; 218 219 /** 220 * A state used by the scheduler to mark that a thread is in privileged code 221 * that does not need to synchronize with the collector. This is a special 222 * state, similar to the IN_JNI state but requiring different interaction with 223 * the collector (as there is no JNI stack frame, the registers have to be 224 * saved in contextRegisters). As well, this state should only be entered 225 * from privileged code in the org.jikesrvm.scheduler package. Typically, 226 * this state is entered using a call to enterNative() just prior to idling 227 * the thread; though it would not be wrong to enter it prior to any other 228 * long-running activity that does not require interaction with the GC. 229 */ 230 public static final int IN_NATIVE = 2; 231 232 /** 233 * Same as IN_NATIVE, except that we're executing JNI code and thus have a 234 * JNI stack frame and JNI environment, and thus the GC can load registers 235 * from there rather than using contextRegisters. 236 */ 237 public static final int IN_JNI = 3; 238 239 /** 240 * thread is in Java code but is expected to block. the transition from IN_JAVA 241 * to IN_jAVA_TO_BLOCK happens as a result of an asynchronous call by the GC 242 * or any other internal VM code that requires this thread to perform an 243 * asynchronous activity (another example is the request to do an isync on PPC). 244 * the point is that we're waiting for the thread to reach a safe point and 245 * expect this to happen in bounded time; but if the thread were to escape to 246 * native we want to know about it. thus, transitions into native code while 247 * in the IN_JAVA_TO_BLOCK state result in a notification (broadcast on the 248 * thread's monitor) and a state change to BLOCKED_IN_NATIVE. Observe that it 249 * is always safe to conservatively change IN_JAVA to IN_JAVA_TO_BLOCK. 250 */ 251 public static final int IN_JAVA_TO_BLOCK = 4; 252 253 /** 254 * thread is in native code, and is to block before returning to Java code. 255 * the transition from IN_NATIVE to BLOCKED_IN_NATIVE happens as a result 256 * of an asynchronous call by the GC or any other internal VM code that 257 * requires this thread to perform an asynchronous activity (another example 258 * is the request to do an isync on PPC). as well, code entering privileged 259 * code that would otherwise go from IN_JAVA to IN_NATIVE will go to 260 * BLOCKED_IN_NATIVE instead, if the state was IN_JAVA_TO_BLOCK. 261 * <p> 262 * the point of this state is that the thread is guaranteed not to execute 263 * any Java code until: 264 * <ol> 265 * <li>The state changes to IN_NATIVE, and 266 * <li>The thread gets a broadcast on its monitor. 267 * </ol> 268 * Observe that it is always safe to conservatively change IN_NATIVE to 269 * BLOCKED_IN_NATIVE. 270 */ 271 public static final int BLOCKED_IN_NATIVE = 5; 272 273 /** 274 * like BLOCKED_IN_NATIVE, but indicates that the thread is in JNI rather than 275 * VM native code. 276 */ 277 public static final int BLOCKED_IN_JNI = 6; 278 279 /** 280 * Thread has died. As in, it's no longer executing any Java code and will 281 * never do so in the future. Once this is set, the GC will no longer mark any 282 * part of the thread as live; the thread's stack will be deleted. Note that 283 * this is distinct from the aboutToTerminate state. 284 */ 285 public static final int TERMINATED = 7; 286 287 /** Not actually a state but just a marker. */ 288 public static final int LAST_EXEC_STATUS = 8; 289 290 public static boolean notRunning(int state) { 291 return state == NEW || state == TERMINATED; 292 } 293 294 /** Registers used by return barrier trampoline */ 295 private Registers trampolineRegisters = new Registers(); 296 297 /** Return address of stack frame hijacked by return barrier */ 298 private Address hijackedReturnAddress; 299 300 /** Callee frame pointer for stack frame hijacked by return barrier */ 301 private Address hijackedReturnCalleeFp = Address.zero(); 302 303 /** Caller frame pointer for stack frame hijacked by return barrier */ 304 private Address hijackedReturnCallerFp = ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP; 305 306 /** @return the callee frame pointer for the stack frame hijacked by the return barrier */ 307 public Address getHijackedReturnCalleeFp() { return hijackedReturnCalleeFp; } 308 309 /** debugging flag for return barrier trampoline */ 310 public static final boolean DEBUG_STACK_TRAMPOLINE = false; 311 312 /** pointer to bridge code for return barrier trampoline */ 313 public static ArchitectureSpecific.CodeArray stackTrampolineBridgeInstructions; 314 315 /** 316 * Thread state. Indicates if the thread is running, and if so, what mode of 317 * execution it is using (Java, VM native, or JNI) 318 */ 319 @Entrypoint 320 private int execStatus; 321 322 public int getExecStatus() { 323 observeExecStatus(); 324 return execStatus; 325 } 326 327 private boolean attemptFastExecStatusTransition(int oldState, 328 int newState) { 329 if (Synchronization.tryCompareAndSwap( 330 this, 331 Entrypoints.execStatusField.getOffset(), 332 oldState, 333 newState)) { 334 observeStateTransition(oldState,newState); 335 return true; 336 } else { 337 return false; 338 } 339 } 340 341 // call this only when holding the lock or if you really know what you're 342 // doing. 343 private void setExecStatus(int newState) { 344 observeStateTransition(execStatus,newState); 345 execStatus=newState; 346 } 347 348 /** 349 * Is the thread about to terminate? Protected by the thread's monitor. Note 350 * that this field is not set atomically with the entering of the thread onto 351 * the aboutToTerminate array - in fact it happens before that. When this 352 * field is set to true, the thread's stack will no longer be scanned by GC. 353 * Note that this is distinct from the TERMINATED state. 354 */ 355 // FIXME: there should be an execStatus state called TERMINATING that 356 // corresponds to this. that would make a lot more sense. 357 private boolean isAboutToTerminate; 358 359 public boolean getIsAboutToTerminate() { return isAboutToTerminate; } 360 361 /** Is this thread in the process of blocking? */ 362 boolean isBlocking; 363 364 /** 365 * Is the thread no longer executing user code? Protected by the Java monitor 366 * associated with the Thread object. 367 */ 368 boolean isJoinable; 369 370 /** 371 * Link pointer for queues (specifically ThreadQueue). A thread can only be 372 * on one such queue at a time. The queue that a thread is on is indicated by 373 * <code>queuedOn</code>. 374 */ 375 @Untraced 376 RVMThread next; 377 378 /** 379 * The queue that the thread is on, or null if the thread is not on a queue 380 * (specifically ThreadQueue). If the thread is on such a queue, the 381 * <code>next</code> field is used as a link pointer. 382 */ 383 @Untraced 384 volatile ThreadQueue queuedOn; 385 386 /** 387 * @return True if this thread is currently on a queue. 388 */ 389 public boolean isOnQueue() { 390 return queuedOn != null; 391 } 392 393 /** 394 * Used to handle contention for spin locks 395 */ 396 @Untraced 397 SpinLock awaitingSpinLock; 398 399 @Untraced 400 RVMThread contenderLink; 401 402 /** 403 * java.lang.Thread wrapper for this Thread. Not final so it may be assigned 404 * during booting 405 */ 406 private Thread thread; 407 408 /** Name of the thread (can be changed during execution) */ 409 private String name; 410 411 /** 412 * The virtual machine terminates when the last non-daemon (user) thread 413 * terminates. 414 */ 415 protected boolean daemon; 416 417 /** 418 * Scheduling priority for this thread. Note that: 419 * {@link java.lang.Thread#MIN_PRIORITY} <= priority <= 420 * {@link java.lang.Thread#MAX_PRIORITY}. 421 */ 422 private int priority; 423 424 /** 425 * Index of this thread in {@link #threadBySlot}[]. This value must be non-zero 426 * because it is shifted and used in {@link Object} lock ownership tests. 427 */ 428 @Entrypoint 429 public int threadSlot; 430 431 public int lockingId; 432 433 /** 434 * Non-null indicates this is a system thread, that is one used by the system and as such 435 * doesn't have a Runnable... 436 */ 437 private final SystemThread systemThread; 438 439 /** 440 * The boot thread, can't be final so as to allow initialization during boot 441 * image writing. 442 */ 443 @Entrypoint 444 public static RVMThread bootThread; 445 446 /** 447 * Is the threading system initialized? 448 */ 449 public static boolean threadingInitialized = false; 450 451 /** 452 * Number of timer ticks we've seen 453 */ 454 public static long timerTicks; 455 456 private long yieldpointsTaken; 457 458 private long yieldpointsTakenFully; 459 460 private long nativeEnteredBlocked; 461 462 private long jniEnteredBlocked; 463 464 /** 465 * Assertion checking while manipulating raw addresses -- see 466 * {@link VM#disableGC()}/{@link VM#enableGC()}. A value of "true" means 467 * it's an error for this thread to call "new". This is only used for 468 * assertion checking; we do not bother to set it when 469 * {@link VM#VerifyAssertions} is false. 470 */ 471 private boolean disallowAllocationsByThisThread; 472 473 /** 474 * Counts the depth of outstanding calls to {@link VM#disableGC()}. If this 475 * is set, then we should also have {@link #disallowAllocationsByThisThread} 476 * set. The converse also holds. 477 */ 478 private int disableGCDepth = 0; 479 480 public int barriersEntered = 0; 481 482 public int barriersExited = 0; 483 484 /** 485 * Execution stack for this thread. 486 */ 487 @Entrypoint 488 private byte[] stack; 489 490 /** The {@link Address} of the guard area for {@link #stack}. */ 491 @Entrypoint 492 public Address stackLimit; 493 494 /* --------- BEGIN IA-specific fields. NOTE: NEED TO REFACTOR --------- */ 495 // On powerpc, these values are in dedicated registers, 496 // we don't have registers to burn on IA32, so we indirect 497 // through the TR register to get them instead. 498 /** 499 * FP for current frame, saved in the prologue of every method 500 */ 501 Address framePointer; 502 503 /** 504 * "hidden parameter" for interface invocation thru the IMT 505 */ 506 int hiddenSignatureId; 507 508 /** 509 * "hidden parameter" from ArrayIndexOutOfBounds trap to C trap handler 510 */ 511 int arrayIndexTrapParam; 512 513 /* --------- END IA-specific fields. NOTE: NEED TO REFACTOR --------- */ 514 515 /** 516 * Is the next taken yieldpoint in response to a request to perform OSR? 517 */ 518 public boolean yieldToOSRRequested; 519 520 /** 521 * Is CBS enabled for 'call' yieldpoints? 522 */ 523 public boolean yieldForCBSCall; 524 525 /** 526 * Is CBS enabled for 'method' yieldpoints? 527 */ 528 public boolean yieldForCBSMethod; 529 530 /** 531 * Number of CBS samples to take in this window 532 */ 533 public int numCBSCallSamples; 534 535 /** 536 * Number of call yieldpoints between CBS samples 537 */ 538 public int countdownCBSCall; 539 540 /** 541 * round robin starting point for CBS samples 542 */ 543 public int firstCBSCallSample; 544 545 /** 546 * Number of CBS samples to take in this window 547 */ 548 public int numCBSMethodSamples; 549 550 /** 551 * Number of counter ticks between CBS samples 552 */ 553 public int countdownCBSMethod; 554 555 /** 556 * round robin starting point for CBS samples 557 */ 558 public int firstCBSMethodSample; 559 560 /* --------- BEGIN PPC-specific fields. NOTE: NEED TO REFACTOR --------- */ 561 /** 562 * flag indicating this processor needs to execute a memory synchronization 563 * sequence Used for code patching on SMP PowerPCs. 564 */ 565 public boolean codePatchSyncRequested; 566 567 /* --------- END PPC-specific fields. NOTE: NEED TO REFACTOR --------- */ 568 569 /** 570 * For builds using counter-based sampling. This field holds a 571 * processor-specific counter so that it can be updated efficiently on SMP's. 572 */ 573 public int thread_cbs_counter; 574 575 /** 576 * Should this thread yield at yieldpoints? A value of: 1 means "yes" 577 * (yieldpoints enabled) <= 0 means "no" (yieldpoints disabled) 578 */ 579 private int yieldpointsEnabledCount; 580 581 /** 582 * Is a takeYieldpoint request pending on this thread? 583 */ 584 boolean yieldpointRequestPending; 585 586 /** 587 * Are we at a yieldpoint right now? 588 */ 589 boolean atYieldpoint; 590 591 /** 592 * Is there a flush request for this thread? This is handled via a soft 593 * handshake. 594 */ 595 public boolean flushRequested; 596 597 /** 598 * Is a soft handshake requested? Logically, this field is protected by the 599 * thread's monitor - but it is typically only mucked with when both the 600 * thread's monitor and the softHandshakeDataLock are held. 601 */ 602 public boolean softHandshakeRequested; 603 604 /** 605 * How many threads have not yet reached the soft handshake? (protected by 606 * softHandshakeDataLock) 607 */ 608 public static int softHandshakeLeft; 609 610 /** 611 * Lock that protects soft handshake fields. 612 */ 613 public static Monitor softHandshakeDataLock; 614 615 /** 616 * Lock that prevents multiple (soft or hard) handshakes from proceeding 617 * concurrently. 618 */ 619 public static Monitor handshakeLock; 620 621 /** 622 * Place to save register state when this thread is not actually running. 623 */ 624 @Entrypoint 625 @Untraced 626 public final Registers contextRegisters; 627 @SuppressWarnings("unused") 628 private final Registers contextRegistersShadow; 629 630 /** 631 * Place to save register state when this thread is not actually running. 632 */ 633 @Entrypoint 634 @Untraced 635 public final Registers contextRegistersSave; 636 @SuppressWarnings("unused") 637 private final Registers contextRegistersSaveShadow; 638 639 /** 640 * Place to save register state during hardware(C signal trap handler) or 641 * software (RuntimeEntrypoints.athrow) trap handling. 642 */ 643 @Entrypoint 644 @Untraced 645 private final Registers exceptionRegisters; 646 @SuppressWarnings("unused") 647 private final Registers exceptionRegistersShadow; 648 649 /** Count of recursive uncaught exceptions, we need to bail out at some point */ 650 private int uncaughtExceptionCount = 0; 651 652 /** 653 * A cached free lock. Not a free list; this will only ever contain 0 or 1 654 * locks! 655 */ 656 public Lock cachedFreeLock; 657 658 /* 659 * Wait/notify fields 660 */ 661 662 /** 663 * Place to save/restore this thread's monitor state during 664 * {@link Object#wait} and {@link Object#notify}. 665 */ 666 protected Object waitObject; 667 668 /** Lock recursion count for this thread's monitor. */ 669 protected int waitCount; 670 671 /** 672 * Should the thread suspend? 673 */ 674 boolean shouldSuspend; 675 676 /** 677 * An integer token identifying the last suspend request 678 */ 679 int shouldSuspendToken; 680 681 /** 682 * Is the thread suspended? 683 */ 684 boolean isSuspended; 685 686 /** 687 * Should the thread block for handshake? 688 */ 689 boolean shouldBlockForHandshake; 690 691 /** 692 * Is the thread blocked for handshake? 693 */ 694 boolean isBlockedForHandshake; 695 696 /** 697 * Should the thread block for a thread-to-thread communication? 698 */ 699 boolean shouldBlockForGC; 700 701 /** 702 * Is the thread blocked for thread-to-thread communication? 703 */ 704 boolean isBlockedForGC; 705 706 /** 707 * A block adapter specifies the reason for blocking or unblocking a thread. A thread 708 * remains blocked so long as any of the block adapters say that it should be blocked. 709 * Block adapters are statically allocated, and store their state in instance fields of 710 * RVMThread. 711 */ 712 @Uninterruptible 713 @NonMoving 714 public abstract static class BlockAdapter { 715 /** Should the given thread be blocked for this block adapter? If this returns true, 716 the thread is guaranteed to block. */ 717 abstract boolean isBlocked(RVMThread t); 718 719 /** Specify that the thread is either blocked (value == true) or not blocked 720 (value == false) for this block adapter. This call indicates a statement of 721 fact by the thread itself - it's used either to acknowledge a block request 722 (see hasBlockRequest below) or to respond to a request to unblock. */ 723 abstract void setBlocked(RVMThread t, boolean value); 724 725 /** Request that the thread block, for this block adapter, at its earliest 726 convenience. Called from RVMThread.block() and associated methods. Some 727 block adapters allow for multiple requests to block; in that case this will 728 return a "token" that can be passed to hasBlockRequest() to check, not only 729 whether there is a block request, but whether that block request is still 730 associated with a particular call to requestBlock(). This is used to prevent 731 a suspend() call from stalling due to a concurrent resume() and second 732 suspend(). Note that most block adapers don't care about this scenario, and 733 will just return 0 (or some other meaningless number) here. */ 734 abstract int requestBlock(RVMThread t); 735 736 /** Does the thread have a request to block for this block adapter? */ 737 abstract boolean hasBlockRequest(RVMThread t); 738 739 /** Does the thread have a request to block associated with the given requestBlock() 740 call? */ 741 abstract boolean hasBlockRequest(RVMThread t, int token); 742 743 /** Clear any blocking requests. */ 744 abstract void clearBlockRequest(RVMThread t); 745 } 746 747 @Uninterruptible 748 @NonMoving 749 public static class SuspendBlockAdapter extends BlockAdapter { 750 @Override 751 boolean isBlocked(RVMThread t) { 752 return t.isSuspended; 753 } 754 755 @Override 756 void setBlocked(RVMThread t, boolean value) { 757 t.isSuspended = value; 758 } 759 760 @Override 761 int requestBlock(RVMThread t) { 762 if (t.isSuspended || t.shouldSuspend) { 763 return t.shouldSuspendToken; 764 } else { 765 t.shouldSuspend = true; 766 t.shouldSuspendToken++; 767 return t.shouldSuspendToken; 768 } 769 } 770 771 @Override 772 boolean hasBlockRequest(RVMThread t) { 773 return t.shouldSuspend; 774 } 775 776 @Override 777 boolean hasBlockRequest(RVMThread t, int token) { 778 return t.shouldSuspend && t.shouldSuspendToken == token; 779 } 780 781 @Override 782 void clearBlockRequest(RVMThread t) { 783 t.shouldSuspend = false; 784 } 785 } 786 787 public static final SuspendBlockAdapter suspendBlockAdapter = new SuspendBlockAdapter(); 788 789 @Uninterruptible 790 @NonMoving 791 public static class HandshakeBlockAdapter extends BlockAdapter { 792 @Override 793 boolean isBlocked(RVMThread t) { 794 return t.isBlockedForHandshake; 795 } 796 797 @Override 798 void setBlocked(RVMThread t, boolean value) { 799 t.isBlockedForHandshake = value; 800 } 801 802 @Override 803 int requestBlock(RVMThread t) { 804 if (!t.isBlockedForHandshake) { 805 t.shouldBlockForHandshake = true; 806 } 807 return 0; 808 } 809 810 @Override 811 boolean hasBlockRequest(RVMThread t) { 812 return t.shouldBlockForHandshake; 813 } 814 815 @Override 816 boolean hasBlockRequest(RVMThread t, int token) { 817 return t.shouldBlockForHandshake; 818 } 819 820 @Override 821 void clearBlockRequest(RVMThread t) { 822 t.shouldBlockForHandshake = false; 823 } 824 } 825 826 public static final HandshakeBlockAdapter handshakeBlockAdapter = new HandshakeBlockAdapter(); 827 828 @Uninterruptible 829 @NonMoving 830 public static class GCBlockAdapter extends BlockAdapter { 831 @Override 832 boolean isBlocked(RVMThread t) { 833 return t.isBlockedForGC; 834 } 835 836 @Override 837 void setBlocked(RVMThread t, boolean value) { 838 t.isBlockedForGC = value; 839 } 840 841 @Override 842 int requestBlock(RVMThread t) { 843 if (!t.isBlockedForGC) { 844 t.shouldBlockForGC = true; 845 } 846 return 0; 847 } 848 849 @Override 850 boolean hasBlockRequest(RVMThread t) { 851 return t.shouldBlockForGC; 852 } 853 854 @Override 855 boolean hasBlockRequest(RVMThread t, int token) { 856 return t.shouldBlockForGC; 857 } 858 859 @Override 860 void clearBlockRequest(RVMThread t) { 861 t.shouldBlockForGC = false; 862 } 863 } 864 865 public static final GCBlockAdapter gcBlockAdapter = new GCBlockAdapter(); 866 867 static final BlockAdapter[] blockAdapters = new BlockAdapter[] { 868 suspendBlockAdapter, handshakeBlockAdapter, gcBlockAdapter }; 869 870 /** 871 * An enumeration that describes the different manners in which a thread might 872 * be voluntarily waiting. 873 */ 874 protected static enum Waiting { 875 /** The thread is not waiting at all. In fact it's running. */ 876 RUNNABLE, 877 /** The thread is waiting without a timeout. */ 878 WAITING, 879 /** The thread is waiting with a timeout. */ 880 TIMED_WAITING 881 } 882 883 /** 884 * Accounting of whether or not a thread is waiting (in the Java thread state 885 * sense), and if so, how it's waiting. 886 * <p> 887 * Invariant: the RVM runtime does not ever use this field for any purpose 888 * other than updating it so that the java.lang.Thread knows the state. Thus, 889 * if you get sloppy with this field, the worst case outcome is that some Java 890 * program that queries the thread state will get something other than what it 891 * may or may not have expected. 892 */ 893 protected Waiting waiting; 894 895 /** 896 * Exception to throw in this thread at the earliest possible point. 897 */ 898 Throwable asyncThrowable; 899 900 /** 901 * Has the thread been interrupted? 902 */ 903 boolean hasInterrupt; 904 905 /** 906 * Should the next executed yieldpoint be taken? Can be true for a variety of 907 * reasons. See RVMThread.yieldpoint 908 * <p> 909 * To support efficient sampling of only prologue/epilogues we also encode 910 * some extra information into this field. 0 means that the yieldpoint should 911 * not be taken. >0 means that the next yieldpoint of any type should be taken 912 * <0 means that the next prologue/epilogue yieldpoint should be taken 913 * <p> 914 * Note the following rules: 915 * <ol> 916 * <li>If takeYieldpoint is set to 0 or -1 it is perfectly safe to set it to 917 * 1; this will have almost no effect on the system. Thus, setting 918 * takeYieldpoint to 1 can always be done without acquiring locks.</li> 919 * <li>Setting takeYieldpoint to any value other than 1 should be done while 920 * holding the thread's monitor().</li> 921 * <li>The exception to rule (2) above is that the yieldpoint itself sets 922 * takeYieldpoint to 0 without holding a lock - but this is done after it 923 * ensures that the yieldpoint is deferred by setting yieldpointRequestPending 924 * to true. 925 * </ol> 926 */ 927 @Entrypoint 928 public int takeYieldpoint; 929 930 /** 931 * How many times has the "timeslice" expired? This is only used for profiling 932 * and OSR (in particular base-to-opt OSR). 933 */ 934 public int timeSliceExpired; 935 936 /** Is a running thread permitted to ignore the next park request */ 937 private boolean parkingPermit; 938 939 /* 940 * JNI fields 941 */ 942 943 /** 944 * Cached JNI environment for this thread 945 */ 946 @Entrypoint 947 @Untraced 948 private JNIEnvironment jniEnv; 949 @SuppressWarnings("unused") 950 private JNIEnvironment jniEnvShadow; 951 952 /** Used by GC to determine collection success */ 953 private boolean physicalAllocationFailed; 954 955 /** Used by GC to determine collection success */ 956 private int collectionAttempt; 957 958 /** The OOME to throw */ 959 private static OutOfMemoryError outOfMemoryError; 960 961 /* 962 * Enumerate different types of yield points for sampling 963 */ 964 public static final int PROLOGUE = 0; 965 966 public static final int BACKEDGE = 1; 967 968 public static final int EPILOGUE = 2; 969 970 public static final int NATIVE_PROLOGUE = 3; 971 972 public static final int NATIVE_EPILOGUE = 4; 973 974 public static final int OSROPT = 5; 975 976 /* 977 * Fields used for on stack replacement 978 */ 979 980 /** 981 * Only used by OSR when VM.BuildForAdaptiveSystem. Declared as an Object to 982 * cut link to adaptive system. Ugh. 983 */ 984 public final Object /* OnStackReplacementEvent */onStackReplacementEvent; 985 986 /** 987 * The flag indicates whether this thread is waiting for on stack replacement 988 * before being rescheduled. 989 */ 990 // flags should be packaged or replaced by other solutions 991 public boolean isWaitingForOsr = false; 992 993 /** 994 * Before call new instructions, we need a bridge to recover register states 995 * from the stack frame. 996 */ 997 public CodeArray bridgeInstructions = null; 998 999 /** Foo frame pointer offset */ 1000 public Offset fooFPOffset = Offset.zero(); 1001 1002 /** Thread switch frame pointer offset */ 1003 public Offset tsFPOffset = Offset.zero(); 1004 1005 /** 1006 * Flag to synchronize with osr organizer, the trigger sets osr requests the 1007 * organizer clear the requests 1008 */ 1009 public boolean requesting_osr = false; 1010 1011 /** 1012 * Flag to indicate that the last OSR request is done. 1013 */ 1014 public boolean osr_done = false; 1015 1016 /** 1017 * The number of processors to use. 1018 */ 1019 public static int availableProcessors = -1; 1020 1021 /** 1022 * Thread handle. Currently stores pthread_t, which we assume to be no larger 1023 * than a pointer-sized word. 1024 */ 1025 public Word pthread_id; 1026 1027 /** 1028 * Scratch area for use for gpr <=> fpr transfers by PPC baseline compiler. 1029 * Used to transfer x87 to SSE registers on IA32 1030 */ 1031 @SuppressWarnings({ "unused" }) 1032 // accessed via EntryPoints 1033 private double scratchStorage; 1034 1035 /** 1036 * Current index of this thread in the threads array. This may be changed by 1037 * another thread, but only while the acctLock is held. 1038 */ 1039 private int threadIdx; 1040 1041 /** 1042 * Is the system in the process of shutting down (has System.exit been called) 1043 */ 1044 private static boolean systemShuttingDown = false; 1045 1046 /** 1047 * Flag set by external signal to request debugger activation at next thread 1048 * switch. See also: RunBootImage.C 1049 */ 1050 public static volatile boolean debugRequested; 1051 1052 public volatile boolean asyncDebugRequestedForThisThread; 1053 1054 /** 1055 * The latch for reporting profile data. 1056 */ 1057 public static Latch doProfileReport; 1058 1059 /** Number of times dump stack has been called recursively */ 1060 protected int inDumpStack = 0; 1061 1062 /** Is this a "registered mutator?" */ 1063 public boolean activeMutatorContext = false; 1064 1065 /** Lock used for dumping stack and such. */ 1066 public static Monitor dumpLock; 1067 1068 /** In dump stack and dying */ 1069 protected static boolean exitInProgress = false; 1070 1071 private static boolean worldStopped; 1072 1073 /** Extra debug from traces */ 1074 protected static final boolean traceDetails = false; 1075 1076 /** Toggle display of frame pointer address in stack dump */ 1077 private static final boolean SHOW_FP_IN_STACK_DUMP = true; 1078 1079 /** Index of thread in which "VM.boot()" runs */ 1080 public static final int PRIMORDIAL_THREAD_INDEX = 1; 1081 1082 /** Maximum number of RVMThread's that we can support. */ 1083 public static final int LOG_MAX_THREADS = 10; 1084 1085 public static final int MAX_THREADS = 1 << LOG_MAX_THREADS; 1086 1087 /** 1088 * thread array - all threads are stored in this array according to their 1089 * threadSlot. 1090 */ 1091 public static RVMThread[] threadBySlot = new RVMThread[MAX_THREADS]; 1092 1093 /** 1094 * Per-thread monitors. Note that this array is statically initialized. It 1095 * starts out all null. When a new thread slot is allocated, a monitor is 1096 * added for that slot. 1097 * <p> 1098 * Question: what is the outcome, if any, of taking a yieldpoint while holding 1099 * this lock? 1100 * <ol> 1101 * <li>If there is a GC request we will wait on this condition variable and 1102 * thus release it. Someone else might then acquire the lock before realizing 1103 * that there is a GC request and then do bad things.</li> 1104 * <li>The yieldpoint might acquire another thread's monitor. Thus, two 1105 * threads may get into lock inversion with each other.</li> 1106 * <li>???</li> 1107 * </ol> 1108 */ 1109 private static final NoYieldpointsMonitor[] monitorBySlot = new NoYieldpointsMonitor[MAX_THREADS]; 1110 1111 private static final Monitor[] communicationLockBySlot = new Monitor[MAX_THREADS]; 1112 1113 /** 1114 * Lock (mutex) used for creating and destroying threads as well as thread 1115 * accounting. This mutex should not be held while thread monitors (see monitorBySlot) 1116 * are held. Use this mutex only to protect accesses to: 1117 * <ul> 1118 * <li>the global thread lists, such as threadBySlot, aboutToTerminate, threads, and 1119 * freeLots</li> 1120 * <li>threadIdx field of RVMThread</li> 1121 * <li>numThreads, numActiveThreads, numActiveDaemons static fields of RVMThread</li> 1122 * </ul> 1123 */ 1124 public static NoYieldpointsMonitor acctLock; 1125 1126 /** 1127 * Lock (mutex) used for servicing debug requests. 1128 */ 1129 public static NoYieldpointsMonitor debugLock; 1130 1131 /** 1132 * Lock used for generating debug output. 1133 */ 1134 private static NoYieldpointsMonitor outputLock; 1135 1136 /** 1137 * Thread slots of threads that are about to terminate. This must be 1138 * an int array because it's accessed from code that cannot have 1139 * barriers. 1140 */ 1141 private static final int[] aboutToTerminate = new int[MAX_THREADS]; 1142 1143 /** 1144 * Number of threads that are about to terminate. 1145 */ 1146 private static int aboutToTerminateN; 1147 1148 /** 1149 * Free thread slots 1150 */ 1151 private static final int[] freeSlots = new int[MAX_THREADS]; 1152 1153 /** 1154 * Number of free thread slots. 1155 */ 1156 private static int freeSlotN; 1157 1158 /** 1159 * When there are no thread slots on the free list, this is the next one to 1160 * use. 1161 */ 1162 public static int nextSlot = 2; 1163 1164 /** 1165 * Number of threads in the system (some of which may not be active). 1166 */ 1167 public static int numThreads; 1168 1169 /** 1170 * Packed and unordered array or active threads. Only entries in the range 0 1171 * to numThreads-1 (inclusive) are defined. Note that it should be possible to 1172 * scan this array without locking and get all of the threads - but only if 1173 * you scan downward and place a memory fence between loads. 1174 * <p> 1175 * Note further that threads remain in this array even after the Java 1176 * libraries no longer consider the thread to be active. 1177 */ 1178 public static final RVMThread[] threads = new RVMThread[MAX_THREADS]; 1179 1180 /** 1181 * Preallocated array for use in handshakes. Protected by handshakeLock. 1182 */ 1183 public static final RVMThread[] handshakeThreads = new RVMThread[MAX_THREADS]; 1184 1185 /** 1186 * Preallocated array for use in debug requested. Protected by debugLock. 1187 */ 1188 public static final RVMThread[] debugThreads = new RVMThread[MAX_THREADS]; 1189 1190 /** 1191 * Number of active threads in the system. 1192 */ 1193 private static int numActiveThreads; 1194 1195 /** 1196 * Number of active daemon threads. 1197 */ 1198 private static int numActiveDaemons; 1199 1200 /* 1201 * TuningFork instrumentation support 1202 */ 1203 /** 1204 * The Feedlet instance for this thread to use to make addEvent calls. 1205 */ 1206 public Feedlet feedlet; 1207 1208 /** 1209 * Get a NoYieldpointsCondLock for a given thread slot. 1210 */ 1211 static NoYieldpointsMonitor monitorForSlot(int slot) { 1212 NoYieldpointsMonitor result = monitorBySlot[slot]; 1213 if (VM.VerifyAssertions) 1214 VM._assert(result != null); 1215 return result; 1216 } 1217 1218 /** 1219 * Get the NoYieldpointsCondLock for this thread. 1220 */ 1221 public NoYieldpointsMonitor monitor() { 1222 return monitorForSlot(threadSlot); 1223 } 1224 1225 public Monitor communicationLockForSlot(int slot) { 1226 Monitor result = communicationLockBySlot[slot]; 1227 if (VM.VerifyAssertions) 1228 VM._assert(result != null); 1229 return result; 1230 } 1231 1232 public Monitor communicationLock() { 1233 return communicationLockForSlot(threadSlot); 1234 } 1235 1236 /** 1237 * Initialize the threading subsystem for the boot image. 1238 */ 1239 @Interruptible 1240 public static void init() { 1241 // Enable us to dump a Java Stack from the C trap handler to aid in 1242 // debugging things that 1243 // show up as recursive use of hardware exception registers (eg the 1244 // long-standing lisp bug) 1245 BootRecord.the_boot_record.dumpStackAndDieOffset = 1246 Entrypoints.dumpStackAndDieMethod.getOffset(); 1247 Lock.init(); 1248 } 1249 1250 public void assertAcceptableStates(int expected) { 1251 if (VM.VerifyAssertions) { 1252 int curStatus=getExecStatus(); 1253 if (curStatus!=expected) { 1254 VM.sysWriteln("FATAL ERROR: unexpected thread state."); 1255 VM.sysWriteln("Expected: ",expected); 1256 VM.sysWriteln("Observed: ",curStatus); 1257 VM._assert(curStatus==expected); 1258 } 1259 } 1260 } 1261 1262 public void assertAcceptableStates(int expected1,int expected2) { 1263 if (VM.VerifyAssertions) { 1264 int curStatus=getExecStatus(); 1265 if (curStatus!=expected1 && 1266 curStatus!=expected2) { 1267 VM.sysWriteln("FATAL ERROR: unexpected thread state."); 1268 VM.sysWriteln("Expected: ",expected1); 1269 VM.sysWriteln(" or: ",expected2); 1270 VM.sysWriteln("Observed: ",curStatus); 1271 VM._assert(curStatus==expected1 || 1272 curStatus==expected2); 1273 } 1274 } 1275 } 1276 1277 public void assertUnacceptableStates(int unexpected) { 1278 if (VM.VerifyAssertions) { 1279 int curStatus=getExecStatus(); 1280 if (curStatus==unexpected) { 1281 VM.sysWriteln("FATAL ERROR: unexpected thread state."); 1282 VM.sysWriteln("Unexpected: ",unexpected); 1283 VM.sysWriteln(" Observed: ",curStatus); 1284 VM._assert(curStatus!=unexpected); 1285 } 1286 } 1287 } 1288 1289 public void assertUnacceptableStates(int unexpected1,int unexpected2) { 1290 if (VM.VerifyAssertions) { 1291 int curStatus=getExecStatus(); 1292 if (curStatus==unexpected1 || 1293 curStatus==unexpected2) { 1294 VM.sysWriteln("FATAL ERROR: unexpected thread state for thread", threadSlot); 1295 VM.sysWriteln("Unexpected: ",unexpected1); 1296 VM.sysWriteln(" and: ",unexpected2); 1297 VM.sysWriteln(" Observed: ",curStatus); 1298 VM._assert(curStatus!=unexpected1 && 1299 curStatus!=unexpected2); 1300 } 1301 } 1302 } 1303 1304 static void bind(int cpuId) { 1305 if (VM.VerifyAssertions) VM._assert(sysCall.sysThreadBindSupported()==1); 1306 sysCall.sysThreadBind(cpuId); 1307 } 1308 1309 static void bindIfRequested() { 1310 if (VM.forceOneCPU>=0) { 1311 if (traceBind) { 1312 VM.sysWriteln("binding thread to CPU: ",VM.forceOneCPU); 1313 } 1314 bind(VM.forceOneCPU); 1315 } 1316 } 1317 1318 /** 1319 * Boot the threading subsystem. 1320 */ 1321 @Interruptible 1322 // except not really, since we don't enable yieldpoints yet 1323 public static void boot() { 1324 outOfMemoryError = new OutOfMemoryError(); 1325 dumpLock = new Monitor(); 1326 acctLock = new NoYieldpointsMonitor(); 1327 debugLock = new NoYieldpointsMonitor(); 1328 outputLock = new NoYieldpointsMonitor(); 1329 softHandshakeDataLock = new Monitor(); 1330 handshakeLock = new Monitor(); 1331 doProfileReport = new Latch(false); 1332 monitorBySlot[getCurrentThread().threadSlot] = new NoYieldpointsMonitor(); 1333 communicationLockBySlot[getCurrentThread().threadSlot] = new Monitor(); 1334 sysCall.sysCreateThreadSpecificDataKeys(); 1335 sysCall.sysStashVMThread(getCurrentThread()); 1336 1337 if (traceAcct) { 1338 VM.sysWriteln("boot thread at ",Magic.objectAsAddress(getCurrentThread())); 1339 } 1340 1341 bindIfRequested(); 1342 1343 threadingInitialized = true; 1344 // Always run timer thread, so we can respond to debug requests 1345 new TimerThread().start(); 1346 if (VM.BuildForAdaptiveSystem) { 1347 ObjectHolder.boot(); 1348 } 1349 1350 FinalizerThread.boot(); 1351 getCurrentThread().enableYieldpoints(); 1352 if (traceAcct) VM.sysWriteln("RVMThread booted"); 1353 } 1354 1355 /** 1356 * Add this thread to the termination watchlist. Called by terminating threads 1357 * before they finish terminating. 1358 */ 1359 private void addAboutToTerminate() { 1360 monitor().lockNoHandshake(); 1361 isAboutToTerminate = true; 1362 activeMutatorContext = false; 1363 monitor().broadcast(); 1364 1365 handleHandshakeRequest(); 1366 deinitMutator(); 1367 1368 // WARNING! DANGER! Since we've set isAboutToTerminate to true, when we 1369 // release this lock the GC will: 1370 // 1) No longer scan the thread's stack (though it will *see* the 1371 // thread's stack and mark the stack itself as live, without scanning 1372 // it). 1373 // 2) No longer include the thread in any mutator phases ... hence the 1374 // need to ensure that the mutator context is flushed above. 1375 // 3) No longer attempt to block the thread. 1376 // Moreover, we can no longer do anything that leads to write barriers 1377 // or allocation. 1378 monitor().unlock(); 1379 1380 softRendezvous(); 1381 1382 acctLock.lockNoHandshake(); 1383 aboutToTerminate[aboutToTerminateN++] = threadSlot; 1384 acctLock.unlock(); 1385 } 1386 1387 /** 1388 * Method called after processing a list of threads, or before starting a new 1389 * thread. This does two things. First, it guarantees that the thread slots 1390 * used by any dead threads are freed. Second, it guarantees that each thread 1391 * deregisters itself from GC. Thus, it is essential that after requesting 1392 * things like mutator flushes, you call this, to ensure that any threads that 1393 * had died before or during the mutator flush request do the Right Thing. 1394 */ 1395 @NoCheckStore 1396 public static void processAboutToTerminate() { 1397 if (!neverKillThreads) { 1398 restart: while(true) { 1399 int notKilled = 0; 1400 acctLock.lockNoHandshake(); 1401 for (int i = 0; i < aboutToTerminateN; ++i) { 1402 RVMThread t = threadBySlot[aboutToTerminate[i]]; 1403 if (t.getExecStatus() == TERMINATED) { 1404 aboutToTerminate[i--] = aboutToTerminate[--aboutToTerminateN]; 1405 acctLock.unlock(); 1406 t.releaseThreadSlot(); 1407 continue restart; 1408 } else { 1409 notKilled++; 1410 } 1411 } 1412 acctLock.unlock(); 1413 if (notKilled > 0 && traceAboutToTerminate) { 1414 VM.sysWriteln("didn't kill ", notKilled, " threads"); 1415 } 1416 break; 1417 } 1418 } 1419 } 1420 1421 /** 1422 * Find a thread slot not in use by any other live thread and bind the given 1423 * thread to it. The thread's threadSlot field is set accordingly. 1424 */ 1425 @Interruptible 1426 void assignThreadSlot() { 1427 if (!VM.runningVM) { 1428 // primordial thread 1429 threadSlot = 1; 1430 threadBySlot[1] = this; 1431 threads[0] = this; 1432 threadIdx = 0; 1433 numThreads = 1; 1434 } else { 1435 processAboutToTerminate(); 1436 acctLock.lockNoHandshake(); 1437 if (freeSlotN > 0) { 1438 threadSlot = freeSlots[--freeSlotN]; 1439 } else { 1440 if (nextSlot == threads.length) { 1441 VM.sysFail("too many threads"); 1442 } 1443 threadSlot = nextSlot++; 1444 } 1445 acctLock.unlock(); 1446 // before we actually use this slot, ensure that there is a monitor 1447 // for it. note that if the slot doesn't have a monitor, then we 1448 // "own" it since we allocated it above but haven't done anything 1449 // with it (it's not assigned to a thread, so nobody else can touch 1450 // it) 1451 if (monitorBySlot[threadSlot] == null) { 1452 monitorBySlot[threadSlot] = new NoYieldpointsMonitor(); 1453 } 1454 if (communicationLockBySlot[threadSlot] == null) { 1455 Monitor m = new Monitor(); 1456 handshakeLock.lockWithHandshake(); 1457 communicationLockBySlot[threadSlot] = m; 1458 handshakeLock.unlock(); 1459 } 1460 Magic.sync(); /* 1461 * make sure that nobody sees the thread in any of the 1462 * tables until the thread slot is inited 1463 */ 1464 1465 acctLock.lockNoHandshake(); 1466 threadBySlot[threadSlot] = this; 1467 1468 threadIdx = numThreads++; 1469 threads[threadIdx] = this; 1470 1471 acctLock.unlock(); 1472 } 1473 lockingId = threadSlot << ThinLockConstants.TL_THREAD_ID_SHIFT; 1474 if (traceAcct) { 1475 VM.sysWriteln("Thread #", threadSlot, " at ", Magic.objectAsAddress(this)); 1476 VM.sysWriteln("stack at ", Magic.objectAsAddress(stack), " up to ", Magic.objectAsAddress(stack).plus(stack.length)); 1477 } 1478 } 1479 1480 /** 1481 * Release a thread's slot in the threads array. 1482 */ 1483 @NoCheckStore 1484 void releaseThreadSlot() { 1485 acctLock.lockNoHandshake(); 1486 RVMThread replacementThread = threads[numThreads - 1]; 1487 threads[threadIdx] = replacementThread; 1488 replacementThread.threadIdx = threadIdx; 1489 threadIdx = -1; 1490 Magic.sync(); /* 1491 * make sure that if someone is processing the threads array 1492 * without holding the acctLock (which is definitely legal) 1493 * then they see the replacementThread moved to the new index 1494 * before they see the numThreads decremented (otherwise they 1495 * would miss replacementThread; but with the current 1496 * arrangement at worst they will see it twice) 1497 */ 1498 threads[--numThreads] = null; 1499 threadBySlot[threadSlot] = null; 1500 freeSlots[freeSlotN++] = threadSlot; 1501 acctLock.unlock(); 1502 } 1503 1504 /** 1505 * Create a new RVM Thread 1506 * 1507 * @param stack The stack on which to execute the thread. 1508 * @param thread The corresponding java.lang.Thread. 1509 * @param name The name of the thread 1510 * @param daemon True if this is a daemon thread. 1511 * @param systemThread True if this is a system thread. 1512 * @param priority The threads execution priority. 1513 */ 1514 public RVMThread(byte[] stack, Thread thread, String name, boolean daemon, SystemThread systemThread, int priority) { 1515 this.stack = stack; 1516 1517 this.daemon = daemon; 1518 this.priority = priority; 1519 this.systemThread = systemThread; 1520 1521 this.contextRegisters = this.contextRegistersShadow = new Registers(); 1522 this.contextRegistersSave = this.contextRegistersSaveShadow = new Registers(); 1523 this.exceptionRegisters = this.exceptionRegistersShadow = new Registers(); 1524 1525 if (VM.runningVM) { 1526 feedlet = TraceEngine.engine.makeFeedlet(name, name); 1527 } 1528 1529 if (VM.VerifyAssertions) VM._assert(stack != null); 1530 1531 // put self in list of threads known to scheduler and garbage collector 1532 if (!VM.runningVM) { 1533 if (VM.VerifyAssertions) VM._assert(name != null); 1534 this.name = name; 1535 // create primordial thread (in boot image) 1536 assignThreadSlot(); 1537 1538 if (trace) 1539 trace("RVMThread create: ", name); 1540 if (trace) 1541 trace("daemon: ", daemon ? "true" : "false"); 1542 if (trace) 1543 trace("RVMThread", "create"); 1544 1545 initMutator(threadSlot); 1546 this.activeMutatorContext = true; 1547 // Remember the boot thread 1548 this.execStatus = IN_JAVA; 1549 this.waiting = Waiting.RUNNABLE; 1550 // assign final field 1551 onStackReplacementEvent = null; 1552 } else { 1553 // create a normal (ie. non-primordial) thread 1554 1555 // set up wrapper Thread if one exists 1556 this.thread = thread; 1557 // Set thread type 1558 1559 this.execStatus = NEW; 1560 this.waiting = Waiting.RUNNABLE; 1561 1562 stackLimit = Magic.objectAsAddress(stack).plus(STACK_SIZE_GUARD); 1563 1564 // get instructions for method to be executed as thread startoff 1565 CodeArray instructions = Entrypoints.threadStartoffMethod.getCurrentEntryCodeArray(); 1566 1567 VM.disableGC(); 1568 1569 // initialize thread registers 1570 Address ip = Magic.objectAsAddress(instructions); 1571 Address sp = Magic.objectAsAddress(stack).plus(stack.length); 1572 1573 // Initialize the a thread stack as if "startoff" method had been called 1574 // by an empty baseline-compiled "sentinel" frame with one local variable. 1575 Configuration.archHelper.initializeStack(contextRegisters, ip, sp); 1576 1577 VM.enableGC(); 1578 1579 assignThreadSlot(); 1580 this.name = name == null ? "Thread-" + threadSlot : name; 1581 initMutator(threadSlot); 1582 activeMutatorContext = true; 1583 if (traceAcct) { 1584 VM.sysWriteln("registered mutator for ", threadSlot); 1585 } 1586 1587 initializeJNIEnv(); 1588 1589 if (VM.BuildForAdaptiveSystem) { 1590 onStackReplacementEvent = new OnStackReplacementEvent(); 1591 } else { 1592 onStackReplacementEvent = null; 1593 } 1594 1595 if (thread == null) { 1596 // create wrapper Thread if doesn't exist 1597 this.thread = java.lang.JikesRVMSupport.createThread(this, name); 1598 } 1599 } 1600 } 1601 1602 /** 1603 * Create a thread with default stack and with the given name. 1604 */ 1605 public RVMThread(SystemThread systemThread, String name) { 1606 this(MemoryManager.newStack(STACK_SIZE_NORMAL), null, // java.lang.Thread 1607 name, true, // daemon 1608 systemThread, 1609 Thread.NORM_PRIORITY); 1610 } 1611 1612 /** 1613 * Create a thread with the given stack and name. Used by 1614 * {@link org.jikesrvm.mm.mminterface.CollectorThread} and the 1615 * boot image writer for the boot thread. 1616 */ 1617 public RVMThread(SystemThread systemThread, byte[] stack, String name) { 1618 this(stack, null, // java.lang.Thread 1619 name, true, // daemon 1620 systemThread, 1621 Thread.NORM_PRIORITY); 1622 } 1623 1624 /** 1625 * Create a thread with ... called by java.lang.VMThread.create. System thread 1626 * isn't set. 1627 */ 1628 public RVMThread(Thread thread, long stacksize, String name, boolean daemon, int priority) { 1629 this(MemoryManager.newStack((stacksize <= 0) ? STACK_SIZE_NORMAL : (int) stacksize), thread, name, daemon, null, priority); 1630 } 1631 1632 /** 1633 * Check if the thread has block requests (for example, for suspension and GC). If 1634 * it does, clear the requests and marked the thread as blocked for that request. 1635 * If there were any block requests, do a broadcast() on the thread's monitor(). 1636 * This is an internal method and should only be called from code that implements 1637 * thread blocking. The monitor() lock must be held for this method to work properly. 1638 */ 1639 private void acknowledgeBlockRequests() { 1640 boolean hadSome = false; 1641 if (VM.VerifyAssertions) 1642 VM._assert(blockAdapters != null); 1643 for (int i = 0; i < blockAdapters.length; ++i) { 1644 if (blockAdapters[i].hasBlockRequest(this)) { 1645 blockAdapters[i].setBlocked(this, true); 1646 blockAdapters[i].clearBlockRequest(this); 1647 hadSome = true; 1648 } 1649 } 1650 if (hadSome) { 1651 monitor().broadcast(); 1652 } 1653 } 1654 1655 /** 1656 * Checks if the thread system has acknowledged that the thread is supposed 1657 * to be blocked. This will return true if the thread is actually blocking, or 1658 * if the thread is running native code but is guaranteed to block before 1659 * returning to Java. Only call this method when already holding the monitor(), 1660 * for two reasons: 1661 * <ol> 1662 * <li>This method does not acquire the monitor() lock even though it needs 1663 * to have it acquired given the data structures that it is accessing. 1664 * <li>You will typically want to call this method to decide if you need to 1665 * take action under the assumption that the thread is blocked (or not 1666 * blocked). So long as you hold the lock the thread cannot change state from 1667 * blocked to not blocked. 1668 * </ol> 1669 * 1670 * @return if the thread is supposed to be blocked 1671 */ 1672 public boolean isBlocked() { 1673 for (int i = 0; i < blockAdapters.length; ++i) { 1674 if (blockAdapters[i].isBlocked(this)) { 1675 return true; 1676 } 1677 } 1678 return false; 1679 } 1680 1681 /** 1682 * Checks if the thread is executing Java code. A thread is executing Java 1683 * code if its <code>execStatus</code> is <code>IN_JAVA</code> or 1684 * <code>IN_JAVA_TO_BLOCK</code>, and if it is not 1685 * <code>aboutToTerminate</code>, and if it is not blocked. Only call this 1686 * method when already holding the monitor(), and probably only after calling 1687 * setBlockedExecStatus(), for two reasons: 1688 * <ol> 1689 * <li>This method does not acquire the monitor() lock even though it needs 1690 * to have it acquired given the data structures that it is accessing. 1691 * <li>You will typically want to call this method to decide if you need to 1692 * take action under the assumption that the thread is running Java (or not 1693 * running Java). So long as you hold the lock - and you have called 1694 * setBlockedExecStatus() - the thread cannot change state from running-Java 1695 * to not-running-Java. 1696 * </ol> 1697 * 1698 * @return if the thread is running Java 1699 */ 1700 public boolean isInJava() { 1701 return !isBlocking && !isAboutToTerminate && 1702 (getExecStatus() == IN_JAVA || getExecStatus() == IN_JAVA_TO_BLOCK); 1703 } 1704 1705 /** 1706 * Should the thread by eligible for sampling by the timer thread? 1707 * Heuristically, we use timer-based sampling the in the adaptive system 1708 * to determine where the program is spending time (and thus what to optimize). 1709 * This doesn't have to be a 100% accurate, but it must be non-blocking 1710 * and also closely approximate whether or not the thread is executing. 1711 * For now, approximate just as being in JAVA. 1712 * As a future item, we may want to actually correctly attribute time 1713 * spent in native code to the top native method on the frame when the timer 1714 * goes off. This will require work in the JNI enter/exit sequence to deal with 1715 * timer samples appropriately. 1716 */ 1717 public boolean shouldBeSampled() { 1718 return execStatus == IN_JAVA; 1719 } 1720 1721 /** A variant of checkBlock() that does not save the thread state. */ 1722 @NoInline 1723 @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking") 1724 private void checkBlockNoSaveContext() { 1725 assertUnacceptableStates(NEW, TERMINATED); 1726 if (VM.VerifyAssertions) VM._assert(!isAboutToTerminate); 1727 if (VM.VerifyAssertions) VM._assert(!isBlocking); 1728 1729 if (traceBlock) 1730 VM.sysWriteln("Thread #", threadSlot, " in checkBlockNoSaveContext"); 1731 // NB: anything this method calls CANNOT change the contextRegisters 1732 // or the JNI env. as well, this code will be running concurrently 1733 // with stop-the-world GC! 1734 monitor().lockNoHandshake(); 1735 isBlocking = true; 1736 if (traceBlock) 1737 VM.sysWriteln("Thread #", threadSlot, 1738 " acquired lock and has notified everyone that we're blocked"); 1739 1740 // deal with requests that would require a soft handshake rendezvous 1741 handleHandshakeRequest(); 1742 // check if a soft handshake has been requested, and if so, clear the 1743 // request 1744 boolean commitSoftRendezvous = softRendezvousCheckAndClear(); 1745 if (commitSoftRendezvous) { 1746 // if a soft handshake had been requested, we need to acknowledge it. 1747 // but to acknowledge it we cannot be holding the monitor() lock. 1748 // it turns out that at this point in the code it is perfectly safe 1749 // to release it, because: 1750 // 1) callers of this method expect that it may, in all likelihood, 1751 // release the monitor() lock if they were holding it, since it 1752 // calls wait() 1753 // 2) if the block requests get cleared when we release the lock, 1754 // we won't call wait, since we reacquire the lock prior to checking 1755 // for block requests. 1756 int recCount = monitor().unlockCompletely(); 1757 softRendezvousCommit(); 1758 monitor().relockNoHandshake(recCount); 1759 } 1760 1761 if (traceBlock) 1762 VM.sysWriteln("Thread #", threadSlot, 1763 " has acknowledged soft handshakes"); 1764 1765 boolean hadReallyBlocked=false; 1766 1767 for (;;) { 1768 // deal with block requests 1769 acknowledgeBlockRequests(); 1770 // are we blocked? 1771 if (!isBlocked()) { 1772 break; 1773 } 1774 if (traceReallyBlock) { 1775 hadReallyBlocked=true; 1776 VM.sysWriteln("Thread #", threadSlot, 1777 " is really blocked with status ", getExecStatus()); 1778 VM.sysWriteln("Thread #", threadSlot, 1779 " has fp = ", Magic.getFramePointer()); 1780 if (dumpStackOnBlock) { 1781 dumpStack(); 1782 } 1783 } 1784 // what if a GC request comes while we're here for a suspend() 1785 // request? 1786 // answer: we get awoken, reloop, and acknowledge the GC block 1787 // request. 1788 monitor().waitNoHandshake(); 1789 1790 if (traceBlock) 1791 VM.sysWriteln("Thread #", threadSlot, 1792 " has awoken; checking if we're still blocked"); 1793 } 1794 1795 if (traceBlock || (traceReallyBlock && hadReallyBlocked)) 1796 VM.sysWriteln("Thread #", threadSlot, " is unblocking"); 1797 1798 // we're about to unblock, so indicate to the world that we're running 1799 // again. 1800 setExecStatus(IN_JAVA); 1801 // let everyone know that we're back to executing code 1802 isBlocking = false; 1803 // deal with requests that came up while we were blocked. 1804 handleHandshakeRequest(); 1805 monitor().unlock(); 1806 1807 if (traceBlock) 1808 VM.sysWriteln("Thread #", threadSlot, " is unblocked"); 1809 } 1810 1811 /** 1812 * Check if the thread is supposed to block, and if so, block it. This method 1813 * will ensure that soft handshake requests are acknowledged or else 1814 * inhibited, that any blocking request is handled, that the execution state 1815 * of the thread (<code>execStatus</code>) is set to <code>IN_JAVA</code> 1816 * once all blocking requests are cleared, and that other threads are notified 1817 * that this thread is in the middle of blocking by setting the appropriate 1818 * flag (<code>isBlocking</code>). Note that this thread acquires the 1819 * monitor(), though it may release it completely either by calling wait() or 1820 * by calling unlockCompletely(). Thus, although it isn't generally a problem 1821 * to call this method while holding the monitor() lock, you should only do so 1822 * if the loss of atomicity is acceptable. 1823 * <p> 1824 * Generally, this method should be called from the following four places: 1825 * <ol> 1826 * <li>The block() method, if the thread is requesting to block itself. 1827 * Currently such requests only come when a thread calls suspend(). Doing so 1828 * has unclear semantics (other threads may call resume() too early causing 1829 * the well-known race) but must be supported because it's still part of the 1830 * JDK. Why it's safe: the block() method needs to hold the monitor() for the 1831 * time it takes it to make the block request, but does not need to continue 1832 * to hold it when it calls checkBlock(). Thus, the fact that checkBlock() 1833 * breaks atomicity is not a concern. 1834 * <li>The yieldpoint. One of the purposes of a yieldpoint is to periodically 1835 * check if the current thread should be blocked. This is accomplished by 1836 * calling checkBlock(). Why it's safe: the yieldpoint performs several 1837 * distinct actions, all of which individually require the monitor() lock - 1838 * but the monitor() lock does not have to be held contiguously. Thus, the 1839 * loss of atomicity from calling checkBlock() is fine. 1840 * <li>The "WithHandshake" methods of HeavyCondLock. These methods allow you to 1841 * block on a mutex or condition variable while notifying the system that you 1842 * are not executing Java code. When these blocking methods return, they check 1843 * if there had been a request to block, and if so, they call checkBlock(). 1844 * Why it's safe: This is subtle. Two cases exist. The first case is when a 1845 * WithHandshake method is called on a HeavyCondLock instance that is not a thread 1846 * monitor(). In this case, it does not matter that checkBlock() may acquire 1847 * and then completely release the monitor(), since the user was not holding 1848 * the monitor(). However, this will break if the user is <i>also</i> holding 1849 * the monitor() when calling the WithHandshake method on a different lock. This case 1850 * should never happen because no other locks should ever be acquired when the 1851 * monitor() is held. Additionally: there is the concern that some other locks 1852 * should never be held while attempting to acquire the monitor(); the 1853 * HeavyCondLock ensures that checkBlock() is only called when that lock 1854 * itself is released. The other case is when a WithHandshake method is called on the 1855 * monitor() itself. This should only be done when using <i>your own</i> 1856 * monitor() - that is the monitor() of the thread your are running on. In 1857 * this case, the WithHandshake methods work because: (i) lockWithHandshake() only calls 1858 * checkBlock() on the initial lock entry (not on recursive entry), so 1859 * atomicity is not broken, and (ii) waitWithHandshake() and friends only call 1860 * checkBlock() after wait() returns - at which point it is safe to release 1861 * and reacquire the lock, since there cannot be a race with broadcast() once 1862 * we have committed to not calling wait() again. 1863 * <li>Any code following a potentially-blocking native call. Case (3) above 1864 * is somewhat subsumed in this except that it is special due to the fact that 1865 * it's blocking on VM locks. So, this case refers specifically to JNI. The 1866 * JNI epilogues will call leaveJNIBlocked(), which calls a variant of this 1867 * method. 1868 * </ol> 1869 */ 1870 @NoInline 1871 @NoOptCompile 1872 @BaselineSaveLSRegisters 1873 @Unpreemptible("May block if asked to do so, but otherwise does not actions that would block") 1874 void checkBlock() { 1875 saveThreadState(); 1876 checkBlockNoSaveContext(); 1877 } 1878 1879 /** 1880 * Internal method for transitioning a thread from IN_JAVA or IN_JAVA_TO_BLOCK to 1881 * either BLOCKED_IN_NATIVE or BLOCKED_IN_JNI, depending on the value of the jni 1882 * parameter. It is always safe to conservatively call this method when transitioning 1883 * to native code, though it is faster to call either enterNative(), 1884 * enterJNIFromCallIntoNative(), or enterJNIFromJNIFunctionCall(). 1885 * <p> 1886 * This method takes care of all bookkeeping and notifications required when a 1887 * a thread that has been requested to block instead decides to run native code. 1888 * Threads enter native code never need to block, since they will not be executing 1889 * any Java code. However, such threads must ensure that any system services (like 1890 * GC) that are waiting for this thread to stop are notified that the thread has 1891 * instead chosen to exit Java. As well, any requests to perform a sot handshake 1892 * must be serviced and acknowledged. 1893 */ 1894 private void enterNativeBlockedImpl(boolean jni) { 1895 if (traceReallyBlock) 1896 VM.sysWriteln("Thread #", threadSlot, " entering native blocked."); 1897 // NB: anything this method calls CANNOT change the contextRegisters 1898 // or the JNI env. as well, this code will be running concurrently 1899 // with stop-the-world GC! 1900 boolean commitSoftRendezvous; 1901 monitor().lockNoHandshake(); 1902 if (jni) { 1903 jniEnteredBlocked++; 1904 setExecStatus(BLOCKED_IN_JNI); 1905 } else { 1906 nativeEnteredBlocked++; 1907 setExecStatus(BLOCKED_IN_NATIVE); 1908 } 1909 acknowledgeBlockRequests(); 1910 handleHandshakeRequest(); 1911 commitSoftRendezvous = softRendezvousCheckAndClear(); 1912 monitor().unlock(); 1913 if (traceBlock) 1914 VM.sysWriteln("Thread #", threadSlot, 1915 " done with the locking part of native entry."); 1916 if (commitSoftRendezvous) 1917 softRendezvousCommit(); 1918 if (traceBlock) 1919 VM.sysWriteln("Thread #", threadSlot, " done enter native blocked."); 1920 } 1921 1922 @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking") 1923 private void leaveNativeBlockedImpl() { 1924 checkBlockNoSaveContext(); 1925 } 1926 1927 private void enterNativeBlocked() { 1928 assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK); 1929 enterNativeBlockedImpl(false); 1930 assertAcceptableStates(IN_NATIVE,BLOCKED_IN_NATIVE); 1931 } 1932 1933 @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking") 1934 private void leaveNativeBlocked() { 1935 assertAcceptableStates(IN_NATIVE,BLOCKED_IN_NATIVE); 1936 leaveNativeBlockedImpl(); 1937 assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK); 1938 } 1939 1940 private void enterJNIBlocked() { 1941 assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK); 1942 enterNativeBlockedImpl(true); 1943 assertAcceptableStates(IN_JNI,BLOCKED_IN_JNI); 1944 } 1945 1946 @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking") 1947 private void leaveJNIBlocked() { 1948 assertAcceptableStates(IN_JNI,BLOCKED_IN_JNI); 1949 leaveNativeBlockedImpl(); 1950 assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK); 1951 } 1952 1953 @Entrypoint 1954 public static void enterJNIBlockedFromJNIFunctionCall() { 1955 RVMThread t=getCurrentThread(); 1956 if (traceReallyBlock) { 1957 VM.sysWriteln("Thread #",t.getThreadSlot(), " in enterJNIBlockedFromJNIFunctionCall"); 1958 VM.sysWriteln("thread address = ",Magic.objectAsAddress(t)); 1959 } 1960 t.enterJNIBlocked(); 1961 } 1962 1963 @Entrypoint 1964 public static void enterJNIBlockedFromCallIntoNative() { 1965 RVMThread t=getCurrentThread(); 1966 if (traceReallyBlock) { 1967 VM.sysWriteln("Thread #",t.getThreadSlot(), " in enterJNIBlockedFromCallIntoNative"); 1968 VM.sysWriteln("thread address = ",Magic.objectAsAddress(t)); 1969 } 1970 t.enterJNIBlocked(); 1971 } 1972 1973 @Entrypoint 1974 @Unpreemptible("May block if the thread was asked to do so, but otherwise will not block") 1975 static void leaveJNIBlockedFromJNIFunctionCall() { 1976 RVMThread t = getCurrentThread(); 1977 if (traceReallyBlock) { 1978 VM.sysWriteln("Thread #", t.getThreadSlot(), 1979 " in leaveJNIBlockedFromJNIFunctionCall"); 1980 VM.sysWriteln("thread address = ",Magic.objectAsAddress(t)); 1981 VM.sysWriteln("state = ", t.getExecStatus()); 1982 VM.sysWriteln("jtoc = ", Magic.getJTOC()); 1983 } 1984 t.leaveJNIBlocked(); 1985 } 1986 1987 /** 1988 * Called when JNI code tried to transition from IN_JNI to IN_JAVA but failed 1989 */ 1990 @Entrypoint 1991 @Unpreemptible("May block if the thread was asked to do so, but otherwise will not block") 1992 public static void leaveJNIBlockedFromCallIntoNative() { 1993 RVMThread t = getCurrentThread(); 1994 if (traceReallyBlock) { 1995 VM.sysWriteln("Thread #", t.getThreadSlot(), 1996 " in leaveJNIBlockedFromCallIntoNative"); 1997 VM.sysWriteln("state = ", t.getExecStatus()); 1998 VM.sysWriteln("jtoc = ", Magic.getJTOC()); 1999 } 2000 t.leaveJNIBlocked(); 2001 } 2002 2003 private int setBlockedExecStatus() { 2004 int oldState, newState; 2005 do { 2006 oldState = getExecStatus(); 2007 if (oldState == IN_JAVA) { 2008 newState = IN_JAVA_TO_BLOCK; 2009 } else if (oldState == IN_NATIVE) { 2010 newState = BLOCKED_IN_NATIVE; 2011 } else if (oldState == IN_JNI) { 2012 newState = BLOCKED_IN_JNI; 2013 } else { 2014 newState = oldState; 2015 } 2016 /* 2017 * use the CAS to assert that we observed what we 2018 * thought we observed 2019 */ 2020 } while (!(attemptFastExecStatusTransition(oldState,newState))); 2021 return newState; 2022 } 2023 2024 /** 2025 * Attempt to block the thread, and return the state it is in after the 2026 * attempt. If we're blocking ourselves, this will always return IN_JAVA. If 2027 * the thread signals to us the intention to die as we are trying to block it, 2028 * this will return TERMINATED. NOTE: the thread's execStatus will not 2029 * actually be TERMINATED at that point yet. 2030 * <p> 2031 * Note that this method is ridiculously dangerous, especially if you pass 2032 * asynchronous==false. Waiting for another thread to stop is not in itself 2033 * interruptible - so if you ask another thread to block and they ask you 2034 * to block, you might deadlock. 2035 */ 2036 @Unpreemptible("Only blocks if the receiver is the current thread, or if asynchronous is set to false and the thread is not already blocked") 2037 int block(BlockAdapter ba, boolean asynchronous) { 2038 int result; 2039 if (traceBlock) 2040 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2041 " is requesting that thread #", threadSlot, " blocks."); 2042 monitor().lockNoHandshake(); 2043 int token = ba.requestBlock(this); 2044 if (getCurrentThread() == this) { 2045 if (traceBlock) 2046 VM.sysWriteln("Thread #", threadSlot, " is blocking."); 2047 checkBlock(); 2048 result = getExecStatus(); 2049 } else { 2050 if (traceBlock) 2051 VM.sysWriteln("Thread #", threadSlot, " is being told to block."); 2052 if (isAboutToTerminate) { 2053 if (traceBlock) 2054 VM.sysWriteln("Thread #", threadSlot, 2055 " is terminating, returning as if blocked in TERMINATED state."); 2056 result = TERMINATED; 2057 } else { 2058 takeYieldpoint = 1; 2059 // CAS the execStatus field 2060 int newState = setBlockedExecStatus(); 2061 result = newState; 2062 if (traceReallyBlock) 2063 VM.sysWriteln("Thread #", getCurrentThreadSlot(), 2064 " is blocking thread #", threadSlot, " which is in state ", 2065 newState); 2066 // this broadcast serves two purposes: notifies threads that are 2067 // IN_JAVA but waiting on monitor() that they should awake and 2068 // acknowledge the block request; or notifies anyone 2069 // waiting for this thread to block that the thread is 2070 // BLOCKED_IN_NATIVE or BLOCKED_IN_JNI. in the latter case the 2071 // broadcast() happens _before_ the setting of the flags that the 2072 // other threads would be awaiting, but that is fine, since we're 2073 // still holding the lock anyway. 2074 monitor().broadcast(); 2075 if (newState == IN_JAVA_TO_BLOCK) { 2076 if (!asynchronous) { 2077 if (traceBlock) 2078 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2079 " is waiting for thread #", threadSlot, " to block."); 2080 while (ba.hasBlockRequest(this, token) && !ba.isBlocked(this) && !isAboutToTerminate) { 2081 if (traceBlock) 2082 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2083 " is calling wait until thread #", threadSlot, " blocks."); 2084 // will this deadlock when the thread dies? 2085 if (VM.VerifyAssertions) { 2086 // do a timed wait, and assert that the thread did not disappear 2087 // into native in the meantime 2088 monitor().timedWaitRelativeNoHandshake(1000L * 1000L * 1000L); // 1 sec 2089 if (traceReallyBlock) { 2090 VM.sysWriteln("Thread #", threadSlot, "'s status is ", 2091 getExecStatus()); 2092 } 2093 assertUnacceptableStates(IN_NATIVE); 2094 } else { 2095 monitor().waitNoHandshake(); 2096 } 2097 if (traceBlock) 2098 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2099 " has returned from the wait call."); 2100 } 2101 if (isAboutToTerminate) { 2102 result = TERMINATED; 2103 } else { 2104 result=getExecStatus(); 2105 } 2106 } 2107 } else if (newState == BLOCKED_IN_NATIVE || newState == BLOCKED_IN_JNI) { 2108 // we own the thread for now - it cannot go back to executing Java 2109 // code until we release the lock. before we do so we change its 2110 // state accordingly and tell anyone who is waiting. 2111 if (traceBlock) 2112 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2113 " has seen thread #", threadSlot, 2114 " in native; changing its status accordingly."); 2115 ba.clearBlockRequest(this); 2116 ba.setBlocked(this, true); 2117 } 2118 } 2119 } 2120 monitor().unlock(); 2121 if (traceReallyBlock) 2122 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2123 " is done telling thread #", threadSlot, " to block."); 2124 return result; 2125 } 2126 2127 public boolean blockedFor(BlockAdapter ba) { 2128 monitor().lockNoHandshake(); 2129 boolean result = ba.isBlocked(this); 2130 monitor().unlock(); 2131 return result; 2132 } 2133 2134 @UninterruptibleNoWarn("Never blocks; only asynchronously notifies the receiver to do so") 2135 public int asyncBlock(BlockAdapter ba) { 2136 if (VM.VerifyAssertions) 2137 VM._assert(getCurrentThread() != this); 2138 return block(ba, true); 2139 } 2140 2141 @Unpreemptible("May block if the receiver is the current thread or if the receiver is not yet blocked; otherwise does not perform actions that lead to blocking") 2142 public int block(BlockAdapter ba) { 2143 return block(ba, false); 2144 } 2145 2146 @Unpreemptible 2147 public void beginPairWith(RVMThread other) { 2148 if (traceBlock) VM.sysWriteln("attempting to pair ",threadSlot," with ",other.threadSlot); 2149 Monitor.lockWithHandshake( 2150 communicationLock(),Word.fromIntSignExtend(threadSlot), 2151 other.communicationLock(),Word.fromIntSignExtend(other.threadSlot)); 2152 } 2153 2154 public void endPairWith(RVMThread other) { 2155 communicationLock().unlock(); 2156 other.communicationLock().unlock(); 2157 if (traceBlock) VM.sysWriteln("unpairing ",threadSlot," from ",other.threadSlot); 2158 } 2159 2160 @Unpreemptible 2161 public void beginPairWithCurrent() { 2162 beginPairWith(getCurrentThread()); 2163 } 2164 2165 public void endPairWithCurrent() { 2166 endPairWith(getCurrentThread()); 2167 } 2168 2169 @Unpreemptible 2170 private int safeBlock(BlockAdapter ba, boolean asynchronous) { 2171 if (VM.VerifyAssertions) 2172 VM._assert(getCurrentThread() != this); 2173 beginPairWithCurrent(); 2174 int result=block(ba,asynchronous); 2175 endPairWithCurrent(); 2176 return result; 2177 } 2178 2179 @Unpreemptible 2180 public int safeAsyncBlock(BlockAdapter ba) { 2181 return safeBlock(ba, true); 2182 } 2183 2184 @Unpreemptible 2185 public int safeBlock(BlockAdapter ba) { 2186 if (getCurrentThread()==this) { 2187 return block(ba,false); 2188 } else { 2189 return safeBlock(ba, false); 2190 } 2191 } 2192 2193 @Unpreemptible 2194 public void beginPairHandshake() { 2195 beginPairWithCurrent(); 2196 block(handshakeBlockAdapter); 2197 } 2198 2199 @Uninterruptible 2200 public void endPairHandshake() { 2201 unblock(handshakeBlockAdapter); 2202 endPairWithCurrent(); 2203 } 2204 2205 /** 2206 * Save the current thread state. Call this prior to calling enterNative(). You must 2207 * be in a method that is marked BaselineSaveLSRegisters. 2208 */ 2209 @NoInline 2210 public static void saveThreadState() { 2211 Address curFP=Magic.getFramePointer(); 2212 getCurrentThread().contextRegisters.setInnermost(Magic.getReturnAddressUnchecked(curFP), 2213 Magic.getCallerFramePointer(curFP)); 2214 } 2215 2216 /** 2217 * Indicate that we'd like the current thread to be executing privileged code that 2218 * does not require synchronization with the GC. This call may be made on a thread 2219 * that is IN_JAVA or IN_JAVA_TO_BLOCK, and will result in the thread being either 2220 * IN_NATIVE or BLOCKED_IN_NATIVE. In the case of an 2221 * IN_JAVA_TO_BLOCK->BLOCKED_IN_NATIVE transition, this call will acquire the 2222 * thread's lock and send out a notification to any threads waiting for this thread 2223 * to reach a safepoint. This notification serves to notify them that the thread 2224 * is in GC-safe code, but will not reach an actual safepoint for an indetermined 2225 * amount of time. This is significant, because safepoints may perform additional 2226 * actions (such as handling handshake requests, which may include things like 2227 * mutator flushes and running isync) that IN_NATIVE code will not perform until 2228 * returning to IN_JAVA by way of a leaveNative() call. 2229 */ 2230 @NoInline // so we can get the fp 2231 public static void enterNative() { 2232 RVMThread t = getCurrentThread(); 2233 if (ALWAYS_LOCK_ON_STATE_TRANSITION) { 2234 t.enterNativeBlocked(); 2235 } else { 2236 int oldState, newState; 2237 do { 2238 oldState = t.getExecStatus(); 2239 if (oldState == IN_JAVA) { 2240 newState = IN_NATIVE; 2241 } else { 2242 t.assertAcceptableStates(IN_JAVA_TO_BLOCK); 2243 t.enterNativeBlocked(); 2244 return; 2245 } 2246 } while (!(t.attemptFastExecStatusTransition(oldState, newState))); 2247 } 2248 // NB this is not a correct assertion, as there is a race. we could succeed in 2249 // CASing the status to IN_NATIVE, but then someone else could asynchronosly 2250 // set it to whatever they want. 2251 //if (VM.VerifyAssertions) 2252 // VM._assert(t.execStatus == IN_NATIVE); 2253 } 2254 2255 /** 2256 * Attempt to transition from IN_JNI or IN_NATIVE to IN_JAVA, fail if execStatus is 2257 * anything but IN_JNI or IN_NATIVE. 2258 * 2259 * @return true if thread transitioned to IN_JAVA, otherwise false 2260 */ 2261 public static boolean attemptLeaveNativeNoBlock() { 2262 if (ALWAYS_LOCK_ON_STATE_TRANSITION) 2263 return false; 2264 RVMThread t = getCurrentThread(); 2265 int oldState, newState; 2266 do { 2267 oldState = t.getExecStatus(); 2268 if (oldState == IN_NATIVE || oldState == IN_JNI) { 2269 newState = IN_JAVA; 2270 } else { 2271 t.assertAcceptableStates(BLOCKED_IN_NATIVE,BLOCKED_IN_JNI); 2272 return false; 2273 } 2274 } while (!(t.attemptFastExecStatusTransition(oldState, newState))); 2275 return true; 2276 } 2277 2278 /** 2279 * Leave privileged code. This is valid for threads that are either IN_NATIVE, 2280 * IN_JNI, BLOCKED_IN_NATIVE, or BLOCKED_IN_JNI, and always results in the thread 2281 * being IN_JAVA. If the thread was previously BLOCKED_IN_NATIVE or BLOCKED_IN_JNI, 2282 * the thread will block until notified that it can run again. 2283 */ 2284 @Unpreemptible("May block if the thread was asked to do so; otherwise does no actions that would lead to blocking") 2285 public static void leaveNative() { 2286 if (!attemptLeaveNativeNoBlock()) { 2287 if (traceReallyBlock) { 2288 VM.sysWriteln("Thread #", getCurrentThreadSlot(), 2289 " is leaving native blocked"); 2290 } 2291 getCurrentThread().leaveNativeBlocked(); 2292 } 2293 } 2294 2295 public static void enterJNIFromCallIntoNative() { 2296 // FIXME: call these in PPC instead of doing it in machine code... 2297 getCurrentThread().observeExecStatus(); 2298 if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JAVA, 2299 RVMThread.IN_JNI)) { 2300 RVMThread.enterJNIBlockedFromCallIntoNative(); 2301 } 2302 } 2303 2304 @Unpreemptible 2305 public static void leaveJNIFromCallIntoNative() { 2306 // FIXME: call these in PPC instead of doing it in machine code... 2307 getCurrentThread().observeExecStatus(); 2308 if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JNI, 2309 RVMThread.IN_JAVA)) { 2310 RVMThread.leaveJNIBlockedFromCallIntoNative(); 2311 } 2312 } 2313 2314 public static void enterJNIFromJNIFunctionCall() { 2315 // FIXME: call these instead of doing it in machine code... currently this 2316 // is never called. 2317 getCurrentThread().observeExecStatus(); 2318 if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JAVA, 2319 RVMThread.IN_JNI)) { 2320 RVMThread.enterJNIBlockedFromJNIFunctionCall(); 2321 } 2322 } 2323 2324 @Unpreemptible 2325 public static void leaveJNIFromJNIFunctionCall() { 2326 // FIXME: call these instead of doing it in machine code... currently this 2327 // is never called. 2328 getCurrentThread().observeExecStatus(); 2329 if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JNI, 2330 RVMThread.IN_JAVA)) { 2331 RVMThread.leaveJNIBlockedFromJNIFunctionCall(); 2332 } 2333 } 2334 2335 public void unblock(BlockAdapter ba) { 2336 if (traceBlock) 2337 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2338 " is requesting that thread #", threadSlot, " unblocks."); 2339 monitor().lockNoHandshake(); 2340 ba.clearBlockRequest(this); 2341 ba.setBlocked(this, false); 2342 monitor().broadcast(); 2343 monitor().unlock(); 2344 if (traceBlock) 2345 VM.sysWriteln("Thread #", getCurrentThread().threadSlot, 2346 " is done requesting that thread #", threadSlot, " unblocks."); 2347 } 2348 2349 private void handleDebugRequestForThread() { 2350 monitor().lockNoHandshake(); 2351 dumpLock.lockNoHandshake(); 2352 extDump(); 2353 if (!isAboutToTerminate) { 2354 setBlockedExecStatus(); 2355 if (isInJava()) { 2356 asyncDebugRequestedForThisThread = true; 2357 takeYieldpoint = 1; 2358 VM.sysWriteln("(stack trace will follow if thread is not lost...)"); 2359 } else { 2360 if (contextRegisters != null) { 2361 dumpStack(contextRegisters.getInnermostFramePointer()); 2362 } else { 2363 VM.sysWriteln("(cannot dump stack trace; thread is not running in Java but has no contextRegisters)"); 2364 } 2365 } 2366 } 2367 dumpLock.unlock(); 2368 monitor().unlock(); 2369 } 2370 2371 @NoCheckStore 2372 public static void checkDebugRequest() { 2373 if (debugRequested) { 2374 debugLock.lockNoHandshake(); 2375 if (debugRequested) { 2376 debugRequested = false; 2377 VM.sysWriteln("=== Debug requested - attempting safe VM dump ==="); 2378 dumpAcct(); 2379 reportThreadTransitionCounts(); 2380 2381 // FIXME: this code runs concurrently to GC and has no way of stopping 2382 // it. hence it is dangerous. leaving it as-is for now, since it's 2383 // only meant to be used for debugging. 2384 2385 VM.sysWriteln("Timer ticks = ", timerTicks); 2386 doProfileReport.openNoHandshake(); 2387 // snapshot the threads 2388 acctLock.lockNoHandshake(); 2389 int numDebugThreads = numThreads; 2390 for (int i = 0; i < numThreads; ++i) { 2391 debugThreads[i] = threads[i]; 2392 } 2393 acctLock.unlock(); 2394 // do the magic 2395 for (int i = 0; i < numDebugThreads; ++i) { 2396 debugThreads[i].handleDebugRequestForThread(); 2397 debugThreads[i] = null; 2398 } 2399 } 2400 debugLock.unlock(); 2401 } 2402 } 2403 2404 void timerTick() { 2405 if (shouldBeSampled()) { 2406 timeSliceExpired++; 2407 takeYieldpoint=1; 2408 } 2409 } 2410 2411 /** Are we allowed to take yieldpoints? */ 2412 @Inline 2413 public boolean yieldpointsEnabled() { 2414 return yieldpointsEnabledCount == 1; 2415 } 2416 2417 /** Enable yieldpoints on this thread. */ 2418 public void enableYieldpoints() { 2419 ++yieldpointsEnabledCount; 2420 if (VM.VerifyAssertions) 2421 VM._assert(yieldpointsEnabledCount <= 1); 2422 if (yieldpointsEnabled() && yieldpointRequestPending) { 2423 takeYieldpoint = 1; 2424 yieldpointRequestPending = false; 2425 } 2426 } 2427 2428 /** Disable yieldpoints on this thread. */ 2429 public void disableYieldpoints() { 2430 --yieldpointsEnabledCount; 2431 } 2432 2433 /** 2434 * Fail if yieldpoints are disabled on this thread 2435 */ 2436 public void failIfYieldpointsDisabled() { 2437 if (!yieldpointsEnabled()) { 2438 VM.sysWrite("No yieldpoints on thread ", threadSlot); 2439 VM.sysWrite(" with addr ", Magic.objectAsAddress(this)); 2440 VM.sysWriteln(); 2441 VM.sysFail("Yieldpoints are disabled on this thread!"); 2442 } 2443 } 2444 2445 /** 2446 * @return The currently executing thread 2447 */ 2448 @Uninterruptible 2449 public static RVMThread getCurrentThread() { 2450 return ThreadLocalState.getCurrentThread(); 2451 } 2452 2453 /** 2454 * @return the unique slot of the currently executing thread 2455 */ 2456 public static int getCurrentThreadSlot() { 2457 return getCurrentThread().threadSlot; 2458 } 2459 2460 /** 2461 * @return the slot of this thread 2462 */ 2463 public int getThreadSlot() { 2464 return threadSlot; 2465 } 2466 2467 /** 2468 * Called during booting to give the boot thread a java.lang.Thread 2469 */ 2470 @Interruptible 2471 public void setupBootJavaThread() { 2472 thread = java.lang.JikesRVMSupport.createThread(this, 2473 "Jikes_RVM_Boot_Thread"); 2474 } 2475 2476 /** 2477 * String representation of thread 2478 */ 2479 @Override 2480 public String toString() { 2481 return name; 2482 } 2483 2484 /** 2485 * Get the current java.lang.Thread. 2486 */ 2487 public Thread getJavaLangThread() { 2488 return thread; 2489 } 2490 2491 /** 2492 * Get current thread's JNI environment. 2493 */ 2494 public JNIEnvironment getJNIEnv() { 2495 return jniEnv; 2496 } 2497 2498 /** Get the disable GC depth */ 2499 public int getDisableGCDepth() { 2500 return disableGCDepth; 2501 } 2502 2503 /** Modify the disable GC depth */ 2504 public void setDisableGCDepth(int d) { 2505 disableGCDepth = d; 2506 } 2507 2508 /** Are allocations allowed by this thread? */ 2509 public boolean getDisallowAllocationsByThisThread() { 2510 return disallowAllocationsByThisThread; 2511 } 2512 2513 /** Disallow allocations by this thread */ 2514 public void setDisallowAllocationsByThisThread() { 2515 disallowAllocationsByThisThread = true; 2516 } 2517 2518 /** Allow allocations by this thread */ 2519 public void clearDisallowAllocationsByThisThread() { 2520 disallowAllocationsByThisThread = false; 2521 } 2522 2523 /** 2524 * Initialize JNI environment for system threads. Called by VM.finishBooting 2525 */ 2526 @Interruptible 2527 public void initializeJNIEnv() { 2528 this.jniEnv = this.jniEnvShadow = new JNIEnvironment(); 2529 } 2530 2531 /** 2532 * Indicate whether the stack of this Thread contains any C frame (used in 2533 * RuntimeEntrypoints.deliverHardwareException for stack resize) 2534 * 2535 * @return false during the prolog of the first Java to C transition true 2536 * afterward 2537 */ 2538 public boolean hasNativeStackFrame() { 2539 return jniEnv != null && jniEnv.hasNativeStackFrame(); 2540 } 2541 2542 /* 2543 * Starting and ending threads 2544 */ 2545 2546 /** 2547 * Method to be executed when this thread starts running. Calls 2548 * java.lang.Thread.run but system threads can override directly. 2549 */ 2550 @Interruptible 2551 @Entrypoint 2552 public void run() { 2553 try { 2554 synchronized (thread) { 2555 Throwable t = java.lang.JikesRVMSupport.getStillBorn(thread); 2556 if (t != null) { 2557 java.lang.JikesRVMSupport.setStillBorn(thread, null); 2558 throw t; 2559 } 2560 } 2561 thread.run(); 2562 } catch (Throwable t) { 2563 if (traceAcct) { 2564 VM.sysWriteln("Thread ",getThreadSlot()," exiting with exception."); 2565 } 2566 try { 2567 Thread.UncaughtExceptionHandler handler; 2568 handler = thread.getUncaughtExceptionHandler(); 2569 handler.uncaughtException(thread, t); 2570 } catch (Throwable ignore) { 2571 } 2572 } 2573 } 2574 2575 /** 2576 * Begin execution of current thread by calling its "run" method. This method 2577 * is at the bottom of all created method's stacks. 2578 */ 2579 @Interruptible 2580 @SuppressWarnings({ "unused" }) 2581 // Called by back-door methods. 2582 private static void startoff() { 2583 bindIfRequested(); 2584 2585 sysCall.sysSetupHardwareTrapHandler(); 2586 2587 RVMThread currentThread = getCurrentThread(); 2588 2589 /* 2590 * get pthread_id from the operating system and store into RVMThread field 2591 */ 2592 currentThread.pthread_id = sysCall.sysGetThreadId(); 2593 currentThread.enableYieldpoints(); 2594 sysCall.sysStashVMThread(currentThread); 2595 if (traceAcct) { 2596 VM.sysWriteln("Thread #", currentThread.threadSlot, " with pthread id ", 2597 currentThread.pthread_id, " running!"); 2598 } 2599 2600 if (trace) { 2601 VM.sysWriteln("Thread.startoff(): about to call ", currentThread.toString(), ".run()"); 2602 } 2603 2604 try { 2605 if (currentThread.systemThread != null) { 2606 currentThread.systemThread.run(); 2607 } else { 2608 currentThread.run(); 2609 } 2610 } finally { 2611 if (trace) { 2612 VM.sysWriteln("Thread.startoff(): finished ", currentThread.toString(), ".run()"); 2613 } 2614 currentThread.terminate(); 2615 if (VM.VerifyAssertions) 2616 VM._assert(VM.NOT_REACHED); 2617 } 2618 } 2619 2620 /** 2621 * Start execution of 'this' by putting it on the appropriate queue of an 2622 * unspecified virtual processor. 2623 */ 2624 @Interruptible 2625 public void start() { 2626 // N.B.: cannot hit a yieldpoint between setting execStatus and starting the 2627 // thread!! 2628 setExecStatus(IN_JAVA); 2629 acctLock.lockNoHandshake(); 2630 numActiveThreads++; 2631 if (daemon) { 2632 numActiveDaemons++; 2633 } 2634 acctLock.unlock(); 2635 if (traceAcct) 2636 VM.sysWriteln("Thread #", threadSlot, " starting!"); 2637 sysCall.sysThreadCreate(Magic.objectAsAddress(this), 2638 contextRegisters.ip, contextRegisters.getInnermostFramePointer()); 2639 } 2640 2641 /** 2642 * Terminate execution of current thread by abandoning all references to it 2643 * and resuming execution in some other (ready) thread. 2644 */ 2645 @Interruptible 2646 public void terminate() { 2647 if (traceAcct) 2648 VM.sysWriteln("in terminate() for Thread #", threadSlot); 2649 if (VM.VerifyAssertions) 2650 VM._assert(getCurrentThread() == this); 2651 boolean terminateSystem = false; 2652 if (traceTermination) { 2653 VM.disableGC(); 2654 VM.sysWriteln("[ BEGIN Verbosely dumping stack at time of thread termination"); 2655 dumpStack(); 2656 VM.sysWriteln("END Verbosely dumping stack at time of creating thread termination ]"); 2657 VM.enableGC(); 2658 } 2659 2660 // allow java.lang.Thread.exit() to remove this thread from ThreadGroup 2661 java.lang.JikesRVMSupport.threadDied(thread); 2662 2663 TraceEngine.engine.removeFeedlet(feedlet); 2664 2665 if (VM.VerifyAssertions) { 2666 if (Lock.countLocksHeldByThread(getLockingId()) > 0) { 2667 VM.sysWriteln("Error, thread terminating holding a lock"); 2668 RVMThread.dumpVirtualMachine(); 2669 } 2670 } 2671 2672 if (traceAcct) 2673 VM.sysWriteln("doing accounting..."); 2674 acctLock.lockNoHandshake(); 2675 2676 // if the thread terminated because of an exception, remove 2677 // the mark from the exception register object, or else the 2678 // garbage collector will attempt to relocate its ip field. 2679 exceptionRegisters.inuse = false; 2680 2681 numActiveThreads -= 1; 2682 if (daemon) { 2683 numActiveDaemons -= 1; 2684 } 2685 if (traceAcct) 2686 VM.sysWriteln("active = ", numActiveThreads, ", daemons = ", 2687 numActiveDaemons); 2688 if ((numActiveDaemons == numActiveThreads) && (VM.mainThread != null) && VM.mainThread.launched) { 2689 // no non-daemon thread remains and the main thread was launched 2690 terminateSystem = true; 2691 } 2692 if (terminateSystem) { 2693 if (systemShuttingDown == false) { 2694 systemShuttingDown = true; 2695 } else { 2696 terminateSystem = false; 2697 } 2698 } 2699 if (traceTermination) { 2700 VM.sysWriteln("Thread.terminate: myThread.daemon = ", daemon); 2701 VM.sysWriteln(" RVMThread.numActiveThreads = ", 2702 RVMThread.numActiveThreads); 2703 VM.sysWriteln(" RVMThread.numActiveDaemons = ", 2704 RVMThread.numActiveDaemons); 2705 VM.sysWriteln(" terminateSystem = ", terminateSystem); 2706 } 2707 2708 acctLock.unlock(); 2709 2710 if (traceAcct) 2711 VM.sysWriteln("done with accounting."); 2712 2713 if (terminateSystem) { 2714 if (traceAcct) 2715 VM.sysWriteln("terminating system."); 2716 if (uncaughtExceptionCount > 0) 2717 /* Use System.exit so that any shutdown hooks are run. */{ 2718 if (VM.TraceExceptionDelivery) { 2719 VM.sysWriteln("Calling sysExit due to uncaught exception."); 2720 } 2721 callSystemExit(VM.EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION); 2722 } else if (thread instanceof MainThread) { 2723 MainThread mt = (MainThread) thread; 2724 if (!mt.launched) { 2725 /* 2726 * Use System.exit so that any shutdown hooks are run. It is possible 2727 * that shutdown hooks may be installed by static initializers which 2728 * were run by classes initialized before we attempted to run the main 2729 * thread. (As of this writing, 24 January 2005, the Classpath 2730 * libraries do not do such a thing, but there is no reason why we 2731 * should not support this.) This was discussed on 2732 * jikesrvm-researchers on 23 Jan 2005 and 24 Jan 2005. 2733 */ 2734 callSystemExit(VM.EXIT_STATUS_MAIN_THREAD_COULD_NOT_LAUNCH); 2735 } 2736 } 2737 /* Use System.exit so that any shutdown hooks are run. */ 2738 callSystemExit(0); 2739 if (VM.VerifyAssertions) 2740 VM._assert(VM.NOT_REACHED); 2741 } 2742 2743 if (traceAcct) 2744 VM.sysWriteln("making joinable..."); 2745 2746 // this works. we use synchronized because we cannot use the thread's 2747 // monitor(). see comment in join(). this is fine, because we're still 2748 // "running" from the standpoint of GC. 2749 synchronized (this) { 2750 isJoinable = true; 2751 notifyAll(); 2752 } 2753 if (traceAcct) 2754 VM.sysWriteln("Thread #", threadSlot, " is joinable."); 2755 2756 if (traceAcct) 2757 VM.sysWriteln("making joinable..."); 2758 2759 // Switch to uninterruptible portion of termination 2760 terminateUnpreemptible(); 2761 } 2762 2763 /** 2764 * Call System.exit() with the correct security status. 2765 * 2766 * @param exitStatus 2767 */ 2768 @Interruptible 2769 private void callSystemExit(final int exitStatus) { 2770 AccessController.doPrivileged(new PrivilegedAction<Object>() { 2771 @Override 2772 public Object run() { 2773 System.exit(exitStatus); 2774 return null; 2775 } 2776 }); 2777 } 2778 2779 /** 2780 * Unpreemptible portion of thread termination. Unpreemptible to avoid a dead 2781 * thread from being scheduled. 2782 */ 2783 @Unpreemptible 2784 private void terminateUnpreemptible() { 2785 // return cached free lock 2786 if (traceAcct) 2787 VM.sysWriteln("returning cached lock..."); 2788 2789 if (cachedFreeLock != null) { 2790 if (Lock.trace) { 2791 VM.sysWriteln("Thread #", threadSlot, ": about to free lock ", 2792 Magic.objectAsAddress(cachedFreeLock)); 2793 } 2794 if (VM.VerifyAssertions) 2795 VM._assert(cachedFreeLock.mutex.latestContender != this); 2796 Lock.returnLock(cachedFreeLock); 2797 cachedFreeLock = null; 2798 } 2799 2800 if (traceAcct) 2801 VM.sysWriteln("adding to aboutToTerminate..."); 2802 2803 addAboutToTerminate(); 2804 // NB we can no longer do anything that would lead to write barriers or 2805 // GC 2806 2807 if (traceAcct) { 2808 VM.sysWriteln("acquireCount for my monitor: ", monitor().acquireCount); 2809 VM.sysWriteln("timer ticks: ", timerTicks); 2810 VM.sysWriteln("yieldpoints taken: ", yieldpointsTaken); 2811 VM.sysWriteln("yieldpoints taken fully: ", yieldpointsTakenFully); 2812 } 2813 if (traceAcct) 2814 VM.sysWriteln("finishing thread termination..."); 2815 2816 finishThreadTermination(); 2817 } 2818 2819 /** Uninterruptible final portion of thread termination. */ 2820 void finishThreadTermination() { 2821 sysCall.sysThreadTerminate(); 2822 if (VM.VerifyAssertions) 2823 VM._assert(VM.NOT_REACHED); 2824 } 2825 2826 /* 2827 * Support for yieldpoints 2828 */ 2829 2830 /** 2831 * Yieldpoint taken in prologue. 2832 */ 2833 @BaselineSaveLSRegisters 2834 // Save all non-volatile registers in prologue 2835 @NoOptCompile 2836 @NoInline 2837 // We should also have a pragma that saves all non-volatiles in opt compiler, 2838 // BaselineExecuctionStateExtractor.java, should then restore all 2839 // non-volatiles before stack replacement 2840 // TODO fix this -- related to SaveVolatile 2841 @Entrypoint 2842 @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process") 2843 public static void yieldpointFromPrologue() { 2844 Address fp = Magic.getFramePointer(); 2845 yieldpoint(PROLOGUE, fp); 2846 } 2847 2848 /** 2849 * Yieldpoint taken on backedge. 2850 */ 2851 @BaselineSaveLSRegisters 2852 // Save all non-volatile registers in prologue 2853 @NoOptCompile 2854 @NoInline 2855 // We should also have a pragma that saves all non-volatiles in opt compiler, 2856 // BaselineExecuctionStateExtractor.java, should then restore all 2857 // non-volatiles before stack replacement 2858 // TODO fix this -- related to SaveVolatile 2859 @Entrypoint 2860 @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process") 2861 public static void yieldpointFromBackedge() { 2862 Address fp = Magic.getFramePointer(); 2863 yieldpoint(BACKEDGE, fp); 2864 } 2865 2866 /** 2867 * The return barrier. 2868 * <p> 2869 * The following code implements return barriers as described 2870 * for Lisp by Yuasa 2871 * 2872 * http://www.yuasa.kuis.kyoto-u.ac.jp/~yuasa/ilc2002/index.html 2873 * http://dx.doi.org/10.1109/ISORC.2005.45 2874 * 2875 * and for Jikes RVM by Kumar et al 2876 * 2877 * http://dx.doi.org/10.1145/2398857.2384639 2878 * <p> 2879 * This code is executed when a method returns into a frame that 2880 * has been hijacked by the return barrier mechanism. The return 2881 * barrier trampoline will save state, execute this method, and 2882 * then upon return from this method will transparently return into 2883 * the frame that had been hijacked. 2884 * <p> 2885 * In this default implementation, the barrier reinstalls itself 2886 * in the caller's frame thus incrementally moving the barrier down 2887 * the stack. 2888 * <p> 2889 * The execution of this method is fragile. It is generally safest 2890 * to call some other method from here that does the substantive work 2891 * of the barrier. 2892 */ 2893 @Entrypoint 2894 @Uninterruptible 2895 @Unpreemptible 2896 public static void returnBarrier() { 2897 /* reinstall the barrier in the caller's frame */ 2898 if (DEBUG_STACK_TRAMPOLINE) { 2899 VM.sysWriteln(getCurrentThread().getId(), " T0: ", getCurrentThread().trampolineRegisters.gprs.get(BaselineConstants.T0_int).toAddress()); 2900 VM.sysWriteln(getCurrentThread().getId(), " T1: ", getCurrentThread().trampolineRegisters.gprs.get(BaselineConstants.T1_int).toAddress()); 2901 VM.sysWriteln(getCurrentThread().getId(), " nf: ", getCurrentThread().hijackedReturnCallerFp); 2902 VM.sysWriteln(getCurrentThread().getId(), " lf: ", getCurrentThread().hijackedReturnCalleeFp); 2903 VM.sysWriteln(getCurrentThread().getId(), " fp: ", Magic.getFramePointer()); 2904 VM.sysWriteln(getCurrentThread().getId(), " np: ", Magic.getCallerFramePointer(Magic.getFramePointer())); 2905 } 2906 /* reinstall the barrier in the specified frame */ 2907 getCurrentThread().installStackTrampolineBridge(getCurrentThread().hijackedReturnCallerFp); 2908 } 2909 2910 /** 2911 * Install the stack trampoline bridge at a given frame, hijacking 2912 * that frame, saving the hijacked return address and callee fp 2913 * in thread-local state to allow execution of the hijacked frame 2914 * later. 2915 * 2916 * @param targetFp The frame to be hijacked. 2917 */ 2918 @Uninterruptible 2919 public void installStackTrampolineBridge(Address targetFp) { 2920 Address trampoline = getStackTrampolineBridgeIP(); 2921 if (trampoline.isZero()) { 2922 if (VM.VerifyAssertions) 2923 VM._assert(VM.NOT_REACHED); 2924 else 2925 VM.sysWriteln("Warning: attempt to install stack trampoline without bridge instructions - nothing done. See RVMThread."); 2926 } else if (trampoline.NE(Magic.getReturnAddressUnchecked(targetFp))) { 2927 /* install the trampoline at fp or the next suitable frame after fp */ 2928 while (true) { 2929 if (Magic.getCallerFramePointer(targetFp).EQ(ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP)) { 2930 /* if we're at the bottom of the stack, then do not install anything */ 2931 hijackedReturnAddress = Address.zero(); 2932 hijackedReturnCalleeFp = Address.zero(); 2933 return; 2934 } 2935 int cmid = Magic.getCompiledMethodID(targetFp); 2936 if (cmid == ArchitectureSpecific.ArchConstants.INVISIBLE_METHOD_ID) { 2937 /* skip invisible methods */ 2938 targetFp = Magic.getCallerFramePointer(targetFp); 2939 } else { 2940 CompiledMethod calleeCM = CompiledMethods.getCompiledMethod(cmid); 2941 if (calleeCM.getCompilerType() == CompiledMethod.TRAP || 2942 calleeCM.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { 2943 /* skip traps and native bridges */ 2944 targetFp = Magic.getCallerFramePointer(targetFp); 2945 } else 2946 break; 2947 } 2948 } 2949 hijackedReturnAddress = Magic.getReturnAddressUnchecked(targetFp); 2950 hijackedReturnCalleeFp = targetFp; 2951 hijackedReturnCallerFp = Magic.getCallerFramePointer(targetFp); 2952 if (VM.VerifyAssertions) VM._assert(trampoline.NE(hijackedReturnAddress)); 2953 if (DEBUG_STACK_TRAMPOLINE) dumpFrame(targetFp); 2954 Magic.setReturnAddress(targetFp, trampoline); 2955 if (DEBUG_STACK_TRAMPOLINE) { 2956 dumpFrame(targetFp); 2957 VM.sysWriteln(getId(), " Installing trampoline at: ", targetFp); 2958 VM.sysWriteln(getId(), " Trampoline: ", trampoline); 2959 VM.sysWriteln(getId(), " Hijacked return address: ", hijackedReturnAddress); 2960 VM.sysWriteln(getId(), " Callee fp: ", hijackedReturnCalleeFp); 2961 VM.sysWriteln(getId(), " Caller fp: ", hijackedReturnCallerFp); 2962 dumpStack(hijackedReturnCalleeFp); 2963 } 2964 } 2965 } 2966 2967 /** 2968 * de-install the stack trampoline (disabling return barriers). 2969 */ 2970 @Uninterruptible 2971 public void deInstallStackTrampoline() { 2972 if (DEBUG_STACK_TRAMPOLINE) VM.sysWriteln("deinstalling trampoline: ", framePointer); 2973 if (!hijackedReturnCalleeFp.isZero()) { 2974 if (DEBUG_STACK_TRAMPOLINE) VM.sysWriteln("need to reinstall: ", hijackedReturnAddress); 2975 hijackedReturnCalleeFp.plus(STACKFRAME_RETURN_ADDRESS_OFFSET).store(hijackedReturnAddress); 2976 hijackedReturnCalleeFp = Address.zero(); 2977 hijackedReturnCallerFp = ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP; 2978 } 2979 } 2980 2981 /** @return the address of the stack trampoline bridge code */ 2982 @Inline 2983 private Address getStackTrampolineBridgeIP() { return Magic.objectAsAddress(stackTrampolineBridgeInstructions); } 2984 2985 /** @return the hijacked return address */ 2986 @Inline 2987 public Address getTrampolineHijackedReturnAddress() { return hijackedReturnAddress; } 2988 2989 /** 2990 * Determine whether a given method is the stack trampoline 2991 * 2992 * @param ip the code to be checked 2993 * @return <code>true</code> if the code is the stack trampoline. 2994 */ 2995 @Inline 2996 public static boolean isTrampolineIP(Address ip) { return getCurrentThread().getStackTrampolineBridgeIP().EQ(ip); } 2997 2998 /** 2999 * Given a frame that has been hijacked by the stack trampoline, 3000 * return the real (hijacked) return address. 3001 * 3002 * @param hijackedFp a frame that has been hijacked by the stack trampoline 3003 * @return the return address for the frame that was hijacked. 3004 */ 3005 @Uninterruptible 3006 public static Address getHijackedReturnAddress(Address hijackedFp) { 3007 if (VM.VerifyAssertions) VM._assert(isTrampolineIP(Magic.getReturnAddressUnchecked(hijackedFp))); 3008 RVMThread t = getCurrentThread(); 3009 if (!t.hijackedReturnCalleeFp.EQ(hijackedFp)) { 3010 for (int tid = 0; tid < nextSlot; tid++) { 3011 t = threadBySlot[tid]; 3012 if (t != null && t.hijackedReturnCalleeFp.EQ(hijackedFp)) 3013 break; 3014 } 3015 } 3016 return t.hijackedReturnAddress; 3017 } 3018 3019 /** 3020 * Dump the specified frame in a format useful for debugging the stack 3021 * trampoline 3022 * 3023 * @param fp The frame to be dumped. 3024 */ 3025 private static void dumpFrame(Address fp) { 3026 Address sp = fp.minus(40); 3027 VM.sysWriteln("--"); 3028 Address nextFp = Magic.getCallerFramePointer(fp); 3029 while (sp.LE(nextFp)) { 3030 VM.sysWrite("["); VM.sysWrite(sp); VM.sysWrite("]"); 3031 if (sp.EQ(fp) || sp.EQ(nextFp)) VM.sysWrite("* "); 3032 else if (sp.EQ(fp.plus(STACKFRAME_RETURN_ADDRESS_OFFSET)) || sp.EQ(nextFp.plus(STACKFRAME_RETURN_ADDRESS_OFFSET))) VM.sysWrite("R "); 3033 else if (sp.EQ(fp.plus(STACKFRAME_METHOD_ID_OFFSET)) || sp.EQ(nextFp.plus(STACKFRAME_METHOD_ID_OFFSET))) VM.sysWrite("M "); 3034 else VM.sysWrite(" "); 3035 VM.sysWriteln(sp.loadInt()); 3036 sp = sp.plus(4); 3037 } 3038 } 3039 3040 /** 3041 * @return the caller of the frame in which the trampoline is installed (STACKFRAME_SENTINEL_FP by default) 3042 */ 3043 public Address getNextUnencounteredFrame() { 3044 return hijackedReturnCallerFp.EQ(ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP) ? hijackedReturnCallerFp : Magic.getCallerFramePointer(hijackedReturnCallerFp); 3045 } 3046 3047 /** 3048 * Yieldpoint taken in epilogue. 3049 */ 3050 @BaselineSaveLSRegisters 3051 // Save all non-volatile registers in prologue 3052 @NoOptCompile 3053 @NoInline 3054 // We should also have a pragma that saves all non-volatiles in opt compiler, 3055 // BaselineExecutionStateExtractor.java, should then restore all non-volatiles 3056 // before stack replacement 3057 // TODO fix this -- related to SaveVolatile 3058 @Entrypoint 3059 @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process") 3060 public static void yieldpointFromEpilogue() { 3061 Address fp = Magic.getFramePointer(); 3062 yieldpoint(EPILOGUE, fp); 3063 } 3064 3065 /* 3066 * Support for suspend/resume 3067 */ 3068 3069 /** 3070 * Suspend execution of current thread until it is resumed. Call only if 3071 * caller has appropriate security clearance. 3072 */ 3073 @UnpreemptibleNoWarn("Exceptions may possibly cause yields") 3074 public void suspend() { 3075 if (false) VM.sysWriteln("Thread #",getCurrentThreadSlot()," suspending Thread #",getThreadSlot()); 3076 ObjectModel.genericUnlock(thread); 3077 Throwable rethrow = null; 3078 try { 3079 observeExecStatus(); 3080 if (execStatus != IN_JAVA && execStatus != IN_JAVA_TO_BLOCK && 3081 execStatus != IN_NATIVE && execStatus != BLOCKED_IN_NATIVE && 3082 execStatus != BLOCKED_IN_JNI && execStatus != IN_JNI) { 3083 throw new IllegalThreadStateException( 3084 "Cannot suspend a thread that is not running."); 3085 } 3086 block(suspendBlockAdapter); 3087 } catch (Throwable t) { 3088 rethrow = t; 3089 } 3090 ObjectModel.genericLock(thread); 3091 if (rethrow != null) 3092 RuntimeEntrypoints.athrow(rethrow); 3093 } 3094 3095 /** 3096 * Resume execution of a thread that has been suspended. Call only if caller 3097 * has appropriate security clearance. 3098 */ 3099 @Interruptible 3100 public void resume() { 3101 unblock(suspendBlockAdapter); 3102 } 3103 3104 public static void yieldNoHandshake() { 3105 sysCall.sysThreadYield(); 3106 } 3107 3108 @UnpreemptibleNoWarn 3109 public static void yieldWithHandshake() { 3110 getCurrentThread().checkBlock(); 3111 sysCall.sysThreadYield(); 3112 } 3113 /** 3114 * Suspend execution of current thread for specified number of seconds (or 3115 * fraction). 3116 */ 3117 @Interruptible 3118 public static void sleep(long ns) throws InterruptedException { 3119 RVMThread t = getCurrentThread(); 3120 t.waiting = Waiting.TIMED_WAITING; 3121 long atStart = sysCall.sysNanoTime(); 3122 long whenEnd = atStart + ns; 3123 t.monitor().lockNoHandshake(); 3124 while (!t.hasInterrupt && t.asyncThrowable == null && 3125 sysCall.sysNanoTime() < whenEnd) { 3126 t.monitor().timedWaitAbsoluteWithHandshake(whenEnd); 3127 } 3128 boolean throwInterrupt = false; 3129 Throwable throwThis = null; 3130 if (t.hasInterrupt) { 3131 t.hasInterrupt = false; 3132 throwInterrupt = true; 3133 } 3134 if (t.asyncThrowable != null) { 3135 throwThis = t.asyncThrowable; 3136 t.asyncThrowable = null; 3137 } 3138 t.monitor().unlock(); 3139 t.waiting = Waiting.RUNNABLE; 3140 if (throwThis != null) { 3141 RuntimeEntrypoints.athrow(throwThis); 3142 } 3143 if (throwInterrupt) { 3144 throw new InterruptedException("sleep interrupted"); 3145 } 3146 } 3147 3148 /** 3149 * Suspend execution of current thread for specified number of seconds (or 3150 * fraction). 3151 */ 3152 @Interruptible 3153 public static void sleep(long millis, int ns) throws InterruptedException { 3154 sleep(ns + millis * 1000L * 1000L); 3155 } 3156 3157 /* 3158 * Wait and notify support 3159 */ 3160 3161 @Interruptible 3162 void waitImpl(Object o, boolean hasTimeout, long whenWakeupNanos) { 3163 boolean throwInterrupt = false; 3164 Throwable throwThis = null; 3165 if (asyncThrowable != null) { 3166 throwThis = asyncThrowable; 3167 asyncThrowable = null; 3168 } else if (!ObjectModel.holdsLock(o, this)) { 3169 throw new IllegalMonitorStateException("waiting on " + o); 3170 } else if (hasInterrupt) { 3171 throwInterrupt = true; 3172 hasInterrupt = false; 3173 } else { 3174 waiting = hasTimeout ? Waiting.TIMED_WAITING : Waiting.WAITING; 3175 // get lock for object 3176 Lock l = ObjectModel.getHeavyLock(o, true); 3177 3178 // release the lock 3179 l.mutex.lock(); 3180 // this thread is supposed to own the lock on o 3181 if (VM.VerifyAssertions) VM._assert(l.getOwnerId() == getLockingId()); 3182 RVMThread toAwaken = l.entering.dequeue(); 3183 waitObject = l.getLockedObject(); 3184 waitCount = l.getRecursionCount(); 3185 l.setOwnerId(0); 3186 l.waiting.enqueue(this); 3187 l.mutex.unlock(); 3188 3189 // if there was a thread waiting, awaken it 3190 if (toAwaken != null) { 3191 // is this where the problem is coming from? 3192 toAwaken.monitor().lockedBroadcastNoHandshake(); 3193 } 3194 // block 3195 monitor().lockNoHandshake(); 3196 while (l.waiting.isQueued(this) && !hasInterrupt && asyncThrowable == null && 3197 (!hasTimeout || sysCall.sysNanoTime() < whenWakeupNanos)) { 3198 if (hasTimeout) { 3199 monitor().timedWaitAbsoluteWithHandshake(whenWakeupNanos); 3200 } else { 3201 monitor().waitWithHandshake(); 3202 } 3203 } 3204 // figure out if anything special happened while we were blocked 3205 if (hasInterrupt) { 3206 throwInterrupt = true; 3207 hasInterrupt = false; 3208 } 3209 if (asyncThrowable != null) { 3210 throwThis = asyncThrowable; 3211 asyncThrowable = null; 3212 } 3213 monitor().unlock(); 3214 if (l.waiting.isQueued(this)) { 3215 l.mutex.lock(); 3216 l.waiting.remove(this); /* 3217 * in case we got here due to an interrupt or a 3218 * stop() rather than a notify 3219 */ 3220 l.mutex.unlock(); 3221 // Note that the above must be done before attempting to acquire 3222 // the lock, since acquiring the lock may require queueing the thread. 3223 // But we cannot queue the thread if it is already on another 3224 // queue. 3225 } 3226 // reacquire the lock, restoring the recursion count 3227 ObjectModel.genericLock(o); 3228 waitObject = null; 3229 if (waitCount != 1) { // reset recursion count 3230 Lock l2 = ObjectModel.getHeavyLock(o, true); 3231 l2.setRecursionCount(waitCount); 3232 } 3233 waiting = Waiting.RUNNABLE; 3234 } 3235 // check if we should exit in a special way 3236 if (throwThis != null) { 3237 RuntimeEntrypoints.athrow(throwThis); 3238 } 3239 if (throwInterrupt) { 3240 RuntimeEntrypoints.athrow(new InterruptedException("sleep interrupted")); 3241 } 3242 } 3243 3244 /** 3245 * Support for Java {@link java.lang.Object#wait()} synchronization primitive. 3246 * 3247 * @param o 3248 * the object synchronized on 3249 */ 3250 @Interruptible 3251 /* only loses control at expected points -- I think -dave */ 3252 public static void wait(Object o) { 3253 getCurrentThread().waitImpl(o, false, 0); 3254 } 3255 3256 /** 3257 * Support for Java {@link java.lang.Object#wait()} synchronization primitive. 3258 * 3259 * @param o 3260 * the object synchronized on 3261 * @param millis 3262 * the number of milliseconds to wait for notification 3263 */ 3264 @Interruptible 3265 public static void wait(Object o, long millis) { 3266 long currentNanos = sysCall.sysNanoTime(); 3267 getCurrentThread().waitImpl(o, true, currentNanos + millis * 1000 * 1000); 3268 } 3269 3270 /** 3271 * Support for RTSJ- and pthread-style absolute wait. 3272 * 3273 * @param o 3274 * the object synchronized on 3275 * @param whenNanos 3276 * the absolute time in nanoseconds when we should wake up 3277 */ 3278 @Interruptible 3279 public static void waitAbsoluteNanos(Object o, long whenNanos) { 3280 getCurrentThread().waitImpl(o, true, whenNanos); 3281 } 3282 3283 @UnpreemptibleNoWarn("Possible context when generating exception") 3284 public static void raiseIllegalMonitorStateException(String msg, Object o) { 3285 throw new IllegalMonitorStateException(msg + (o == null ? "<null>" : o.toString())); 3286 } 3287 3288 /** 3289 * Support for Java {@link java.lang.Object#notify()} synchronization 3290 * primitive. 3291 * 3292 * @param o the object synchronized on 3293 */ 3294 @Interruptible 3295 public static void notify(Object o) { 3296 if (STATS) 3297 notifyOperations++; 3298 Lock l = ObjectModel.getHeavyLock(o, false); 3299 if (l == null) 3300 return; 3301 // the reason for locking: when inflating a lock we *first* install it in the status 3302 // word and *then* initialize its state. but fortunately, we do so while holding 3303 // the lock's mutex. thus acquiring the lock's mutex is the only way to ensure that 3304 // we see the lock's state after initialization. 3305 l.mutex.lock(); 3306 int owner=l.getOwnerId(); 3307 l.mutex.unlock(); 3308 int me=getCurrentThread().getLockingId(); 3309 if (owner != me) { 3310 raiseIllegalMonitorStateException("notifying (expected lock to be held by "+me+"("+getCurrentThread().getLockingId()+") but was held by "+owner+"("+l.getOwnerId()+")) ", o); 3311 } 3312 l.mutex.lock(); 3313 RVMThread toAwaken = l.waiting.dequeue(); 3314 l.mutex.unlock(); 3315 if (toAwaken != null) { 3316 toAwaken.monitor().lockedBroadcastNoHandshake(); 3317 } 3318 } 3319 3320 /** 3321 * Support for Java synchronization primitive. 3322 * 3323 * @param o the object synchronized on 3324 * @see java.lang.Object#notifyAll 3325 */ 3326 @Interruptible 3327 public static void notifyAll(Object o) { 3328 if (STATS) 3329 notifyAllOperations++; 3330 Lock l = ObjectModel.getHeavyLock(o, false); 3331 if (l == null) 3332 return; 3333 l.mutex.lock(); 3334 int owner=l.getOwnerId(); 3335 l.mutex.unlock(); 3336 if (owner != getCurrentThread().getLockingId()) { 3337 raiseIllegalMonitorStateException("notifying all (expected lock to be held by "+getCurrentThread().getLockingId()+" but was held by "+l.getOwnerId()+") ", o); 3338 } 3339 for (;;) { 3340 l.mutex.lock(); 3341 RVMThread toAwaken = l.waiting.dequeue(); 3342 l.mutex.unlock(); 3343 if (toAwaken == null) 3344 break; 3345 toAwaken.monitor().lockedBroadcastNoHandshake(); 3346 } 3347 } 3348 3349 public void stop(Throwable cause) { 3350 monitor().lockNoHandshake(); 3351 asyncThrowable = cause; 3352 takeYieldpoint = 1; 3353 monitor().broadcast(); 3354 monitor().unlock(); 3355 } 3356 3357 /* 3358 * Park and unpark support 3359 */ 3360 @Interruptible 3361 public void park(boolean isAbsolute, long time) throws Throwable { 3362 if (parkingPermit) { 3363 // fast path 3364 parkingPermit = false; 3365 Magic.sync(); 3366 return; 3367 } 3368 // massive retardation. someone might be holding the java.lang.Thread lock. 3369 boolean holdsLock = holdsLock(thread); 3370 if (holdsLock) 3371 ObjectModel.genericUnlock(thread); 3372 boolean hasTimeout; 3373 long whenWakeupNanos; 3374 hasTimeout = (time != 0); 3375 if (isAbsolute) { 3376 whenWakeupNanos = time; 3377 } else { 3378 whenWakeupNanos = sysCall.sysNanoTime() + time; 3379 } 3380 Throwable throwThis = null; 3381 monitor().lockNoHandshake(); 3382 waiting = hasTimeout ? Waiting.TIMED_WAITING : Waiting.WAITING; 3383 while (!parkingPermit && !hasInterrupt && asyncThrowable == null && 3384 (!hasTimeout || sysCall.sysNanoTime() < whenWakeupNanos)) { 3385 if (hasTimeout) { 3386 monitor().timedWaitAbsoluteWithHandshake(whenWakeupNanos); 3387 } else { 3388 monitor().waitWithHandshake(); 3389 } 3390 } 3391 waiting = Waiting.RUNNABLE; 3392 parkingPermit = false; 3393 if (asyncThrowable != null) { 3394 throwThis = asyncThrowable; 3395 asyncThrowable = null; 3396 } 3397 monitor().unlock(); 3398 3399 if (holdsLock) 3400 ObjectModel.genericLock(thread); 3401 3402 if (throwThis != null) { 3403 throw throwThis; 3404 } 3405 } 3406 3407 @Interruptible 3408 public void unpark() { 3409 monitor().lockNoHandshake(); 3410 parkingPermit = true; 3411 monitor().broadcast(); 3412 monitor().unlock(); 3413 } 3414 3415 /** 3416 * Get this thread's id for use in lock ownership tests. This is just the 3417 * thread's slot as returned by {@link #getThreadSlot()}, shifted appropriately 3418 * so it can be directly used in the ownership tests. 3419 */ 3420 public int getLockingId() { 3421 return lockingId; 3422 } 3423 3424 @Uninterruptible 3425 public static class SoftHandshakeVisitor { 3426 /** 3427 * Set whatever flags need to be set to signal that the given thread should 3428 * perform some action when it acknowledges the soft handshake. If not 3429 * interested in this thread, return false; otherwise return true. Returning 3430 * true will cause a soft handshake request to be put through. 3431 * <p> 3432 * This method is called with the thread's monitor() held, but while the 3433 * thread may still be running. This method is not called on mutators that 3434 * have indicated that they are about to terminate. 3435 */ 3436 public boolean checkAndSignal(RVMThread t) { 3437 return true; 3438 } 3439 3440 /** 3441 * Called when it is determined that the thread is stuck in native. While 3442 * this method is being called, the thread cannot return to running Java 3443 * code. As such, it is safe to perform actions "on the thread's behalf". 3444 */ 3445 public void notifyStuckInNative(RVMThread t) { 3446 } 3447 3448 /** 3449 * Check whether to include the specified thread in the soft handshake. 3450 * 3451 * @param t The thread to check for inclusion 3452 * @return True if the thread should be included. 3453 */ 3454 public boolean includeThread(RVMThread t) { 3455 return true; 3456 } 3457 } 3458 3459 @NoCheckStore 3460 public static int snapshotHandshakeThreads(SoftHandshakeVisitor v) { 3461 // figure out which threads to consider 3462 acctLock.lockNoHandshake(); /* get a consistent view of which threads are live. */ 3463 3464 int numToHandshake = 0; 3465 for (int i = 0; i < numThreads; ++i) { 3466 RVMThread t = threads[i]; 3467 if (t != RVMThread.getCurrentThread() && !t.ignoreHandshakesAndGC() && v.includeThread(t)) { 3468 handshakeThreads[numToHandshake++] = t; 3469 } 3470 } 3471 acctLock.unlock(); 3472 return numToHandshake; 3473 } 3474 3475 /** 3476 * Tell each thread to take a yieldpoint and wait until all of them have done 3477 * so at least once. Additionally, call the visitor on each thread when making 3478 * the yieldpoint request; the purpose of the visitor is to set any additional 3479 * fields as needed to make specific requests to the threads that yield. Note 3480 * that the visitor's <code>visit()</code> method is called with both the 3481 * thread's monitor held, and the <code>softHandshakeDataLock</code> held. 3482 * <p> 3483 * Currently we only use this mechanism for code patch isync requests on PPC, 3484 * but this mechanism is powerful enough to be used by sliding-views style 3485 * concurrent GC. 3486 */ 3487 @NoCheckStore 3488 @Unpreemptible("Does not perform actions that lead to blocking, but may wait for threads to rendezvous with the soft handshake") 3489 public static void softHandshake(SoftHandshakeVisitor v) { 3490 handshakeLock.lockWithHandshake(); /* 3491 * prevent multiple (soft or hard) handshakes 3492 * from proceeding concurrently 3493 */ 3494 3495 int numToHandshake = snapshotHandshakeThreads(v); 3496 if (VM.VerifyAssertions) 3497 VM._assert(softHandshakeLeft == 0); 3498 3499 // in turn, check if each thread needs a handshake, and if so, 3500 // request one 3501 for (int i = 0; i < numToHandshake; ++i) { 3502 RVMThread t = handshakeThreads[i]; 3503 handshakeThreads[i] = null; // help GC 3504 t.monitor().lockNoHandshake(); 3505 boolean waitForThisThread = false; 3506 if (!t.isAboutToTerminate && v.checkAndSignal(t)) { 3507 // CAS the execStatus field 3508 t.setBlockedExecStatus(); 3509 // Note that at this point if the thread tries to either enter or 3510 // exit Java code, it will be diverted into either 3511 // enterNativeBlocked() or checkBlock(), both of which cannot do 3512 // anything until they acquire the monitor() lock, which we now 3513 // hold. Thus, the code below can, at its leisure, examine the 3514 // thread's state and make its decision about what to do, fully 3515 // confident that the thread's state is blocked from changing. 3516 if (t.isInJava()) { 3517 // the thread is currently executing Java code, so we must ensure 3518 // that it either: 3519 // 1) takes the next yieldpoint and rendezvous with this soft 3520 // handshake request (see yieldpoint), or 3521 // 2) performs the rendezvous when leaving Java code 3522 // (see enterNativeBlocked, checkBlock, and addAboutToTerminate) 3523 // either way, we will wait for it to get there before exiting 3524 // this call, since the caller expects that after softHandshake() 3525 // returns, no thread will be running Java code without having 3526 // acknowledged. 3527 t.softHandshakeRequested = true; 3528 t.takeYieldpoint = 1; 3529 waitForThisThread = true; 3530 } else { 3531 // the thread is not in Java code (it may be blocked or it may be 3532 // in native), so we don't have to wait for it since it will 3533 // do the Right Thing before returning to Java code. essentially, 3534 // the thread cannot go back to running Java without doing whatever 3535 // was requested because: 3536 // A) we've set the execStatus to blocked, and 3537 // B) we're holding its lock. 3538 v.notifyStuckInNative(t); 3539 } 3540 } 3541 t.monitor().unlock(); 3542 3543 // NOTE: at this point the thread may already decrement the 3544 // softHandshakeLeft counter, causing it to potentially go negative. 3545 // this is unlikely and completely harmless. 3546 3547 if (waitForThisThread) { 3548 softHandshakeDataLock.lockNoHandshake(); 3549 softHandshakeLeft++; 3550 softHandshakeDataLock.unlock(); 3551 } 3552 } 3553 3554 // wait for all threads to reach the handshake 3555 softHandshakeDataLock.lockNoHandshake(); 3556 if (VM.VerifyAssertions) 3557 VM._assert(softHandshakeLeft >= 0); 3558 while (softHandshakeLeft > 0) { 3559 // wait and tell the world that we're off in native land. this way 3560 // if someone tries to block us at this point (suspend() or GC), 3561 // they'll know not to wait for us. 3562 softHandshakeDataLock.waitWithHandshake(); 3563 } 3564 if (VM.VerifyAssertions) 3565 VM._assert(softHandshakeLeft == 0); 3566 softHandshakeDataLock.unlock(); 3567 3568 processAboutToTerminate(); 3569 3570 handshakeLock.unlock(); 3571 } 3572 3573 /** 3574 * Check and clear the need for a soft handshake rendezvous. This method 3575 * cannot do anything that leads to a write barrier or allocation. 3576 */ 3577 public boolean softRendezvousCheckAndClear() { 3578 boolean result = false; 3579 monitor().lockNoHandshake(); 3580 if (softHandshakeRequested) { 3581 softHandshakeRequested = false; 3582 result = true; 3583 } 3584 monitor().unlock(); 3585 return result; 3586 } 3587 3588 /** 3589 * Commit the soft handshake rendezvous. This method cannot do anything 3590 * that leads to a write barrier or allocation. 3591 */ 3592 public void softRendezvousCommit() { 3593 softHandshakeDataLock.lockNoHandshake(); 3594 softHandshakeLeft--; 3595 if (softHandshakeLeft == 0) { 3596 softHandshakeDataLock.broadcast(); 3597 } 3598 softHandshakeDataLock.unlock(); 3599 } 3600 3601 /** 3602 * Rendezvous with a soft handshake request. Can only be called when the 3603 * thread's monitor is held. 3604 */ 3605 public void softRendezvous() { 3606 if (softRendezvousCheckAndClear()) 3607 softRendezvousCommit(); 3608 } 3609 3610 /** 3611 * Handle requests that required a soft handshake. May be called after we 3612 * acknowledged the soft handshake. Thus - this is for actions in which it is 3613 * sufficient for the thread to acknowledge that it plans to act upon the 3614 * request in the immediate future, rather than that the thread acts upon the 3615 * request prior to acknowledging. 3616 * <p> 3617 * This is almost always called with the monitor() lock held, but that's 3618 * not guaranteed. If you need that lock, you can grab it (since it's a 3619 * recursive lock). But you should avoid grabbing other sorts of locks since 3620 * that might cause deadlock. 3621 */ 3622 void handleHandshakeRequest() { 3623 // Process request for code-patch memory sync operation 3624 if (VM.BuildForPowerPC && codePatchSyncRequested) { 3625 codePatchSyncRequested = false; 3626 // Q: Is this sufficient? Ask Steve why we don't need to sync 3627 // icache/dcache. --dave 3628 // A: Yes, this is sufficient. We (Filip and Dave) talked about it and 3629 // agree that remote processors only need to execute isync. --Filip 3630 // make sure not get stale data 3631 Magic.isync(); 3632 } 3633 // process memory management requests 3634 if (flushRequested && activeMutatorContext) { 3635 MemoryManager.flushMutatorContext(); 3636 flushRequested = false; 3637 } 3638 // not really a "soft handshake" request but we handle it here anyway 3639 if (asyncDebugRequestedForThisThread) { 3640 asyncDebugRequestedForThisThread = false; 3641 dumpLock.lockNoHandshake(); 3642 VM.sysWriteln("Handling async stack trace request..."); 3643 dump(); 3644 VM.sysWriteln(); 3645 dumpStack(); 3646 dumpLock.unlock(); 3647 } 3648 } 3649 3650 /** 3651 * Stop all mutator threads. This is current intended to be run by a single thread. 3652 * 3653 * Fixpoint until there are no threads that we haven't blocked. Fixpoint is needed to 3654 * catch the (unlikely) case that a thread spawns another thread while we are waiting. 3655 */ 3656 @NoCheckStore 3657 @Unpreemptible 3658 public static void blockAllMutatorsForGC() { 3659 RVMThread.handshakeLock.lockNoHandshake(); 3660 while (true) { 3661 // (1) Find all the threads that need to be blocked for GC 3662 RVMThread.acctLock.lockNoHandshake(); 3663 int numToHandshake = 0; 3664 for (int i = 0; i < RVMThread.numThreads; i++) { 3665 RVMThread t = RVMThread.threads[i]; 3666 if (!t.isCollectorThread() && !t.ignoreHandshakesAndGC()) { 3667 RVMThread.handshakeThreads[numToHandshake++] = t; 3668 } 3669 } 3670 RVMThread.acctLock.unlock(); 3671 3672 // (2) Remove any threads that have already been blocked from the list. 3673 for (int i = 0; i < numToHandshake; i++) { 3674 RVMThread t = RVMThread.handshakeThreads[i]; 3675 t.monitor().lockNoHandshake(); 3676 if (t.blockedFor(RVMThread.gcBlockAdapter) || RVMThread.notRunning(t.asyncBlock(RVMThread.gcBlockAdapter))) { 3677 // Already blocked or not running, remove. 3678 RVMThread.handshakeThreads[i--] = RVMThread.handshakeThreads[--numToHandshake]; 3679 RVMThread.handshakeThreads[numToHandshake] = null; // help GC 3680 } 3681 t.monitor().unlock(); 3682 } 3683 3684 // (3) Quit trying to block threads if all threads are either blocked 3685 // or not running (a thread is "not running" if it is NEW or TERMINATED; 3686 // in the former case it means that the thread has not had start() 3687 // called on it while in the latter case it means that the thread 3688 // is either in the TERMINATED state or is about to be in that state 3689 // real soon now, and will not perform any heap-related work before 3690 // terminating). 3691 if (numToHandshake == 0) break; 3692 3693 // (4) Request a block for GC from all other threads. 3694 for (int i = 0; i < numToHandshake; i++) { 3695 if (false) VM.sysWriteln("Waiting for ", RVMThread.handshakeThreads[i].getThreadSlot(), " to block."); 3696 RVMThread t = RVMThread.handshakeThreads[i]; 3697 RVMThread.observeExecStatusAtSTW(t.block(RVMThread.gcBlockAdapter)); 3698 RVMThread.handshakeThreads[i] = null; // help GC 3699 } 3700 } 3701 RVMThread.handshakeLock.unlock(); 3702 3703 // Deal with terminating threads to ensure that all threads are either dead to MMTk or stopped above. 3704 RVMThread.processAboutToTerminate(); 3705 } 3706 3707 /** 3708 * Unblock all mutators blocked for GC. 3709 */ 3710 @NoCheckStore 3711 @Unpreemptible 3712 public static void unblockAllMutatorsForGC() { 3713 RVMThread.handshakeLock.lockNoHandshake(); 3714 RVMThread.acctLock.lockNoHandshake(); 3715 int numToHandshake = 0; 3716 for (int i = 0; i < RVMThread.numThreads; i++) { 3717 RVMThread t = RVMThread.threads[i]; 3718 if (!t.isCollectorThread() && !t.ignoreHandshakesAndGC()) { 3719 RVMThread.handshakeThreads[numToHandshake++] = t; 3720 } 3721 } 3722 RVMThread.acctLock.unlock(); 3723 for (int i = 0; i < numToHandshake; i++) { 3724 RVMThread.handshakeThreads[i].unblock(RVMThread.gcBlockAdapter); 3725 RVMThread.handshakeThreads[i] = null; // Help GC 3726 } 3727 RVMThread.handshakeLock.unlock(); 3728 } 3729 3730 @Uninterruptible 3731 public static class HardHandshakeVisitor { 3732 public boolean includeThread(RVMThread t) { 3733 return true; 3734 } 3735 } 3736 3737 @Uninterruptible 3738 @NonMoving 3739 static class AllButGCHardHandshakeVisitor extends HardHandshakeVisitor { 3740 @Override 3741 public boolean includeThread(RVMThread t) { 3742 return !t.isCollectorThread(); 3743 } 3744 } 3745 3746 public static final AllButGCHardHandshakeVisitor allButGC= 3747 new AllButGCHardHandshakeVisitor(); 3748 3749 static long totalSuspendTime; 3750 static long totalResumeTime; 3751 3752 @Unpreemptible 3753 @NoCheckStore 3754 public static void hardHandshakeSuspend(BlockAdapter ba, 3755 HardHandshakeVisitor hhv) { 3756 long before=sysCall.sysNanoTime(); 3757 3758 RVMThread current=getCurrentThread(); 3759 3760 handshakeLock.lockWithHandshake(); 3761 int numLockedLocks=0; 3762 for (int i=0;i<nextSlot;++i) { 3763 Monitor l=communicationLockBySlot[i]; 3764 if (l!=null) { 3765 l.lockWithHandshake(); 3766 numLockedLocks++; 3767 } 3768 } 3769 3770 // fixpoint until there are no threads that we haven't blocked. 3771 // fixpoint is needed in case some thread spawns another thread 3772 // while we're waiting. that is unlikely but possible. 3773 for (;;) { 3774 acctLock.lockNoHandshake(); 3775 int numToHandshake=0; 3776 for (int i=0;i<numThreads;++i) { 3777 RVMThread t=threads[i]; 3778 if (t!=current && 3779 !t.ignoreHandshakesAndGC() && 3780 hhv.includeThread(t)) { 3781 handshakeThreads[numToHandshake++]=t; 3782 } 3783 } 3784 acctLock.unlock(); 3785 3786 for (int i=0;i<numToHandshake;++i) { 3787 RVMThread t=handshakeThreads[i]; 3788 t.monitor().lockNoHandshake(); 3789 if (t.blockedFor(ba) || 3790 notRunning(t.asyncBlock(ba))) { 3791 // already blocked or not running, remove 3792 handshakeThreads[i--]=handshakeThreads[--numToHandshake]; 3793 handshakeThreads[numToHandshake]=null; // help GC 3794 } 3795 t.monitor().unlock(); 3796 } 3797 // quit trying to block threads if all threads are either blocked 3798 // or not running (a thread is "not running" if it is NEW or TERMINATED; 3799 // in the former case it means that the thread has not had start() 3800 // called on it while in the latter case it means that the thread 3801 // is either in the TERMINATED state or is about to be in that state 3802 // real soon now, and will not perform any heap-related stuff before 3803 // terminating). 3804 if (numToHandshake==0) break; 3805 for (int i=0;i<numToHandshake;++i) { 3806 RVMThread t=handshakeThreads[i]; 3807 observeExecStatusAtSTW(t.block(ba)); 3808 handshakeThreads[i]=null; // help GC 3809 } 3810 } 3811 worldStopped=true; 3812 3813 processAboutToTerminate(); /* 3814 * ensure that any threads that died while 3815 * we were stopping the world notify us 3816 * that they had stopped. 3817 */ 3818 3819 int numUnlockedLocks=0; 3820 for (int i=0;i<nextSlot;++i) { 3821 Monitor l=communicationLockBySlot[i]; 3822 if (l!=null) { 3823 l.unlock(); 3824 numUnlockedLocks++; 3825 } 3826 } 3827 if (VM.VerifyAssertions) VM._assert(numLockedLocks==numUnlockedLocks); 3828 handshakeLock.unlock(); 3829 3830 if (false) { 3831 long after=sysCall.sysNanoTime(); 3832 totalSuspendTime+=after-before; 3833 VM.sysWriteln("Stopping the world took ",(after-before)," ns (",totalSuspendTime," ns total)"); 3834 } 3835 } 3836 3837 @NoCheckStore 3838 @Unpreemptible 3839 public static void hardHandshakeResume(BlockAdapter ba, 3840 HardHandshakeVisitor hhv) { 3841 long before=sysCall.sysNanoTime(); 3842 3843 handshakeLock.lockWithHandshake(); 3844 3845 RVMThread current=getCurrentThread(); 3846 worldStopped=false; 3847 acctLock.lockNoHandshake(); 3848 int numToHandshake=0; 3849 for (int i=0;i<numThreads;++i) { 3850 RVMThread t=threads[i]; 3851 if (t!=current && 3852 !t.ignoreHandshakesAndGC() && 3853 hhv.includeThread(t)) { 3854 handshakeThreads[numToHandshake++]=t; 3855 } 3856 } 3857 acctLock.unlock(); 3858 for (int i=0;i<numToHandshake;++i) { 3859 handshakeThreads[i].unblock(ba); 3860 handshakeThreads[i]=null; // help GC 3861 } 3862 3863 handshakeLock.unlock(); 3864 3865 if (false) { 3866 long after=sysCall.sysNanoTime(); 3867 totalResumeTime+=after-before; 3868 VM.sysWriteln("Resuming the world took ",(after-before)," ns (",totalResumeTime," ns total)"); 3869 } 3870 } 3871 3872 @Unpreemptible 3873 public static void hardHandshakeSuspend() { 3874 hardHandshakeSuspend(handshakeBlockAdapter,allButGC); 3875 } 3876 3877 @Unpreemptible 3878 public static void hardHandshakeResume() { 3879 hardHandshakeResume(handshakeBlockAdapter,allButGC); 3880 } 3881 3882 public static boolean worldStopped() { 3883 return worldStopped; 3884 } 3885 3886 /** 3887 * Process a taken yieldpoint. 3888 */ 3889 @Unpreemptible("May block if the thread was asked to do so but otherwise does not perform actions that may lead to blocking") 3890 public static void yieldpoint(int whereFrom, Address yieldpointServiceMethodFP) { 3891 RVMThread t = getCurrentThread(); 3892 boolean wasAtYieldpoint = t.atYieldpoint; 3893 t.atYieldpoint = true; 3894 t.yieldpointsTaken++; 3895 // If thread is in critical section we can't do anything right now, defer 3896 // until later 3897 // we do this without acquiring locks, since part of the point of disabling 3898 // yieldpoints is to ensure that locks are not "magically" acquired 3899 // through unexpected yieldpoints. As well, this makes code running with 3900 // yieldpoints disabled more predictable. Note furthermore that the only 3901 // race here is setting takeYieldpoint to 0. But this is perfectly safe, 3902 // since we are guaranteeing that a yieldpoint will run after we emerge from 3903 // the no-yieldpoints code. At worst, setting takeYieldpoint to 0 will be 3904 // lost (because some other thread sets it to non-0), but in that case we'll 3905 // just come back here and reset it to 0 again. 3906 if (!t.yieldpointsEnabled()) { 3907 if (VM.VerifyAssertions) 3908 VM._assert(!t.yieldToOSRRequested); 3909 if (traceBlock && !wasAtYieldpoint) { 3910 VM.sysWriteln("Thread #", t.threadSlot, " deferring yield!"); 3911 dumpStack(); 3912 } 3913 t.yieldpointRequestPending = true; 3914 t.takeYieldpoint = 0; 3915 t.atYieldpoint = false; 3916 return; 3917 } 3918 t.yieldpointsTakenFully++; 3919 3920 Throwable throwThis = null; 3921 t.monitor().lockNoHandshake(); 3922 3923 int takeYieldpointVal = t.takeYieldpoint; 3924 if (takeYieldpointVal != 0) { 3925 t.takeYieldpoint = 0; 3926 // do two things: check if we should be blocking, and act upon 3927 // handshake requests. This also has the effect of reasserting that 3928 // we are in fact IN_JAVA (as opposed to IN_JAVA_TO_BLOCK). 3929 t.checkBlock(); 3930 3931 // Process timer interrupt event 3932 if (t.timeSliceExpired != 0) { 3933 t.timeSliceExpired = 0; 3934 3935 if (t.yieldForCBSCall || t.yieldForCBSMethod) { 3936 /* 3937 * CBS Sampling is still active from previous quantum. Note that fact, 3938 * but leave all the other CBS parameters alone. 3939 */ 3940 } else { 3941 if (VM.CBSCallSamplesPerTick > 0) { 3942 t.yieldForCBSCall = true; 3943 t.takeYieldpoint = -1; 3944 t.firstCBSCallSample++; 3945 t.firstCBSCallSample = t.firstCBSCallSample % VM.CBSCallSampleStride; 3946 t.countdownCBSCall = t.firstCBSCallSample; 3947 t.numCBSCallSamples = VM.CBSCallSamplesPerTick; 3948 } 3949 3950 if (VM.CBSMethodSamplesPerTick > 0) { 3951 t.yieldForCBSMethod = true; 3952 t.takeYieldpoint = -1; 3953 t.firstCBSMethodSample++; 3954 t.firstCBSMethodSample = t.firstCBSMethodSample % VM.CBSMethodSampleStride; 3955 t.countdownCBSMethod = t.firstCBSMethodSample; 3956 t.numCBSMethodSamples = VM.CBSMethodSamplesPerTick; 3957 } 3958 } 3959 3960 if (VM.BuildForAdaptiveSystem) { 3961 RuntimeMeasurements.takeTimerSample(whereFrom, 3962 yieldpointServiceMethodFP); 3963 } 3964 if (VM.BuildForAdaptiveSystem) { 3965 OSRListener 3966 .checkForOSRPromotion(whereFrom, yieldpointServiceMethodFP); 3967 } 3968 } 3969 3970 if (t.yieldForCBSCall) { 3971 if (!(whereFrom == BACKEDGE || whereFrom == OSROPT)) { 3972 if (--t.countdownCBSCall <= 0) { 3973 if (VM.BuildForAdaptiveSystem) { 3974 // take CBS sample 3975 RuntimeMeasurements.takeCBSCallSample(whereFrom, 3976 yieldpointServiceMethodFP); 3977 } 3978 t.countdownCBSCall = VM.CBSCallSampleStride; 3979 t.numCBSCallSamples--; 3980 if (t.numCBSCallSamples <= 0) { 3981 t.yieldForCBSCall = false; 3982 } 3983 } 3984 } 3985 if (t.yieldForCBSCall) { 3986 t.takeYieldpoint = -1; 3987 } 3988 } 3989 3990 if (t.yieldForCBSMethod) { 3991 if (--t.countdownCBSMethod <= 0) { 3992 if (VM.BuildForAdaptiveSystem) { 3993 // take CBS sample 3994 RuntimeMeasurements.takeCBSMethodSample(whereFrom, 3995 yieldpointServiceMethodFP); 3996 } 3997 t.countdownCBSMethod = VM.CBSMethodSampleStride; 3998 t.numCBSMethodSamples--; 3999 if (t.numCBSMethodSamples <= 0) { 4000 t.yieldForCBSMethod = false; 4001 } 4002 } 4003 if (t.yieldForCBSMethod) { 4004 t.takeYieldpoint = 1; 4005 } 4006 } 4007 4008 if (VM.BuildForAdaptiveSystem && t.yieldToOSRRequested) { 4009 t.yieldToOSRRequested = false; 4010 OSRListener.handleOSRFromOpt(yieldpointServiceMethodFP); 4011 } 4012 4013 // what is the reason for this? and what was the reason for doing 4014 // a thread switch following the suspension in the OSR trigger code? 4015 // ... it seems that at least part of the point here is that if a 4016 // thread switch was desired for other reasons, then we need to ensure 4017 // that between when this runs and when the glue code runs there will 4018 // be no interleaved GC; obviously if we did this before the thread 4019 // switch then there would be the possibility of interleaved GC. 4020 if (VM.BuildForAdaptiveSystem && t.isWaitingForOsr) { 4021 PostThreadSwitch.postProcess(t); 4022 } 4023 if (t.asyncThrowable != null) { 4024 throwThis = t.asyncThrowable; 4025 t.asyncThrowable = null; 4026 } 4027 } 4028 t.monitor().unlock(); 4029 t.atYieldpoint = false; 4030 if (throwThis != null) { 4031 throwFromUninterruptible(throwThis); 4032 } 4033 } 4034 4035 @Unpreemptible 4036 private static void throwFromUninterruptible(Throwable e) { 4037 RuntimeEntrypoints.athrow(e); 4038 } 4039 4040 /** 4041 * Change the size of the currently executing thread's stack. 4042 * 4043 * @param newSize 4044 * new size (in bytes) 4045 * @param exceptionRegisters 4046 * register state at which stack overflow trap was encountered (null 4047 * --> normal method call, not a trap) 4048 */ 4049 @Unpreemptible("May block due to allocation") 4050 public static void resizeCurrentStack(int newSize, 4051 Registers exceptionRegisters) { 4052 if (!getCurrentThread().hijackedReturnAddress.isZero()) { 4053 /* stack resizing currently unsupported with return barrier */ 4054 VM.sysFail("system error: resizing stack while return barrier enabled (currently unsupported)"); 4055 } 4056 if (traceAdjustments) 4057 VM.sysWrite("Thread: resizeCurrentStack\n"); 4058 if (MemoryManager.gcInProgress()) { 4059 VM.sysFail("system error: resizing stack while GC is in progress"); 4060 } 4061 byte[] newStack = MemoryManager.newStack(newSize); 4062 getCurrentThread().disableYieldpoints(); 4063 transferExecutionToNewStack(newStack, exceptionRegisters); 4064 getCurrentThread().enableYieldpoints(); 4065 if (traceAdjustments) { 4066 RVMThread t = getCurrentThread(); 4067 VM.sysWrite("Thread: resized stack ", t.getThreadSlot()); 4068 VM.sysWrite(" to ", t.stack.length / 1024); 4069 VM.sysWrite("k\n"); 4070 } 4071 } 4072 4073 @NoInline 4074 @BaselineNoRegisters 4075 // this method does not do a normal return and hence does not execute epilogue 4076 // --> non-volatiles not restored! 4077 private static void transferExecutionToNewStack(byte[] newStack, 4078 Registers exceptionRegisters) { 4079 // prevent opt compiler from inlining a method that contains a magic 4080 // (returnToNewStack) that it does not implement. 4081 4082 RVMThread myThread = getCurrentThread(); 4083 byte[] myStack = myThread.stack; 4084 4085 // initialize new stack with live portion of stack we're 4086 // currently running on 4087 // 4088 // lo-mem hi-mem 4089 // |<---myDepth----| 4090 // +----------+---------------+ 4091 // | empty | live | 4092 // +----------+---------------+ 4093 // ^myStack ^myFP ^myTop 4094 // 4095 // +-------------------+---------------+ 4096 // | empty | live | 4097 // +-------------------+---------------+ 4098 // ^newStack ^newFP ^newTop 4099 // 4100 Address myTop = Magic.objectAsAddress(myStack).plus(myStack.length); 4101 Address newTop = Magic.objectAsAddress(newStack).plus(newStack.length); 4102 4103 Address myFP = Magic.getFramePointer(); 4104 Offset myDepth = myTop.diff(myFP); 4105 Address newFP = newTop.minus(myDepth); 4106 4107 // The frame pointer addresses the top of the frame on powerpc and 4108 // the bottom 4109 // on intel. if we copy the stack up to the current 4110 // frame pointer in here, the 4111 // copy will miss the header of the intel frame. Thus we make another 4112 // call 4113 // to force the copy. A more explicit way would be to up to the 4114 // frame pointer 4115 // and the header for intel. 4116 Offset delta = copyStack(newStack); 4117 4118 // fix up registers and save areas so they refer 4119 // to "newStack" rather than "myStack" 4120 // 4121 if (exceptionRegisters != null) { 4122 adjustRegisters(exceptionRegisters, delta); 4123 } 4124 adjustStack(newStack, newFP, delta); 4125 4126 // install new stack 4127 // 4128 myThread.stack = newStack; 4129 myThread.stackLimit = Magic.objectAsAddress(newStack) 4130 .plus(STACK_SIZE_GUARD); 4131 4132 // return to caller, resuming execution on new stack 4133 // (original stack now abandoned) 4134 // 4135 if (VM.BuildForPowerPC) { 4136 Magic.returnToNewStack(Magic.getCallerFramePointer(newFP)); 4137 } else if (VM.BuildForIA32) { 4138 Magic.returnToNewStack(newFP); 4139 } 4140 4141 if (VM.VerifyAssertions) 4142 VM._assert(VM.NOT_REACHED); 4143 } 4144 4145 /** 4146 * This (suspended) thread's stack has been moved. Fixup register and memory 4147 * references to reflect its new position. 4148 * 4149 * @param delta 4150 * displacement to be applied to all interior references 4151 */ 4152 public void fixupMovedStack(Offset delta) { 4153 if (traceAdjustments) 4154 VM.sysWrite("Thread: fixupMovedStack\n"); 4155 4156 if (!contextRegisters.getInnermostFramePointer().isZero()) { 4157 adjustRegisters(contextRegisters, delta); 4158 } 4159 if ((exceptionRegisters.inuse) && 4160 (exceptionRegisters.getInnermostFramePointer().NE(Address.zero()))) { 4161 adjustRegisters(exceptionRegisters, delta); 4162 } 4163 if (!contextRegisters.getInnermostFramePointer().isZero()) { 4164 adjustStack(stack, contextRegisters.getInnermostFramePointer(), delta); 4165 } 4166 stackLimit = stackLimit.plus(delta); 4167 } 4168 4169 /** 4170 * A thread's stack has been moved or resized. Adjust registers to reflect new 4171 * position. 4172 * 4173 * @param registers 4174 * registers to be adjusted 4175 * @param delta 4176 * displacement to be applied 4177 */ 4178 private static void adjustRegisters(Registers registers, Offset delta) { 4179 if (traceAdjustments) 4180 VM.sysWrite("Thread: adjustRegisters\n"); 4181 4182 // adjust FP 4183 // 4184 Address newFP = registers.getInnermostFramePointer().plus(delta); 4185 Address ip = registers.getInnermostInstructionAddress(); 4186 registers.setInnermost(ip, newFP); 4187 if (traceAdjustments) { 4188 VM.sysWrite(" fp="); 4189 VM.sysWrite(registers.getInnermostFramePointer()); 4190 } 4191 4192 // additional architecture specific adjustments 4193 // (1) frames from all compilers on IA32 need to update ESP 4194 int compiledMethodId = Magic.getCompiledMethodID(registers 4195 .getInnermostFramePointer()); 4196 if (compiledMethodId != INVISIBLE_METHOD_ID) { 4197 if (VM.BuildForIA32) { 4198 Configuration.archHelper.adjustESP(registers, delta, traceAdjustments); 4199 } 4200 if (traceAdjustments) { 4201 CompiledMethod compiledMethod = CompiledMethods 4202 .getCompiledMethod(compiledMethodId); 4203 VM.sysWrite(" method="); 4204 VM.sysWrite(compiledMethod.getMethod()); 4205 VM.sysWrite("\n"); 4206 } 4207 } 4208 } 4209 4210 /** 4211 * A thread's stack has been moved or resized. Adjust internal pointers to 4212 * reflect new position. 4213 * 4214 * @param stack 4215 * stack to be adjusted 4216 * @param fp 4217 * pointer to its innermost frame 4218 * @param delta 4219 * displacement to be applied to all its interior references 4220 */ 4221 private static void adjustStack(byte[] stack, Address fp, Offset delta) { 4222 if (traceAdjustments) 4223 VM.sysWrite("Thread: adjustStack\n"); 4224 4225 while (Magic.getCallerFramePointer(fp).NE(STACKFRAME_SENTINEL_FP)) { 4226 // adjust FP save area 4227 // 4228 Magic.setCallerFramePointer(fp, Magic.getCallerFramePointer(fp).plus( 4229 delta)); 4230 if (traceAdjustments) { 4231 VM.sysWrite(" fp=", fp.toWord()); 4232 } 4233 4234 // advance to next frame 4235 // 4236 fp = Magic.getCallerFramePointer(fp); 4237 } 4238 } 4239 4240 /** 4241 * Initialize a new stack with the live portion of the stack we're currently 4242 * running on. 4243 * 4244 * <pre> 4245 * lo-mem hi-mem 4246 * |<---myDepth----| 4247 * +----------+---------------+ 4248 * | empty | live | 4249 * +----------+---------------+ 4250 * ˆmyStack ˆmyFP ˆmyTop 4251 * +-------------------+---------------+ 4252 * | empty | live | 4253 * +-------------------+---------------+ 4254 * ˆnewStack ˆnewFP ˆnewTop 4255 * </pre> 4256 */ 4257 private static Offset copyStack(byte[] newStack) { 4258 RVMThread myThread = getCurrentThread(); 4259 byte[] myStack = myThread.stack; 4260 4261 Address myTop = Magic.objectAsAddress(myStack).plus(myStack.length); 4262 Address newTop = Magic.objectAsAddress(newStack).plus(newStack.length); 4263 Address myFP = Magic.getFramePointer(); 4264 Offset myDepth = myTop.diff(myFP); 4265 Address newFP = newTop.minus(myDepth); 4266 4267 // before copying, make sure new stack isn't too small 4268 // 4269 if (VM.VerifyAssertions) { 4270 VM._assert(newFP.GE(Magic.objectAsAddress(newStack) 4271 .plus(STACK_SIZE_GUARD))); 4272 } 4273 4274 Memory.memcopy(newFP, myFP, myDepth.toWord().toExtent()); 4275 4276 return newFP.diff(myFP); 4277 } 4278 4279 /** 4280 * Set the "isDaemon" status of this thread. Although a java.lang.Thread can 4281 * only have setDaemon invoked on it before it is started, Threads can become 4282 * daemons at any time. Note: making the last non daemon a daemon will 4283 * terminate the VM. 4284 * <p> 4285 * Note: This method might need to be uninterruptible so it is final, which is 4286 * why it isn't called setDaemon. 4287 * <p> 4288 * Public so that java.lang.Thread can use it. 4289 */ 4290 public void makeDaemon(boolean on) { 4291 if (daemon == on) { 4292 // nothing to do 4293 } else { 4294 daemon = on; 4295 if (getExecStatus() == NEW) { 4296 // thread will start as a daemon 4297 } else { 4298 boolean terminateSystem = false; 4299 acctLock.lockNoHandshake(); 4300 numActiveDaemons += on ? 1 : -1; 4301 if (numActiveDaemons == numActiveThreads) { 4302 terminateSystem = true; 4303 } 4304 acctLock.unlock(); 4305 if (terminateSystem) { 4306 if (VM.TraceThreads) { 4307 trace("Thread", "last non Daemon demonized"); 4308 } 4309 VM.sysExit(0); 4310 if (VM.VerifyAssertions) 4311 VM._assert(VM.NOT_REACHED); 4312 } 4313 } 4314 } 4315 } 4316 4317 /** 4318 * Dump information for all threads, via {@link VM#sysWrite(String)}. Each 4319 * thread's info is newline-terminated. 4320 * 4321 * @param verbosity Ignored. 4322 */ 4323 public static void dumpAll(int verbosity) { 4324 for (int i = 0; i < numThreads; i++) { 4325 RVMThread t = threads[i]; 4326 if (t == null) 4327 continue; 4328 VM.sysWrite("Thread "); 4329 VM.sysWriteInt(t.threadSlot); 4330 VM.sysWrite(": "); 4331 VM.sysWriteHex(Magic.objectAsAddress(t)); 4332 VM.sysWrite(" "); 4333 t.dump(verbosity); 4334 // Compensate for t.dump() not newline-terminating info. 4335 VM.sysWriteln(); 4336 } 4337 } 4338 4339 /** @return The value of {@link #isBootThread} */ 4340 public boolean isBootThread() { 4341 return this == bootThread; 4342 } 4343 4344 /** @return Is this the MainThread ? */ 4345 private boolean isMainThread() { 4346 return thread instanceof MainThread; 4347 } 4348 4349 /** Is this a system thread? */ 4350 public boolean isSystemThread() { 4351 return systemThread != null; 4352 } 4353 4354 /** Get the collector thread this RVMTHread is running */ 4355 public CollectorThread getCollectorThread() { 4356 if (VM.VerifyAssertions) VM._assert(isCollectorThread()); 4357 return (CollectorThread)systemThread; 4358 } 4359 4360 /** Returns the value of {@link #daemon}. */ 4361 public boolean isDaemonThread() { 4362 return daemon; 4363 } 4364 4365 /** 4366 * Should this thread run concurrently with STW GC and ignore handshakes? 4367 */ 4368 public boolean ignoreHandshakesAndGC() { 4369 if (systemThread == null) return false; 4370 return systemThread instanceof TimerThread; 4371 } 4372 4373 /** Is the thread started and not terminated */ 4374 public boolean isAlive() { 4375 monitor().lockNoHandshake(); 4376 observeExecStatus(); 4377 boolean result = execStatus != NEW && execStatus != TERMINATED && !isAboutToTerminate; 4378 monitor().unlock(); 4379 return result; 4380 } 4381 4382 /** 4383 * Sets the name of the thread 4384 * 4385 * @param name the new name for the thread 4386 * @see java.lang.Thread#setName(String) 4387 */ 4388 public void setName(String name) { 4389 this.name = name; 4390 } 4391 4392 /** 4393 * Gets the name of the thread 4394 * 4395 * @see java.lang.Thread#getName() 4396 */ 4397 public String getName() { 4398 return name; 4399 } 4400 4401 /** 4402 * Does the currently running Thread hold the lock on an obj? 4403 * 4404 * @param obj 4405 * the object to check 4406 * @return whether the thread holds the lock 4407 * @see java.lang.Thread#holdsLock(Object) 4408 */ 4409 public boolean holdsLock(Object obj) { 4410 RVMThread mine = getCurrentThread(); 4411 return ObjectModel.holdsLock(obj, mine); 4412 } 4413 4414 /** 4415 * Was this thread interrupted? 4416 * 4417 * @return whether the thread has been interrupted 4418 * @see java.lang.Thread#isInterrupted() 4419 */ 4420 public boolean isInterrupted() { 4421 return hasInterrupt; 4422 } 4423 4424 /** 4425 * Clear the interrupted status of this thread 4426 * 4427 * @see java.lang.Thread#interrupted() 4428 */ 4429 public void clearInterrupted() { 4430 hasInterrupt = false; 4431 } 4432 4433 /** 4434 * Interrupt this thread 4435 * 4436 * @see java.lang.Thread#interrupt() 4437 */ 4438 @Interruptible 4439 public void interrupt() { 4440 monitor().lockNoHandshake(); 4441 hasInterrupt = true; 4442 monitor().broadcast(); 4443 monitor().unlock(); 4444 } 4445 4446 /** 4447 * Get the priority of the thread 4448 * 4449 * @return the thread's priority 4450 * @see java.lang.Thread#getPriority() 4451 */ 4452 public int getPriority() { 4453 return priority; 4454 } 4455 4456 /** 4457 * Set the priority of the thread 4458 * 4459 * @param priority 4460 * @see java.lang.Thread#getPriority() 4461 */ 4462 public void setPriority(int priority) { 4463 this.priority = priority; 4464 // @TODO this should be calling a syscall 4465 } 4466 4467 /** 4468 * Get the state of the thread in a manner compatible with the Java API 4469 * 4470 * @return thread state 4471 * @see java.lang.Thread#getState() 4472 */ 4473 @Interruptible 4474 public Thread.State getState() { 4475 monitor().lockNoHandshake(); 4476 try { 4477 observeExecStatus(); 4478 switch (execStatus) { 4479 case NEW: 4480 return Thread.State.NEW; 4481 case IN_JAVA: 4482 case IN_NATIVE: 4483 case IN_JNI: 4484 case IN_JAVA_TO_BLOCK: 4485 case BLOCKED_IN_NATIVE: 4486 case BLOCKED_IN_JNI: 4487 if (isAboutToTerminate) { 4488 return Thread.State.TERMINATED; 4489 } 4490 switch (waiting) { 4491 case RUNNABLE: 4492 return Thread.State.RUNNABLE; 4493 case WAITING: 4494 return Thread.State.WAITING; 4495 case TIMED_WAITING: 4496 return Thread.State.TIMED_WAITING; 4497 default: 4498 VM.sysFail("Unknown waiting value: " + waiting); 4499 return null; 4500 } 4501 case TERMINATED: 4502 return Thread.State.TERMINATED; 4503 default: 4504 VM.sysFail("Unknown value of execStatus: " + execStatus); 4505 return null; 4506 } 4507 } finally { 4508 monitor().unlock(); 4509 } 4510 } 4511 4512 /** 4513 * Wait for the thread to die or for the timeout to occur 4514 * 4515 * @param ms 4516 * milliseconds to wait 4517 * @param ns 4518 * nanoseconds to wait 4519 */ 4520 @Interruptible 4521 public void join(long ms, int ns) throws InterruptedException { 4522 RVMThread myThread = getCurrentThread(); 4523 if (VM.VerifyAssertions) 4524 VM._assert(myThread != this); 4525 if (traceBlock) 4526 VM.sysWriteln("Joining on Thread #", threadSlot); 4527 // this uses synchronized because we cannot have one thread acquire 4528 // another thread's lock using the WithHandshake scheme, as that would result 4529 // in a thread holding two threads' monitor()s. using synchronized 4530 // turns out to be just fine - see comment in terminate(). 4531 synchronized (this) { 4532 if (ms == 0 && ns == 0) { 4533 while (!isJoinable) { 4534 wait(this); 4535 if (traceBlock) 4536 VM.sysWriteln("relooping in join on Thread #", threadSlot); 4537 } 4538 } else { 4539 long startNano = Time.nanoTime(); 4540 long whenWakeup = startNano + ms * 1000L * 1000L + ns; 4541 while (!isJoinable) { 4542 waitAbsoluteNanos(this, whenWakeup); 4543 if (Time.nanoTime() >= whenWakeup) { 4544 break; 4545 } 4546 if (traceBlock) 4547 VM.sysWriteln("relooping in join on Thread #", threadSlot); 4548 } 4549 } 4550 } 4551 } 4552 4553 /** 4554 * Count the stack frames of this thread 4555 */ 4556 @Interruptible 4557 public int countStackFrames() { 4558 if (!isSuspended) { 4559 throw new IllegalThreadStateException( 4560 "Thread.countStackFrames called on non-suspended thread"); 4561 } 4562 throw new UnimplementedError(); 4563 } 4564 4565 /** 4566 * @return the length of the stack 4567 */ 4568 public int getStackLength() { 4569 return stack.length; 4570 } 4571 4572 /** 4573 * @return the stack 4574 */ 4575 public byte[] getStack() { 4576 return stack; 4577 } 4578 4579 /** 4580 * @return the thread's exception registers 4581 */ 4582 public Registers getExceptionRegisters() { 4583 return exceptionRegisters; 4584 } 4585 4586 /** 4587 * @return the thread's context registers (saved registers when thread is 4588 * suspended by green-thread scheduler). 4589 */ 4590 public Registers getContextRegisters() { 4591 return contextRegisters; 4592 } 4593 4594 /** Set the initial attempt. */ 4595 public void reportCollectionAttempt() { 4596 collectionAttempt++; 4597 } 4598 4599 /** Set the initial attempt. */ 4600 public int getCollectionAttempt() { 4601 return collectionAttempt; 4602 } 4603 4604 /** Resets the attempts. */ 4605 public void resetCollectionAttempts() { 4606 collectionAttempt = 0; 4607 } 4608 4609 /** Get the physical allocation failed flag. */ 4610 public boolean physicalAllocationFailed() { 4611 return physicalAllocationFailed; 4612 } 4613 4614 /** Set the physical allocation failed flag. */ 4615 public void setPhysicalAllocationFailed() { 4616 physicalAllocationFailed = true; 4617 } 4618 4619 /** Clear the physical allocation failed flag. */ 4620 public void clearPhysicalAllocationFailed() { 4621 physicalAllocationFailed = false; 4622 } 4623 4624 /** 4625 * Returns the outstanding OutOfMemoryError. 4626 */ 4627 public static OutOfMemoryError getOutOfMemoryError() { 4628 return outOfMemoryError; 4629 } 4630 4631 /** 4632 * Number of active threads in the system. 4633 */ 4634 public static int getNumActiveThreads() { 4635 return numActiveThreads; 4636 } 4637 4638 /** 4639 * Number of active daemon threads. 4640 */ 4641 public static int getNumActiveDaemons() { 4642 return numActiveDaemons; 4643 } 4644 4645 @Interruptible 4646 public void handleUncaughtException(Throwable exceptionObject) { 4647 uncaughtExceptionCount++; 4648 4649 handlePossibleRecursiveException(); 4650 VM.enableGC(); 4651 if (thread == null) { 4652 VM.sysWrite("Exception in the primordial thread \"", getName(), 4653 "\" while booting: "); 4654 } else { 4655 // This is output like that of the Sun JDK. 4656 VM.sysWrite("Exception in thread \"", getName(), "\": "); 4657 } 4658 if (exceptionObject instanceof OutOfMemoryError) { 4659 VM.sysWriteln(" <<No stacktrace available>>"); 4660 } else if (VM.fullyBooted) { 4661 exceptionObject.printStackTrace(); 4662 } 4663 getCurrentThread().terminate(); 4664 if (VM.VerifyAssertions) 4665 VM._assert(VM.NOT_REACHED); 4666 } 4667 4668 /** Handle the case of exception handling triggering new exceptions. */ 4669 private void handlePossibleRecursiveException() { 4670 if (uncaughtExceptionCount > 1 && 4671 uncaughtExceptionCount <= VM.maxSystemTroubleRecursionDepth + VM.maxSystemTroubleRecursionDepthBeforeWeStopVMSysWrite) { 4672 VM.sysWrite("We got an uncaught exception while (recursively) handling "); 4673 VM.sysWrite(uncaughtExceptionCount - 1); 4674 VM.sysWrite(" uncaught exception"); 4675 if (uncaughtExceptionCount - 1 != 1) { 4676 VM.sysWrite("s"); 4677 } 4678 VM.sysWriteln("."); 4679 } 4680 if (uncaughtExceptionCount > VM.maxSystemTroubleRecursionDepth) { 4681 dumpVirtualMachine(); 4682 VM.dieAbruptlyRecursiveSystemTrouble(); 4683 if (VM.VerifyAssertions) 4684 VM._assert(VM.NOT_REACHED); 4685 } 4686 } 4687 4688 private static void dumpThread(RVMThread t) { 4689 if (t == null) { 4690 VM.sysWrite("none"); 4691 } else { 4692 VM.sysWrite(t.threadSlot, "(", t.getExecStatus()); 4693 if (t.isAboutToTerminate) { 4694 VM.sysWrite("T"); 4695 } 4696 if (t.isBlocking) { 4697 VM.sysWrite("B"); 4698 } 4699 if (t.isJoinable) { 4700 VM.sysWrite("J"); 4701 } 4702 if (t.atYieldpoint) { 4703 VM.sysWrite("Y"); 4704 } 4705 VM.sysWrite(")"); 4706 } 4707 } 4708 4709 private static void dumpThreadArray(RVMThread[] array, int bound) { 4710 for (int i = 0; i < bound; ++i) { 4711 if (i != 0) { 4712 VM.sysWrite(", "); 4713 } 4714 VM.sysWrite(i, ":"); 4715 dumpThread(array[i]); 4716 } 4717 } 4718 4719 private static void dumpThreadSlotArray(int[] array, int bound) { 4720 for (int i = 0; i < bound; ++i) { 4721 if (i != 0) { 4722 VM.sysWrite(", "); 4723 } 4724 VM.sysWrite(i, ":"); 4725 int threadSlot=array[i]; 4726 VM.sysWrite(threadSlot, ","); 4727 dumpThread(threadBySlot[array[i]]); 4728 } 4729 } 4730 4731 private static void dumpThreadArray(String name, RVMThread[] array, int bound) { 4732 VM.sysWrite(name); 4733 VM.sysWrite(": "); 4734 dumpThreadArray(array, bound); 4735 VM.sysWriteln(); 4736 } 4737 4738 private static void dumpThreadSlotArray(String name, int[] array, int bound) { 4739 VM.sysWrite(name); 4740 VM.sysWrite(": "); 4741 dumpThreadSlotArray(array, bound); 4742 VM.sysWriteln(); 4743 } 4744 4745 public static void dumpAcct() { 4746 acctLock.lockNoHandshake(); 4747 dumpLock.lockNoHandshake(); 4748 VM.sysWriteln("====== Begin Thread Accounting Dump ======"); 4749 dumpThreadArray("threadBySlot", threadBySlot, nextSlot); 4750 dumpThreadSlotArray("aboutToTerminate", aboutToTerminate, aboutToTerminateN); 4751 VM.sysWrite("freeSlots: "); 4752 for (int i = 0; i < freeSlotN; ++i) { 4753 if (i != 0) { 4754 VM.sysWrite(", "); 4755 } 4756 VM.sysWrite(i, ":", freeSlots[i]); 4757 } 4758 VM.sysWriteln(); 4759 dumpThreadArray("threads", threads, numThreads); 4760 VM.sysWriteln("====== End Thread Accounting Dump ======"); 4761 dumpLock.unlock(); 4762 acctLock.unlock(); 4763 } 4764 4765 public void extDump() { 4766 dump(); 4767 VM.sysWriteln(); 4768 VM.sysWriteln("acquireCount for my monitor: ", monitor().acquireCount); 4769 VM.sysWriteln("yieldpoints taken: ", yieldpointsTaken); 4770 VM.sysWriteln("yieldpoints taken fully: ", yieldpointsTakenFully); 4771 VM.sysWriteln("native entered blocked: ", nativeEnteredBlocked); 4772 VM.sysWriteln("JNI entered blocked: ", jniEnteredBlocked); 4773 } 4774 4775 /** 4776 * Dump this thread's identifying information, for debugging, via 4777 * {@link VM#sysWrite(String)}. We do not use any spacing or newline 4778 * characters. Callers are responsible for space-separating or 4779 * newline-terminating output. 4780 */ 4781 public void dump() { 4782 dump(0); 4783 } 4784 4785 /** 4786 * Dump this thread's identifying information, for debugging, via 4787 * {@link VM#sysWrite(String)}. We pad to a minimum of leftJustify 4788 * characters. We do not use any spacing characters. Callers are responsible 4789 * for space-separating or newline-terminating output. 4790 * 4791 * @param leftJustify 4792 * minimum number of characters emitted, with any extra characters 4793 * being spaces. 4794 */ 4795 public void dumpWithPadding(int leftJustify) { 4796 char[] buf = Services.grabDumpBuffer(); 4797 int len = dump(buf); 4798 VM.sysWrite(buf, len); 4799 for (int i = leftJustify - len; i > 0; i--) { 4800 VM.sysWrite(" "); 4801 } 4802 Services.releaseDumpBuffer(); 4803 } 4804 4805 /** 4806 * Dump this thread's identifying information, for debugging, via 4807 * {@link VM#sysWrite(String)}. We do not use any spacing or newline 4808 * characters. Callers are responsible for space-separating or 4809 * newline-terminating output. 4810 * 4811 * This function avoids write barriers and allocation. 4812 * 4813 * @param verbosity 4814 * Ignored. 4815 */ 4816 public void dump(int verbosity) { 4817 char[] buf = Services.grabDumpBuffer(); 4818 int len = dump(buf); 4819 VM.sysWrite(buf, len); 4820 Services.releaseDumpBuffer(); 4821 } 4822 4823 /** 4824 * Dump this thread's info, for debugging. Copy the info about it into a 4825 * destination char array. We do not use any spacing or newline characters. 4826 * 4827 * This function may be called during GC; it avoids write barriers and 4828 * allocation. 4829 * 4830 * For this reason, we do not throw an <code>IndexOutOfBoundsException</code>. 4831 * 4832 * @param dest 4833 * char array to copy the source info into. 4834 * @param offset 4835 * Offset into <code>dest</code> where we start copying 4836 * 4837 * @return 1 plus the index of the last character written. If we were to write 4838 * zero characters (which we won't) then we would return 4839 * <code>offset</code>. This is intended to represent the first 4840 * unused position in the array <code>dest</code>. However, it also 4841 * serves as a pseudo-overflow check: It may have the value 4842 * <code>dest.length</code>, if the array <code>dest</code> was 4843 * completely filled by the call, or it may have a value greater than 4844 * <code>dest.length</code>, if the info needs more than 4845 * <code>dest.length - offset</code> characters of space. 4846 * 4847 * -1 if <code>offset</code> is negative. 4848 */ 4849 public int dump(char[] dest, int offset) { 4850 offset = Services.sprintf(dest, offset, getThreadSlot()); // id 4851 if (daemon) { 4852 offset = Services.sprintf(dest, offset, "-daemon"); // daemon thread? 4853 } 4854 if (isBootThread()) { 4855 offset = Services.sprintf(dest, offset, "-Boot"); // Boot (Primordial) 4856 // thread 4857 } 4858 if (isSystemThread()) { 4859 offset = Services.sprintf(dest, offset, "-system"); // System Thread 4860 } 4861 if (isMainThread()) { 4862 offset = Services.sprintf(dest, offset, "-main"); // Main Thread 4863 } 4864 if (isCollectorThread()) { 4865 offset = Services.sprintf(dest, offset, "-collector"); // gc thread? 4866 } 4867 offset = Services.sprintf(dest, offset, "-"); 4868 offset = Services.sprintf(dest, offset, getExecStatus()); 4869 offset = Services.sprintf(dest, offset, "-"); 4870 offset = Services.sprintf(dest, offset, java.lang.JikesRVMSupport 4871 .getEnumName(waiting)); 4872 if (hasInterrupt || asyncThrowable != null) { 4873 offset = Services.sprintf(dest, offset, "-interrupted"); 4874 } 4875 if (isAboutToTerminate) { 4876 offset = Services.sprintf(dest, offset, "-terminating"); 4877 } 4878 return offset; 4879 } 4880 4881 /** 4882 * Dump this thread's info, for debugging. Copy the info about it into a 4883 * destination char array. We do not use any spacing or newline characters. 4884 * <p> 4885 * This is identical to calling {@link #dump(char[],int)} with an 4886 * <code>offset</code> of zero. 4887 */ 4888 public int dump(char[] dest) { 4889 return dump(dest, 0); 4890 } 4891 4892 /** Dump statistics gather on operations */ 4893 static void dumpStats() { 4894 VM.sysWrite("FatLocks: "); 4895 VM.sysWrite(waitOperations); 4896 VM.sysWrite(" wait operations\n"); 4897 VM.sysWrite("FatLocks: "); 4898 VM.sysWrite(timedWaitOperations); 4899 VM.sysWrite(" timed wait operations\n"); 4900 VM.sysWrite("FatLocks: "); 4901 VM.sysWrite(notifyOperations); 4902 VM.sysWrite(" notify operations\n"); 4903 VM.sysWrite("FatLocks: "); 4904 VM.sysWrite(notifyAllOperations); 4905 } 4906 4907 /** 4908 * Print out message in format "[j] (cez#td) who: what", where: j = java 4909 * thread id z* = RVMThread.getCurrentThread().yieldpointsEnabledCount (0 4910 * means yieldpoints are enabled outside of the call to debug) t* = 4911 * numActiveThreads d* = numActiveDaemons * parenthetical values, printed only 4912 * if traceDetails = true) 4913 * <p> 4914 * We serialize against a mutex to avoid intermingling debug output from 4915 * multiple threads. 4916 */ 4917 public static void trace(String who, String what) { 4918 outputLock.lockNoHandshake(); 4919 VM.sysWrite("["); 4920 RVMThread t = getCurrentThread(); 4921 t.dump(); 4922 VM.sysWrite("] "); 4923 if (traceDetails) { 4924 VM.sysWrite("("); 4925 VM.sysWriteInt(numActiveDaemons); 4926 VM.sysWrite("/"); 4927 VM.sysWriteInt(numActiveThreads); 4928 VM.sysWrite(") "); 4929 } 4930 VM.sysWrite(who); 4931 VM.sysWrite(": "); 4932 VM.sysWrite(what); 4933 VM.sysWrite("\n"); 4934 outputLock.unlock(); 4935 } 4936 4937 /** 4938 * Print out message in format "p[j] (cez#td) who: what howmany", where: p = 4939 * processor id j = java thread id c* = java thread id of the owner of 4940 * threadCreationMutex (if any) e* = java thread id of the owner of 4941 * threadExecutionMutex (if any) t* = numActiveThreads d* = numActiveDaemons * 4942 * parenthetical values, printed only if traceDetails = true) 4943 * <p> 4944 * We serialize against a mutex to avoid intermingling debug output from 4945 * multiple threads. 4946 */ 4947 public static void trace(String who, String what, int howmany) { 4948 _trace(who, what, howmany, false); 4949 } 4950 4951 // same as trace, but prints integer value in hex 4952 // 4953 public static void traceHex(String who, String what, int howmany) { 4954 _trace(who, what, howmany, true); 4955 } 4956 4957 public static void trace(String who, String what, Address addr) { 4958 outputLock.lockNoHandshake(); 4959 VM.sysWrite("["); 4960 getCurrentThread().dump(); 4961 VM.sysWrite("] "); 4962 if (traceDetails) { 4963 VM.sysWrite("("); 4964 VM.sysWriteInt(numActiveDaemons); 4965 VM.sysWrite("/"); 4966 VM.sysWriteInt(numActiveThreads); 4967 VM.sysWrite(") "); 4968 } 4969 VM.sysWrite(who); 4970 VM.sysWrite(": "); 4971 VM.sysWrite(what); 4972 VM.sysWrite(" "); 4973 VM.sysWriteHex(addr); 4974 VM.sysWrite("\n"); 4975 outputLock.unlock(); 4976 } 4977 4978 private static void _trace(String who, String what, int howmany, boolean hex) { 4979 outputLock.lockNoHandshake(); 4980 VM.sysWrite("["); 4981 // VM.sysWriteInt(RVMThread.getCurrentThread().getThreadSlot()); 4982 getCurrentThread().dump(); 4983 VM.sysWrite("] "); 4984 if (traceDetails) { 4985 VM.sysWrite("("); 4986 VM.sysWriteInt(numActiveDaemons); 4987 VM.sysWrite("/"); 4988 VM.sysWriteInt(numActiveThreads); 4989 VM.sysWrite(") "); 4990 } 4991 VM.sysWrite(who); 4992 VM.sysWrite(": "); 4993 VM.sysWrite(what); 4994 VM.sysWrite(" "); 4995 if (hex) { 4996 VM.sysWriteHex(howmany); 4997 } else { 4998 VM.sysWriteInt(howmany); 4999 } 5000 VM.sysWrite("\n"); 5001 outputLock.unlock(); 5002 } 5003 5004 /** 5005 * Print interesting scheduler information, starting with a stack traceback. 5006 * <p> 5007 * Note: the system could be in a fragile state when this method is called, so 5008 * we try to rely on as little runtime functionality as possible (eg. use no 5009 * bytecodes that require RuntimeEntrypoints support). 5010 */ 5011 public static void traceback(String message) { 5012 if (VM.runningVM) { 5013 outputLock.lockNoHandshake(); 5014 } 5015 VM.sysWriteln(message); 5016 tracebackWithoutLock(); 5017 if (VM.runningVM) { 5018 outputLock.unlock(); 5019 } 5020 } 5021 5022 public static void traceback(String message, int number) { 5023 if (VM.runningVM) { 5024 outputLock.lockNoHandshake(); 5025 } 5026 VM.sysWriteln(message, number); 5027 tracebackWithoutLock(); 5028 if (VM.runningVM) { 5029 outputLock.unlock(); 5030 } 5031 } 5032 5033 static void tracebackWithoutLock() { 5034 if (VM.runningVM) { 5035 VM.sysWriteln("Thread #", getCurrentThreadSlot()); 5036 dumpStack(Magic.getCallerFramePointer(Magic.getFramePointer())); 5037 } else { 5038 dumpStack(); 5039 } 5040 } 5041 5042 /** 5043 * Dump stack of calling thread, starting at callers frame 5044 */ 5045 @UninterruptibleNoWarn("Never blocks") 5046 public static void dumpStack() { 5047 if (VM.runningVM) { 5048 VM.sysWriteln("Dumping stack for Thread #", getCurrentThreadSlot()); 5049 dumpStack(Magic.getFramePointer()); 5050 } else { 5051 StackTraceElement[] elements = (new Throwable( 5052 "--traceback from Jikes RVM's RVMThread class--")).getStackTrace(); 5053 for (StackTraceElement element : elements) { 5054 System.err.println(element.toString()); 5055 } 5056 } 5057 } 5058 5059 /** 5060 * Dump state of a (stopped) thread's stack. 5061 * 5062 * @param fp address of starting frame. first frame output is the calling 5063 * frame of passed frame 5064 */ 5065 public static void dumpStack(Address fp) { 5066 if (VM.VerifyAssertions) { 5067 VM._assert(VM.runningVM); 5068 } 5069 Address ip = Magic.getReturnAddress(fp); 5070 fp = Magic.getCallerFramePointer(fp); 5071 dumpStack(ip, fp); 5072 } 5073 5074 /** 5075 * Dump state of a (stopped) thread's stack. 5076 * 5077 * @param ip instruction pointer for first frame to dump 5078 * @param fp frame pointer for first frame to dump 5079 */ 5080 public static void dumpStack(Address ip, Address fp) { 5081 boolean b = Monitor.lockNoHandshake(dumpLock); 5082 RVMThread t = getCurrentThread(); 5083 ++t.inDumpStack; 5084 if (t.inDumpStack > 1 && 5085 t.inDumpStack <= VM.maxSystemTroubleRecursionDepth + VM.maxSystemTroubleRecursionDepthBeforeWeStopVMSysWrite) { 5086 VM.sysWrite("RVMThread.dumpStack(): in a recursive call, "); 5087 VM.sysWrite(t.inDumpStack); 5088 VM.sysWriteln(" deep."); 5089 } 5090 if (t.inDumpStack > VM.maxSystemTroubleRecursionDepth) { 5091 VM.dieAbruptlyRecursiveSystemTrouble(); 5092 if (VM.VerifyAssertions) 5093 VM._assert(VM.NOT_REACHED); 5094 } 5095 5096 if (!isAddressValidFramePointer(fp)) { 5097 VM.sysWrite("Bogus looking frame pointer: ", fp); 5098 VM.sysWriteln(" not dumping stack"); 5099 } else { 5100 try { 5101 VM.sysWriteln("-- Stack --"); 5102 while (Magic.getCallerFramePointer(fp).NE( 5103 StackframeLayoutConstants.STACKFRAME_SENTINEL_FP)) { 5104 5105 // if code is outside of RVM heap, assume it to be native code, 5106 // skip to next frame 5107 if (!MemoryManager.addressInVM(ip)) { 5108 showMethod("native frame", fp); 5109 ip = Magic.getReturnAddress(fp); 5110 fp = Magic.getCallerFramePointer(fp); 5111 } else { 5112 5113 int compiledMethodId = Magic.getCompiledMethodID(fp); 5114 VM.sysWrite("("); VM.sysWrite(fp); VM.sysWrite(" "); VM.sysWrite(compiledMethodId); VM.sysWrite(")"); 5115 if (compiledMethodId == StackframeLayoutConstants.INVISIBLE_METHOD_ID) { 5116 showMethod("invisible method", fp); 5117 } else { 5118 // normal java frame(s) 5119 CompiledMethod compiledMethod = CompiledMethods 5120 .getCompiledMethod(compiledMethodId); 5121 if (compiledMethod == null) { 5122 showMethod(compiledMethodId, fp); 5123 } else if (compiledMethod.getCompilerType() == CompiledMethod.TRAP) { 5124 showMethod("hardware trap", fp); 5125 } else { 5126 RVMMethod method = compiledMethod.getMethod(); 5127 Offset instructionOffset = compiledMethod 5128 .getInstructionOffset(ip); 5129 int lineNumber = compiledMethod 5130 .findLineNumberForInstruction(instructionOffset); 5131 boolean frameShown = false; 5132 if (VM.BuildForOptCompiler && compiledMethod.getCompilerType() == CompiledMethod.OPT) { 5133 OptCompiledMethod optInfo = (OptCompiledMethod) compiledMethod; 5134 // Opt stack frames may contain multiple inlined methods. 5135 OptMachineCodeMap map = optInfo.getMCMap(); 5136 int iei = map.getInlineEncodingForMCOffset(instructionOffset); 5137 if (iei >= 0) { 5138 int[] inlineEncoding = map.inlineEncoding; 5139 int bci = map.getBytecodeIndexForMCOffset(instructionOffset); 5140 for (; iei >= 0; iei = OptEncodedCallSiteTree.getParent(iei, inlineEncoding)) { 5141 int mid = OptEncodedCallSiteTree.getMethodID(iei, inlineEncoding); 5142 method = MemberReference.getMemberRef(mid).asMethodReference().getResolvedMember(); 5143 lineNumber = ((NormalMethod) method).getLineNumberForBCIndex(bci); 5144 showMethod(method, lineNumber, fp); 5145 if (iei > 0) { 5146 bci = OptEncodedCallSiteTree.getByteCodeOffset(iei, inlineEncoding); 5147 } 5148 } 5149 frameShown = true; 5150 } 5151 } 5152 if (!frameShown) { 5153 showMethod(method, lineNumber, fp); 5154 } 5155 } 5156 } 5157 ip = Magic.getReturnAddress(fp); 5158 fp = Magic.getCallerFramePointer(fp); 5159 } 5160 if (!isAddressValidFramePointer(fp)) { 5161 VM.sysWrite("Bogus looking frame pointer: ", fp); 5162 VM.sysWriteln(" end of stack dump"); 5163 break; 5164 } 5165 } // end while 5166 } catch (Throwable th) { 5167 VM.sysWriteln("Something bad killed the stack dump. The last frame pointer was: ", fp); 5168 } 5169 } 5170 --t.inDumpStack; 5171 5172 Monitor.unlock(b, dumpLock); 5173 } 5174 5175 /** 5176 * Return true if the supplied address could be a valid frame pointer. To 5177 * check for validity we make sure the frame pointer is in one of the spaces; 5178 * <ul> 5179 * <li>LOS (For regular threads)</li> 5180 * <li>Immortal (For threads allocated in immortal space such as collectors)</li> 5181 * <li>Boot (For the boot thread)</li> 5182 * </ul> 5183 * 5184 * <p> 5185 * or it is {@link StackframeLayoutConstants#STACKFRAME_SENTINEL_FP}. The 5186 * STACKFRAME_SENTINEL_FP is possible when the thread has been created but has 5187 * yet to be scheduled. 5188 * </p> 5189 * 5190 * @param address 5191 * the address. 5192 * @return true if the address could be a frame pointer, false otherwise. 5193 */ 5194 private static boolean isAddressValidFramePointer(final Address address) { 5195 if (address.EQ(Address.zero())) 5196 return false; // Avoid hitting assertion failure in MMTk 5197 else 5198 return address.EQ(StackframeLayoutConstants.STACKFRAME_SENTINEL_FP) || MemoryManager.mightBeFP(address); 5199 } 5200 5201 private static void showPrologue(Address fp) { 5202 VM.sysWrite(" at "); 5203 if (SHOW_FP_IN_STACK_DUMP) { 5204 VM.sysWrite("["); 5205 VM.sysWrite(fp); 5206 VM.sysWrite(", "); 5207 VM.sysWrite(Magic.getReturnAddress(fp)); 5208 VM.sysWrite("] "); 5209 } 5210 } 5211 5212 /** 5213 * Show a method where getCompiledMethod returns null 5214 * 5215 * @param compiledMethodId 5216 * @param fp 5217 */ 5218 private static void showMethod(int compiledMethodId, Address fp) { 5219 showPrologue(fp); 5220 VM.sysWrite( 5221 "<unprintable normal Java frame: CompiledMethods.getCompiledMethod(", 5222 compiledMethodId, ") returned null>\n"); 5223 } 5224 5225 /** 5226 * Show a method that we can't show (ie just a text description of the stack 5227 * frame 5228 * 5229 * @param name 5230 * @param fp 5231 */ 5232 private static void showMethod(String name, Address fp) { 5233 showPrologue(fp); 5234 VM.sysWrite("<"); 5235 VM.sysWrite(name); 5236 VM.sysWrite(">\n"); 5237 } 5238 5239 /** 5240 * Helper function for {@link #dumpStack(Address,Address)}. Print a stack 5241 * frame showing the method. 5242 */ 5243 private static void showMethod(RVMMethod method, int lineNumber, Address fp) { 5244 showPrologue(fp); 5245 if (method == null) { 5246 VM.sysWrite("<unknown method>"); 5247 } else { 5248 VM.sysWrite(method.getDeclaringClass().getDescriptor()); 5249 VM.sysWrite(" "); 5250 VM.sysWrite(method.getName()); 5251 VM.sysWrite(method.getDescriptor()); 5252 } 5253 if (lineNumber > 0) { 5254 VM.sysWrite(" at line "); 5255 VM.sysWriteInt(lineNumber); 5256 } 5257 VM.sysWrite("\n"); 5258 } 5259 5260 /** 5261 * Dump state of a (stopped) thread's stack and exit the virtual machine. 5262 * 5263 * @param fp 5264 * address of starting frame Returned: doesn't return. This method is 5265 * called from RunBootImage.C when something goes horrifically wrong 5266 * with exception handling and we want to die with useful 5267 * diagnostics. 5268 */ 5269 @Entrypoint 5270 public static void dumpStackAndDie(Address fp) { 5271 if (!exitInProgress) { 5272 // This is the first time I've been called, attempt to exit "cleanly" 5273 exitInProgress = true; 5274 dumpStack(fp); 5275 VM.sysExit(VM.EXIT_STATUS_DUMP_STACK_AND_DIE); 5276 } else { 5277 // Another failure occurred while attempting to exit cleanly. 5278 // Get out quick and dirty to avoid hanging. 5279 sysCall.sysExit(VM.EXIT_STATUS_RECURSIVELY_SHUTTING_DOWN); 5280 } 5281 } 5282 5283 /** 5284 * Is it safe to start forcing garbage collects for stress testing? 5285 */ 5286 public static boolean safeToForceGCs() { 5287 return gcEnabled(); 5288 } 5289 5290 /** 5291 * Is it safe to start forcing garbage collects for stress testing? 5292 */ 5293 public static boolean gcEnabled() { 5294 return threadingInitialized && getCurrentThread().yieldpointsEnabled(); 5295 } 5296 5297 /** 5298 * Set up the initial thread and processors as part of boot image writing 5299 * 5300 * @return the boot thread 5301 */ 5302 @Interruptible 5303 public static RVMThread setupBootThread() { 5304 if (VM.VerifyAssertions) VM._assert(bootThread == null); 5305 BootThread bt = new BootThread(); 5306 bootThread = bt.getRVMThread(); 5307 bootThread.feedlet = TraceEngine.engine.makeFeedlet( 5308 "Jikes RVM boot thread", 5309 "Thread used to execute the initial boot sequence of Jikes RVM"); 5310 numActiveThreads++; 5311 numActiveDaemons++; 5312 return bootThread; 5313 } 5314 5315 /** 5316 * Dump state of virtual machine. 5317 */ 5318 public static void dumpVirtualMachine() { 5319 boolean b = Monitor.lockNoHandshake(dumpLock); 5320 getCurrentThread().disableYieldpoints(); 5321 VM.sysWrite("\n-- Threads --\n"); 5322 for (int i = 0; i < numThreads; ++i) { 5323 RVMThread t = threads[i]; 5324 if (t != null) { 5325 t.dumpWithPadding(30); 5326 VM.sysWrite("\n"); 5327 } 5328 } 5329 VM.sysWrite("\n"); 5330 5331 VM.sysWrite("\n-- Locks in use --\n"); 5332 Lock.dumpLocks(); 5333 5334 VM.sysWriteln("Dumping stack of active thread\n"); 5335 dumpStack(); 5336 5337 VM.sysWriteln("Attempting to dump the stack of all other live threads"); 5338 VM.sysWriteln("This is somewhat risky since if the thread is running we're going to be quite confused"); 5339 for (int i = 0; i < numThreads; ++i) { 5340 RVMThread thr = threads[i]; 5341 if (thr != null && thr != RVMThread.getCurrentThread() && thr.isAlive()) { 5342 thr.dump(); 5343 // PNT: FIXME: this won't work so well since the context registers 5344 // don't tend to have sane values 5345 if (thr.contextRegisters != null && !thr.ignoreHandshakesAndGC()) 5346 dumpStack(thr.contextRegisters.getInnermostFramePointer()); 5347 } 5348 } 5349 getCurrentThread().enableYieldpoints(); 5350 Monitor.unlock(b, dumpLock); 5351 } 5352 5353 public static Feedlet getCurrentFeedlet() { 5354 return getCurrentThread().feedlet; 5355 } 5356 5357 ////////////////////////// VM.countThreadTransitions support ////////////////////////// 5358 5359 static final int[] sloppyExecStatusHistogram = 5360 new int[LAST_EXEC_STATUS]; 5361 static final int[] statusAtSTWHistogram = 5362 new int[LAST_EXEC_STATUS]; 5363 static final int[] execStatusTransitionHistogram = 5364 new int[LAST_EXEC_STATUS*LAST_EXEC_STATUS]; 5365 5366 public static void reportThreadTransitionCounts() { 5367 VM.sysWriteln("Thread Transition Counts:"); 5368 dump1DHisto("Sloppy Exec Status Histogram",sloppyExecStatusHistogram); 5369 dump1DHisto("Status At Stop-the-world Histogram",statusAtSTWHistogram); 5370 VM.sysWriteln(" Exec Status Transition Histogram:"); 5371 for (int fromI=0;fromI<LAST_EXEC_STATUS;++fromI) { 5372 for (int toI=0;toI<LAST_EXEC_STATUS;++toI) { 5373 int val= 5374 execStatusTransitionHistogram[ 5375 transitionHistogramIndex(fromI,toI)]; 5376 if (val!=0) { 5377 VM.sysWriteln(" ",fromI,"->",toI," ",val); 5378 } 5379 } 5380 } 5381 } 5382 5383 static void dump1DHisto(String name,int[] histo) { 5384 VM.sysWriteln(" ",name,":"); 5385 for (int i=0;i<LAST_EXEC_STATUS;++i) { 5386 if (histo[i]!=0) { 5387 VM.sysWriteln(" ",i," ",histo[i]); 5388 } 5389 } 5390 } 5391 5392 void observeExecStatus() { 5393 sloppyExecStatusHistogram[execStatus]++; 5394 } 5395 5396 public static void observeExecStatusAtSTW(int execStatus) { 5397 statusAtSTWHistogram[execStatus]++; 5398 } 5399 5400 // FIXME: add histograms for states returned from various calls to block() 5401 // currently we just do it for the block() call in GC STW. 5402 5403 static int transitionHistogramIndex(int oldState,int newState) { 5404 return oldState+newState*LAST_EXEC_STATUS; 5405 } 5406 5407 static void observeStateTransition(int oldState,int newState) { 5408 execStatusTransitionHistogram[transitionHistogramIndex(oldState,newState)]++; 5409 sloppyExecStatusHistogram[oldState]++; 5410 sloppyExecStatusHistogram[newState]++; 5411 } 5412 }