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 }