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