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 }