1 /* 2 * Copyright 2019 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 module hunt.net.buffer.ReferenceCountUpdater; 17 18 import hunt.net.buffer.ByteBuf; 19 import hunt.net.buffer.ReferenceCounted; 20 21 import hunt.net.Exceptions; 22 import core.thread; 23 import core.atomic; 24 25 /** 26 * Common logic for {@link ReferenceCounted} implementations 27 */ 28 abstract class ReferenceCountUpdater(T, string fieldName) 29 if(is(T : ReferenceCounted) && (is(typeof(__traits(getMember, T, fieldName)) == shared(int)))) { 30 /* 31 * Implementation notes: 32 * 33 * For the updated int field: 34 * Even => "real" refcount is (refCnt >>> 1) 35 * Odd => "real" refcount is 0 36 * 37 * (x & y) appears to be surprisingly expensive relative to (x == y). Thus this class uses 38 * a fast-path in some places for most common low values when checking for live (even) refcounts, 39 * for example: if (rawCnt == 2 || rawCnt == 4 || (rawCnt & 1) == 0) { ... 40 */ 41 this() { 42 } 43 44 45 protected abstract AtomicIntegerFieldUpdater!(T, fieldName) updater(); 46 47 // protected abstract long unsafeOffset(); 48 49 final int initialValue() { 50 return 2; 51 } 52 53 private static int realRefCnt(int rawCnt) { 54 return rawCnt != 2 && rawCnt != 4 && (rawCnt & 1) != 0 ? 0 : rawCnt >>> 1; 55 } 56 57 /** 58 * Like {@link #realRefCnt(int)} but throws if refCnt == 0 59 */ 60 private static int toLiveRealRefCnt(int rawCnt, int decrement) { 61 if (rawCnt == 2 || rawCnt == 4 || (rawCnt & 1) == 0) { 62 return rawCnt >>> 1; 63 } 64 // odd rawCnt => already deallocated 65 throw new IllegalReferenceCountException(0, -decrement); 66 } 67 68 private int nonVolatileRawCnt(T instance) { 69 // TODO: Once we compile against later versions of Java we can replace the Unsafe usage here by varhandles. 70 // final long offset = unsafeOffset(); 71 // return offset != -1 ? PlatformDependent.getInt(instance, offset) : updater().get(instance); 72 return __traits(getMember, instance, fieldName); 73 74 } 75 76 final int refCnt(T instance) { 77 return realRefCnt(updater().get(instance)); 78 } 79 80 final bool isLiveNonVolatile(T instance) { 81 int rawCnt = nonVolatileRawCnt(instance); 82 83 // The "real" ref count is > 0 if the rawCnt is even. 84 return rawCnt == 2 || rawCnt == 4 || rawCnt == 6 || rawCnt == 8 || (rawCnt & 1) == 0; 85 } 86 87 /** 88 * An unsafe operation that sets the reference count directly 89 */ 90 final void setRefCnt(T instance, int refCnt) { 91 updater().set(instance, refCnt > 0 ? refCnt << 1 : 1); // overflow OK here 92 } 93 94 /** 95 * Resets the reference count to 1 96 */ 97 final void resetRefCnt(T instance) { 98 updater().set(instance, initialValue()); 99 } 100 101 final T retain(T instance) { 102 return retain0(instance, 1, 2); 103 } 104 105 final T retain(T instance, int increment) { 106 // all changes to the raw count are 2x the "real" change - overflow is OK 107 int rawIncrement = checkPositive(increment, "increment") << 1; 108 return retain0(instance, increment, rawIncrement); 109 } 110 111 // rawIncrement == increment << 1 112 private T retain0(T instance, int increment, int rawIncrement) { 113 int oldRef = updater().getAndAdd(instance, rawIncrement); 114 if (oldRef != 2 && oldRef != 4 && (oldRef & 1) != 0) { 115 throw new IllegalReferenceCountException(0, increment); 116 } 117 // don't pass 0! 118 if ((oldRef <= 0 && oldRef + rawIncrement >= 0) 119 || (oldRef >= 0 && oldRef + rawIncrement < oldRef)) { 120 // overflow case 121 updater().getAndAdd(instance, -rawIncrement); 122 throw new IllegalReferenceCountException(realRefCnt(oldRef), increment); 123 } 124 return instance; 125 } 126 127 final bool release(T instance) { 128 int rawCnt = nonVolatileRawCnt(instance); 129 return rawCnt == 2 ? tryFinalRelease0(instance, 2) || retryRelease0(instance, 1) 130 : nonFinalRelease0(instance, 1, rawCnt, toLiveRealRefCnt(rawCnt, 1)); 131 } 132 133 final bool release(T instance, int decrement) { 134 int rawCnt = nonVolatileRawCnt(instance); 135 int realCnt = toLiveRealRefCnt(rawCnt, checkPositive(decrement, "decrement")); 136 return decrement == realCnt ? tryFinalRelease0(instance, rawCnt) || retryRelease0(instance, decrement) 137 : nonFinalRelease0(instance, decrement, rawCnt, realCnt); 138 } 139 140 private bool tryFinalRelease0(T instance, int expectRawCnt) { 141 return updater().compareAndSet(instance, expectRawCnt, 1); // any odd number will work 142 } 143 144 private bool nonFinalRelease0(T instance, int decrement, int rawCnt, int realCnt) { 145 if (decrement < realCnt 146 // all changes to the raw count are 2x the "real" change - overflow is OK 147 && updater().compareAndSet(instance, rawCnt, rawCnt - (decrement << 1))) { 148 return false; 149 } 150 return retryRelease0(instance, decrement); 151 } 152 153 private bool retryRelease0(T instance, int decrement) { 154 for (;;) { 155 int rawCnt = updater().get(instance), realCnt = toLiveRealRefCnt(rawCnt, decrement); 156 if (decrement == realCnt) { 157 if (tryFinalRelease0(instance, rawCnt)) { 158 return true; 159 } 160 } else if (decrement < realCnt) { 161 // all changes to the raw count are 2x the "real" change 162 if (updater().compareAndSet(instance, rawCnt, rawCnt - (decrement << 1))) { 163 return false; 164 } 165 } else { 166 throw new IllegalReferenceCountException(realCnt, -decrement); 167 } 168 Thread.yield(); // this benefits throughput under high contention 169 } 170 } 171 } 172 173 174 175 /** 176 * A reflection-based utility that enables atomic updates to 177 * designated {@code volatile int} fields of designated classes. 178 * This class is designed for use in atomic data structures in which 179 * several fields of the same node are independently subject to atomic 180 * updates. 181 * 182 * <p>Note that the guarantees of the {@code compareAndSet} 183 * method in this class are weaker than in other atomic classes. 184 * Because this class cannot ensure that all uses of the field 185 * are appropriate for purposes of atomic access, it can 186 * guarantee atomicity only with respect to other invocations of 187 * {@code compareAndSet} and {@code set} on the same updater. 188 * 189 * <p>Object arguments for parameters of type {@code T} that are not 190 * instances of the class passed to {@link #newUpdater} will result in 191 * a {@link ClassCastException} being thrown. 192 * 193 * @author Doug Lea 194 * @param <T> The type of the object holding the updatable field 195 */ 196 class AtomicIntegerFieldUpdater(T, string fieldName) 197 if (is(typeof(__traits(getMember, T, fieldName)) == shared(int))) { 198 199 /** 200 * Atomically sets the field of the given object managed by this updater 201 * to the given updated value if the current value {@code ==} the 202 * expected value. This method is guaranteed to be atomic with respect to 203 * other calls to {@code compareAndSet} and {@code set}, but not 204 * necessarily with respect to other changes in the field. 205 * 206 * @param obj An object whose field to conditionally set 207 * @param expect the expected value 208 * @param update the new value 209 * @return {@code true} if successful 210 */ 211 bool compareAndSet(T obj, int expect, int update) { 212 return cas(&__traits(getMember, obj, fieldName), expect, update); 213 } 214 215 /** 216 * Returns the current value held in the field of the given object 217 * managed by this updater. 218 * 219 * @param obj An object whose field to get 220 * @return the current value 221 */ 222 int get(T obj) { 223 // return __traits(getMember, obj, fieldName); 224 return atomicLoad(__traits(getMember, obj, fieldName)); 225 } 226 227 228 /** 229 * Sets the field of the given object managed by this updater to the 230 * given updated value. This operation is guaranteed to act as a volatile 231 * store with respect to subsequent invocations of {@code compareAndSet}. 232 * 233 * @param obj An object whose field to set 234 * @param newValue the new value 235 */ 236 void set(T obj, int newValue) { 237 atomicStore(__traits(getMember, obj, fieldName), newValue); 238 } 239 240 /** 241 * Atomically adds the given value to the current value of the field of 242 * the given object managed by this updater. 243 * 244 * @param obj An object whose field to get and set 245 * @param delta the value to add 246 * @return the previous value 247 */ 248 int getAndAdd(T obj, int delta) { 249 int prev, next; 250 do { 251 prev = get(obj); 252 next = prev + delta; 253 } while (!compareAndSet(obj, prev, next)); 254 return prev; 255 } 256 257 258 /** 259 * Atomically increments by one the current value of the field of the 260 * given object managed by this updater. 261 * 262 * @param obj An object whose field to get and set 263 * @return the updated value 264 */ 265 int incrementAndGet(T obj) { 266 int prev, next; 267 do { 268 prev = get(obj); 269 next = prev + 1; 270 } while (!compareAndSet(obj, prev, next)); 271 return next; 272 } 273 274 /** 275 * Atomically decrements by one the current value of the field of the 276 * given object managed by this updater. 277 * 278 * @param obj An object whose field to get and set 279 * @return the updated value 280 */ 281 int decrementAndGet(T obj) { 282 int prev, next; 283 do { 284 prev = get(obj); 285 next = prev - 1; 286 } while (!compareAndSet(obj, prev, next)); 287 return next; 288 } 289 290 }