1 /* 2 * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 24 #include "precompiled.hpp" 25 26 #include "gc/shenandoah/shenandoahPhaser.hpp" 27 #include "runtime/atomic.hpp" 28 29 30 // Implementation of ShenandoahPhaser 31 ShenandoahPhaser::ShenandoahPhaser(int parties) { 32 assert(((unsigned int)parties) >> PARTIES_SHIFT == 0, 33 "Illegal number of parties"); 34 int phase = 0; 35 _state = (parties == 0) ? (long)EMPTY : 36 ((long)phase << PHASE_SHIFT) | 37 ((long)parties << PARTIES_SHIFT) | 38 ((long)parties); 39 } 40 41 42 int ShenandoahPhaser::do_arrive(int adjust) { 43 for (;;) { 44 jlong s = _state; 45 int phase = phase_of(s); 46 if (phase < 0) return phase; 47 48 int counts = (int)s; 49 int unarrived = unarrived_of(s); 50 51 assert(unarrived > 0, "Bad arrive: attempted arrival of unregistered party [phase = %d" 52 " parites = %d arrived = %d", phase_of(s), parties_of(s), arrived_of(s)); 53 54 if (s == Atomic::cmpxchg((s - adjust), &_state, s)) { 55 s -= adjust; 56 if (unarrived == 1) { 57 jlong n = s & PARTIES_MARK; 58 int nextUnarrived = ((unsigned int)n) >> PARTIES_SHIFT; 59 if (onAdvance(phase, nextUnarrived)) { 60 n |= TERMINATION_BIT; 61 } else if (nextUnarrived == 0) { 62 n |= EMPTY; 63 } else { 64 n |= nextUnarrived; 65 } 66 67 int nextPhase = (phase + 1) & MAX_PHASE; 68 n |= ((jlong)nextPhase) << PHASE_SHIFT; 69 70 Atomic::cmpxchg(n, &_state, s); 71 releaseWaiters(phase); 72 } 73 return phase; 74 } 75 } 76 } 77 78 79 int ShenandoahPhaser::arriveAndAwaitAdvance() { 80 for (;;) { 81 jlong s = _state; 82 int phase = phase_of(s); 83 // Terminated 84 if (phase < 0) return phase; 85 86 int counts = (int)s; 87 int unarrived = unarrived_of(s); 88 89 assert(unarrived > 0, "Bad arrive: attempted arrival of unregistered party [phase = %d" 90 " parites = %d arrived = %d", phase_of(s), parties_of(s), arrived_of(s)); 91 92 if (s == Atomic::cmpxchg((s - ONE_ARRIVAL), &_state, s)) { 93 s -= ONE_ARRIVAL; 94 if (unarrived > 1) { 95 return blockWaiters(phase); 96 } else { 97 // the last one to arrive 98 long n = s & PARTIES_MARK; 99 int nextUnarrived = parties_of(s); 100 101 if (onAdvance(phase, nextUnarrived)) { 102 n |= TERMINATION_BIT; 103 } else if (nextUnarrived == 0) { 104 n |= EMPTY; 105 } else { 106 n |= (long)nextUnarrived; 107 } 108 109 int nextPhase = (phase + 1) & MAX_PHASE; 110 n |= (long)nextPhase << PHASE_SHIFT; 111 112 if (Atomic::cmpxchg(n, &_state, s) != s) { 113 // terminated 114 return phase_of(_state); 115 } 116 117 releaseWaiters(phase); 118 return nextPhase; 119 } 120 } 121 } 122 } 123 124 int ShenandoahPhaser::do_register(int registrations) { 125 jlong adjust = (((jlong)registrations) << PARTIES_SHIFT) | registrations; 126 int phase; 127 for (;;) { 128 jlong s = _state; 129 int counts = (int)s; 130 int parties = parties_of(s); 131 int unarrived = unarrived_of(s); 132 assert(registrations <= MAX_PARTIES - parties, "Too many parties"); 133 phase = phase_of(s); 134 if (phase < 0) { 135 break; 136 } 137 138 if (counts != EMPTY) { 139 if (unarrived == 0) { 140 blockWaiters(phase); // wait out advance 141 } else if (Atomic::cmpxchg((s + adjust), &_state, s) == s) { 142 break; 143 } 144 } else { 145 // 1st registration 146 jlong next = ((jlong)phase << PHASE_SHIFT) | adjust; 147 if (Atomic::cmpxchg(next, &_state, s) == s) { 148 break; 149 } 150 } 151 } 152 return phase; 153 }