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.mmtk.plan;
014
015 import org.mmtk.utility.Constants;
016 import org.mmtk.utility.Log;
017 import org.mmtk.utility.options.Options;
018 import org.mmtk.utility.statistics.Timer;
019 import org.mmtk.vm.VM;
020
021 import org.vmmagic.pragma.*;
022
023 /**
024 * A garbage collection proceeds as a sequence of phases. Each
025 * phase is either simple (singular) or complex (an array).<p>
026 *
027 * The context an individual phase executes in may be global, mutator,
028 * or collector.<p>
029 *
030 * Phases are executed within a stack and all synchronization between
031 * parallel GC threads is managed from within this class.<p>
032 *
033 * @see MutatorContext#collectionPhase
034 */
035 @Uninterruptible
036 public abstract class Phase implements Constants {
037 /***********************************************************************
038 *
039 * Phase allocation and storage.
040 */
041
042 /** The maximum number of phases */
043 private static final int MAX_PHASES = 64;
044 /** The array of phase instances. Zero is unused. */
045 private static final Phase[] phases = new Phase[MAX_PHASES];
046 /** The id to be allocated for the next phase */
047 private static short nextPhaseId = 1;
048
049 /** Run the phase globally. */
050 protected static final short SCHEDULE_GLOBAL = 1;
051 /** Run the phase on collectors. */
052 protected static final short SCHEDULE_COLLECTOR = 2;
053 /** Run the phase on mutators. */
054 protected static final short SCHEDULE_MUTATOR = 3;
055 /** Run this phase concurrently with the mutators */
056 protected static final short SCHEDULE_CONCURRENT = 4;
057 /** Don't run this phase. */
058 protected static final short SCHEDULE_PLACEHOLDER = 100;
059 /** This is a complex phase. */
060 protected static final short SCHEDULE_COMPLEX = 101;
061
062 /**
063 * Retrieve a phase by the unique phase identifier.
064 *
065 * @param id The phase identifier.
066 * @return The Phase instance.
067 */
068 public static Phase getPhase(short id) {
069 if (VM.VERIFY_ASSERTIONS) {
070 VM.assertions._assert(id < nextPhaseId, "Phase ID unknown");
071 VM.assertions._assert(phases[id] != null, "Uninitialised phase");
072 }
073 return phases[id];
074 }
075
076 /** Get the phase id component of an encoded phase */
077 protected static short getPhaseId(int scheduledPhase) {
078 short phaseId = (short)(scheduledPhase & 0x0000FFFF);
079 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(phaseId > 0);
080 return phaseId;
081 }
082
083 /**
084 * @param phaseId The unique phase identifier.
085 * @return The name of the phase.
086 */
087 public static String getName(short phaseId) {
088 return phases[phaseId].name;
089 }
090
091 /** Get the ordering component of an encoded phase */
092 protected static short getSchedule(int scheduledPhase) {
093 short ordering = (short)((scheduledPhase >> 16) & 0x0000FFFF);
094 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(ordering > 0);
095 return ordering;
096 }
097
098 /** Get the ordering component of an encoded phase */
099 protected static String getScheduleName(short ordering) {
100 switch (ordering) {
101 case SCHEDULE_GLOBAL: return "Global";
102 case SCHEDULE_COLLECTOR: return "Collector";
103 case SCHEDULE_MUTATOR: return "Mutator";
104 case SCHEDULE_CONCURRENT: return "Concurrent";
105 case SCHEDULE_PLACEHOLDER: return "Placeholder";
106 case SCHEDULE_COMPLEX: return "Complex";
107 default: return "UNKNOWN!";
108 }
109 }
110
111 /**
112 * Construct a phase.
113 *
114 * @param name Display name of the phase
115 */
116 @Interruptible
117 public static short createSimple(String name) {
118 return new SimplePhase(name).getId();
119 }
120
121 /**
122 * Construct a phase, re-using a specified timer.
123 *
124 * @param name Display name of the phase
125 */
126 @Interruptible
127 public static short createSimple(String name, Timer timer) {
128 return new SimplePhase(name, timer).getId();
129 }
130
131 /**
132 * Construct a complex phase.
133 *
134 * @param name Display name of the phase
135 * @param scheduledPhases The phases in this complex phase.
136 */
137 @Interruptible
138 public static short createComplex(String name,int... scheduledPhases) {
139 return new ComplexPhase(name, scheduledPhases).getId();
140 }
141
142 /**
143 * Construct a complex phase, re-using a specified timer.
144 *
145 * @param name Display name of the phase
146 * @param timer Timer for this phase to contribute to
147 * @param scheduledPhases The phases in this complex phase.
148 */
149 @Interruptible
150 public static short createComplex(String name, Timer timer, int... scheduledPhases) {
151 return new ComplexPhase(name, timer, scheduledPhases).getId();
152 }
153
154 /**
155 * Construct a phase.
156 *
157 * @param name Display name of the phase
158 * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world collection
159 */
160 @Interruptible
161 public static final short createConcurrent(String name, int atomicScheduledPhase) {
162 return new ConcurrentPhase(name, atomicScheduledPhase).getId();
163 }
164
165 /**
166 * Construct a phase, re-using a specified timer.
167 *
168 * @param name Display name of the phase
169 * @param timer Timer for this phase to contribute to
170 * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world collection
171 */
172 @Interruptible
173 public static final short createConcurrent(String name, Timer timer, int atomicScheduledPhase) {
174 return new ConcurrentPhase(name, timer, atomicScheduledPhase).getId();
175 }
176
177 /**
178 * Take the passed phase and return an encoded phase to
179 * run that phase as a complex phase.
180 *
181 * @param phaseId The phase to run as complex
182 * @return The encoded phase value.
183 */
184 public static int scheduleComplex(short phaseId) {
185 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof ComplexPhase);
186 return (SCHEDULE_COMPLEX << 16) + phaseId;
187 }
188
189 /**
190 * Take the passed phase and return an encoded phase to
191 * run that phase as a concurrent phase.
192 *
193 * @param phaseId The phase to run as concurrent
194 * @return The encoded phase value.
195 */
196 public static int scheduleConcurrent(short phaseId) {
197 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof ConcurrentPhase);
198 return (SCHEDULE_CONCURRENT << 16) + phaseId;
199 }
200
201 /**
202 * Take the passed phase and return an encoded phase to
203 * run that phase in a global context;
204 *
205 * @param phaseId The phase to run globally
206 * @return The encoded phase value.
207 */
208 public static int scheduleGlobal(short phaseId) {
209 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
210 return (SCHEDULE_GLOBAL << 16) + phaseId;
211 }
212
213 /**
214 * Take the passed phase and return an encoded phase to
215 * run that phase in a collector context;
216 *
217 * @param phaseId The phase to run on collectors
218 * @return The encoded phase value.
219 */
220 public static int scheduleCollector(short phaseId) {
221 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
222 return (SCHEDULE_COLLECTOR << 16) + phaseId;
223 }
224
225 /**
226 * Take the passed phase and return an encoded phase to
227 * run that phase in a mutator context;
228 *
229 * @param phaseId The phase to run on mutators
230 * @return The encoded phase value.
231 */
232 public static int scheduleMutator(short phaseId) {
233 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
234 return (SCHEDULE_MUTATOR << 16) + phaseId;
235 }
236
237 /**
238 * Take the passed phase and return an encoded phase to
239 * run that phase in a mutator context;
240 *
241 * @param phaseId The phase to run on mutators
242 * @return The encoded phase value.
243 */
244 public static int schedulePlaceholder(short phaseId) {
245 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
246 return (SCHEDULE_PLACEHOLDER << 16) + phaseId;
247 }
248
249 /***********************************************************************
250 *
251 * Phase instance fields/methods.
252 */
253
254 /**
255 * The unique phase identifier.
256 */
257 protected final short id;
258
259 /**
260 * The name of the phase.
261 */
262 protected final String name;
263
264 /**
265 * The Timer that is started and stopped around the execution of this
266 * phase.
267 */
268 protected final Timer timer;
269
270 /**
271 * Create a new Phase. This involves creating a corresponding Timer
272 * instance, allocating a unique identifier, and registering the
273 * Phase.
274 *
275 * @param name The name for the phase.
276 */
277 protected Phase(String name) {
278 this(name, new Timer(name, false, true));
279 }
280
281 /**
282 * Create a new phase. This involves setting the corresponding Timer
283 * instance, allocating a unique identifier, and registering the Phase.
284 *
285 * @param name The name of the phase.
286 * @param timer The timer, or null if this is an untimed phase.
287 */
288 protected Phase(String name, Timer timer) {
289 this.name = name;
290 this.timer = timer;
291 this.id = nextPhaseId++;
292 phases[this.id] = this;
293 }
294
295 /**
296 * @return The unique identifier for this phase.
297 */
298 public final short getId() {
299 return this.id;
300 }
301
302 /**
303 * Display a description of this phase, for debugging purposes.
304 */
305 protected abstract void logPhase();
306
307 /***********************************************************************
308 *
309 * Phase stack
310 */
311
312 /** The maximum stack depth for the phase stack. */
313 private static final int MAX_PHASE_STACK_DEPTH = MAX_PHASES;
314
315 /** Stores the current sub phase for a complex phase. Each entry corresponds to a phase stack entry */
316 private static int[] complexPhaseCursor = new int[MAX_PHASE_STACK_DEPTH];
317
318 /** The phase stack. Stores the current nesting of phases */
319 private static int[] phaseStack = new int[MAX_PHASE_STACK_DEPTH];
320
321 /** The current stack pointer */
322 private static int phaseStackPointer = -1;
323
324 /**
325 * The current even (0 mod 2) scheduled phase.
326 * As we only sync at the end of a phase we need this to ensure that
327 * the primary thread setting the phase does not race with the other
328 * threads reading it.
329 */
330 private static int evenScheduledPhase;
331
332 /**
333 * The current odd (1 mod 2) scheduled phase.
334 * As we only sync at the end of a phase we need this to ensure that
335 * the primary thread setting the phase does not race with the other
336 * threads reading it.
337 */
338 private static int oddScheduledPhase;
339
340 /**
341 * Do we need to add a sync point to reset the mutator count. This
342 * is necessary for consecutive mutator phases and unnecessary
343 * otherwise. Again we separate in even and odd to ensure that there
344 * is no race between the primary thread setting and the helper
345 * threads reading.
346 */
347 private static boolean evenMutatorResetRendezvous;
348
349 /**
350 * Do we need to add a sync point to reset the mutator count. This
351 * is necessary for consecutive mutator phases and unnecessary
352 * otherwise. Again we separate in even and odd to ensure that there
353 * is no race between the primary thread setting and the helper
354 * threads reading.
355 */
356 private static boolean oddMutatorResetRendezvous;
357
358 /**
359 * The complex phase whose timer should be started after the next
360 * rendezvous. We can not start the timer at the point we determine
361 * the next complex phase as we determine the next phase at the
362 * end of the previous phase before the sync point.
363 */
364 private static short startComplexTimer;
365
366 /**
367 * The complex phase whose timer should be stopped after the next
368 * rendezvous. We can not start the timer at the point we determine
369 * the next complex phase as we determine the next phase at the
370 * end of the previous phase before the sync point.
371 */
372 private static short stopComplexTimer;
373
374 /**
375 * Place a phase on the phase stack and begin processing.
376 *
377 * @param scheduledPhase The phase to execute
378 */
379 public static void beginNewPhaseStack(int scheduledPhase) {
380 int order = ((ParallelCollector)VM.activePlan.collector()).rendezvous();
381
382 if (order == 0) {
383 pushScheduledPhase(scheduledPhase);
384 }
385 processPhaseStack(false);
386 }
387
388 /**
389 * Continue the execution of a phase stack. Used for incremental
390 * and concurrent collection.
391 */
392 public static void continuePhaseStack() {
393 processPhaseStack(true);
394 }
395
396 /**
397 * Process the phase stack. This method is called by multiple threads.
398 */
399 private static void processPhaseStack(boolean resume) {
400 /* Global and Collector instances used in phases */
401 Plan plan = VM.activePlan.global();
402 ParallelCollector collector = (ParallelCollector)VM.activePlan.collector();
403
404 int order = collector.rendezvous();
405 final boolean primary = order == 0;
406
407 boolean log = Options.verbose.getValue() >= 6;
408 boolean logDetails = Options.verbose.getValue() >= 7;
409
410 if (primary && resume) {
411 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Phase.isPhaseStackEmpty());
412 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Plan.gcInProgress());
413 Plan.setGCStatus(Plan.GC_PROPER);
414 }
415
416 /* In order to reduce the need for synchronization, we keep an odd or even
417 * counter for the number of phases processed. As each phase has a single
418 * rendezvous it is only possible to be out by one so the odd or even counter
419 * protects us. */
420 boolean isEvenPhase = true;
421
422 if (primary) {
423 /* Only allow concurrent collection if we are not collecting due to resource exhaustion */
424 allowConcurrentPhase = Plan.isInternalTriggeredCollection() && !Plan.isEmergencyCollection();
425
426 /* First phase will be even, so we say we are odd here so that the next phase set is even*/
427 setNextPhase(false, getNextPhase(), false);
428 }
429
430 /* Make sure everyone sees the first phase */
431 collector.rendezvous();
432
433 /* The main phase execution loop */
434 int scheduledPhase;
435 while((scheduledPhase = getCurrentPhase(isEvenPhase)) > 0) {
436 short schedule = getSchedule(scheduledPhase);
437 short phaseId = getPhaseId(scheduledPhase);
438 Phase p = getPhase(phaseId);
439
440 /* Start the timer(s) */
441 if (primary) {
442 if (resume) {
443 resumeComplexTimers();
444 }
445 if (p.timer != null) p.timer.start();
446 if (startComplexTimer > 0) {
447 Phase.getPhase(startComplexTimer).timer.start();
448 startComplexTimer = 0;
449 }
450 }
451
452 if (log) {
453 Log.write("Execute ");
454 p.logPhase();
455 }
456
457 /* Execute a single simple scheduled phase */
458 switch (schedule) {
459 /* Global phase */
460 case SCHEDULE_GLOBAL: {
461 if (logDetails) Log.writeln(" as Global...");
462 if (primary) {
463 if (VM.DEBUG) VM.debugging.globalPhase(phaseId,true);
464 plan.collectionPhase(phaseId);
465 if (VM.DEBUG) VM.debugging.globalPhase(phaseId,false);
466 }
467 break;
468 }
469
470 /* Collector phase */
471 case SCHEDULE_COLLECTOR: {
472 if (logDetails) Log.writeln(" as Collector...");
473 if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,true);
474 collector.collectionPhase(phaseId, primary);
475 if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,false);
476 break;
477 }
478
479 /* Mutator phase */
480 case SCHEDULE_MUTATOR: {
481 if (logDetails) Log.writeln(" as Mutator...");
482 /* Iterate through all mutator contexts */
483 MutatorContext mutator;
484 while ((mutator = VM.activePlan.getNextMutator()) != null) {
485 if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),true);
486 mutator.collectionPhase(phaseId, primary);
487 if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),false);
488 }
489 break;
490 }
491
492 /* Concurrent phase */
493 case SCHEDULE_CONCURRENT: {
494 /* We are yielding to a concurrent collection phase */
495 if (logDetails) Log.writeln(" as Concurrent, yielding...");
496 if (primary) {
497 concurrentPhaseId = phaseId;
498 /* Concurrent phase, we need to stop gc */
499 Plan.setGCStatus(Plan.NOT_IN_GC);
500 Plan.controlCollectorContext.requestConcurrentCollection();
501 }
502 collector.rendezvous();
503 if (primary) {
504 pauseComplexTimers();
505 }
506 return;
507 }
508
509 default: {
510 /* getNextPhase has done the wrong thing */
511 VM.assertions.fail("Invalid schedule in Phase.processPhaseStack");
512 break;
513 }
514 }
515
516 if (primary) {
517 /* Set the next phase by processing the stack */
518 int next = getNextPhase();
519 boolean needsResetRendezvous = (next > 0) && (schedule == SCHEDULE_MUTATOR && getSchedule(next) == SCHEDULE_MUTATOR);
520 setNextPhase(isEvenPhase, next, needsResetRendezvous);
521 }
522
523 /* Sync point after execution of a phase */
524 collector.rendezvous();
525
526 /* Mutator phase reset */
527 if (primary && schedule == SCHEDULE_MUTATOR) {
528 VM.activePlan.resetMutatorIterator();
529 }
530
531 /* At this point, in the case of consecutive phases with mutator
532 * scheduling, we have to double-synchronize to ensure all
533 * collector threads see the reset mutator counter. */
534 if (needsMutatorResetRendezvous(isEvenPhase)) {
535 collector.rendezvous();
536 }
537
538 /* Stop the timer(s) */
539 if (primary) {
540 if (p.timer != null) p.timer.stop();
541 if (stopComplexTimer > 0) {
542 Phase.getPhase(stopComplexTimer).timer.stop();
543 stopComplexTimer = 0;
544 }
545 }
546
547 /* Flip the even / odd phase sense */
548 isEvenPhase = !isEvenPhase;
549 resume = false;
550 }
551 }
552
553 /**
554 * Get the next phase.
555 */
556 private static int getCurrentPhase(boolean isEvenPhase) {
557 return isEvenPhase ? evenScheduledPhase : oddScheduledPhase;
558 }
559
560 /**
561 * Do we need a mutator reset rendezvous in this phase?
562 */
563 private static boolean needsMutatorResetRendezvous(boolean isEvenPhase) {
564 return isEvenPhase ? evenMutatorResetRendezvous : oddMutatorResetRendezvous;
565 }
566 /**
567 * Set the next phase. If we are in an even phase the next phase is odd.
568 */
569 private static void setNextPhase(boolean isEvenPhase, int scheduledPhase, boolean needsResetRendezvous) {
570 if (isEvenPhase) {
571 oddScheduledPhase = scheduledPhase;
572 evenMutatorResetRendezvous = needsResetRendezvous;
573 } else {
574 evenScheduledPhase = scheduledPhase;
575 oddMutatorResetRendezvous = needsResetRendezvous;
576 }
577 }
578
579 /**
580 * Pull the next scheduled phase off the stack. This may involve
581 * processing several complex phases and skipping placeholders, etc.
582 *
583 * @return The next phase to run, or -1 if no phases are left.
584 */
585 private static int getNextPhase() {
586 while (phaseStackPointer >= 0) {
587 int scheduledPhase = peekScheduledPhase();
588 short schedule = getSchedule(scheduledPhase);
589 short phaseId = getPhaseId(scheduledPhase);
590
591 switch(schedule) {
592 case SCHEDULE_PLACEHOLDER: {
593 /* Placeholders are ignored and we continue looking */
594 popScheduledPhase();
595 continue;
596 }
597
598 case SCHEDULE_GLOBAL:
599 case SCHEDULE_COLLECTOR:
600 case SCHEDULE_MUTATOR: {
601 /* Simple phases are just popped off the stack and executed */
602 popScheduledPhase();
603 return scheduledPhase;
604 }
605
606 case SCHEDULE_CONCURRENT: {
607 /* Concurrent phases are either popped off or we forward to
608 * an associated non-concurrent phase. */
609 if (!allowConcurrentPhase) {
610 popScheduledPhase();
611 ConcurrentPhase cp = (ConcurrentPhase)getPhase(phaseId);
612 int alternateScheduledPhase = cp.getAtomicScheduledPhase();
613 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(getSchedule(alternateScheduledPhase) != SCHEDULE_CONCURRENT);
614 pushScheduledPhase(alternateScheduledPhase);
615 continue;
616 }
617 if (VM.VERIFY_ASSERTIONS) {
618 /* Concurrent phases can not have a timer */
619 VM.assertions._assert(getPhase(getPhaseId(scheduledPhase)).timer == null);
620 }
621 return scheduledPhase;
622 }
623
624 case SCHEDULE_COMPLEX: {
625 /* A complex phase may either be a newly pushed complex phase,
626 * or a complex phase we are in the process of executing in
627 * which case we move to the next subphase. */
628 ComplexPhase p = (ComplexPhase)getPhase(phaseId);
629 int cursor = incrementComplexPhaseCursor();
630 if (cursor == 0 && p.timer != null) {
631 /* Tell the primary thread to start the timer after the next sync. */
632 startComplexTimer = phaseId;
633 }
634 if (cursor < p.count()) {
635 /* There are more entries, we push the next one and continue */
636 pushScheduledPhase(p.get(cursor));
637 continue;
638 }
639
640 /* We have finished this complex phase */
641 popScheduledPhase();
642 if (p.timer != null) {
643 /* Tell the primary thread to stop the timer after the next sync. */
644 stopComplexTimer = phaseId;
645 }
646 continue;
647 }
648
649 default: {
650 VM.assertions.fail("Invalid phase type encountered");
651 }
652 }
653 }
654 return -1;
655 }
656
657 /**
658 * Pause all of the timers for the complex phases sitting in the stack.
659 */
660 private static void pauseComplexTimers() {
661 for(int i=phaseStackPointer; i >=0; i--) {
662 Phase p = getPhase(getPhaseId(phaseStack[i]));
663 if (p.timer != null) p.timer.stop();
664 }
665 }
666
667 /**
668 * Resume all of the timers for the complex phases sitting in the stack.
669 */
670 private static void resumeComplexTimers() {
671 for(int i=phaseStackPointer; i >=0; i--) {
672 Phase p = getPhase(getPhaseId(phaseStack[i]));
673 if (p.timer != null) p.timer.start();
674 }
675 }
676
677 /**
678 * Return true if phase stack is empty, false otherwise.
679 *
680 * @return true if phase stack is empty, false otherwise.
681 */
682 @Inline
683 public static boolean isPhaseStackEmpty() {
684 return phaseStackPointer < 0;
685 }
686
687 /**
688 * Clears the scheduled phase stack.
689 */
690 @Inline
691 public static void resetPhaseStack() {
692 phaseStackPointer = -1;
693 }
694
695 /**
696 * Push a scheduled phase onto the top of the work stack.
697 *
698 * @param scheduledPhase The scheduled phase.
699 */
700 @Inline
701 public static void pushScheduledPhase(int scheduledPhase) {
702 phaseStack[++phaseStackPointer] = scheduledPhase;
703 complexPhaseCursor[phaseStackPointer] = 0;
704 }
705
706 /**
707 * Increment the cursor associated with the current phase
708 * stack entry. This is used to remember the current sub phase
709 * when executing a complex phase.
710 *
711 * @return The old value of the cursor.
712 */
713 @Inline
714 private static int incrementComplexPhaseCursor() {
715 return complexPhaseCursor[phaseStackPointer]++;
716 }
717
718 /**
719 * Pop off the scheduled phase at the top of the work stack.
720 */
721 @Inline
722 private static int popScheduledPhase() {
723 return phaseStack[phaseStackPointer--];
724 }
725
726 /**
727 * Peek the scheduled phase at the top of the work stack.
728 */
729 @Inline
730 private static int peekScheduledPhase() {
731 return phaseStack[phaseStackPointer];
732 }
733
734 /** The concurrent phase being executed */
735 private static short concurrentPhaseId;
736 /** Do we want to allow new concurrent workers to become active */
737 private static boolean allowConcurrentPhase;
738
739 /**
740 * Get the current phase Id.
741 */
742 public static short getConcurrentPhaseId() {
743 return concurrentPhaseId;
744 }
745
746 /**
747 * Clear the current phase Id.
748 */
749 public static void clearConcurrentPhase() {
750 concurrentPhaseId = 0;
751 }
752
753 /**
754 * @return {@code true}if there is an active concurrent phase.
755 */
756 public static boolean concurrentPhaseActive() {
757 return (concurrentPhaseId > 0);
758 }
759
760 /**
761 * Notify that the concurrent phase has completed successfully. This must
762 * only be called by a single thread after it has determined that the
763 * phase has been completed successfully.
764 */
765 @Unpreemptible
766 public static boolean notifyConcurrentPhaseComplete() {
767 if (Options.verbose.getValue() >= 2) {
768 Log.write("< Concurrent phase ");
769 Log.write(getName(concurrentPhaseId));
770 Log.writeln(" complete >");
771 }
772 /* Concurrent phase is complete*/
773 concurrentPhaseId = 0;
774 /* Remove it from the stack */
775 popScheduledPhase();
776 /* Pop the next phase off the stack */
777 int nextScheduledPhase = getNextPhase();
778
779 if (nextScheduledPhase > 0) {
780 short schedule = getSchedule(nextScheduledPhase);
781
782 /* A concurrent phase, lets wake up and do it all again */
783 if (schedule == SCHEDULE_CONCURRENT) {
784 concurrentPhaseId = getPhaseId(nextScheduledPhase);
785 return true;
786 }
787
788 /* Push phase back on and resume atomic collection */
789 pushScheduledPhase(nextScheduledPhase);
790 Plan.triggerInternalCollectionRequest();
791 }
792 return false;
793 }
794
795 /**
796 * Notify that the concurrent phase has not finished, and must be
797 * re-attempted.
798 */
799 public static void notifyConcurrentPhaseIncomplete() {
800 if (Options.verbose.getValue() >= 2) {
801 Log.write("< Concurrent phase ");
802 Log.write(getName(concurrentPhaseId));
803 Log.writeln(" incomplete >");
804 }
805 }
806 }