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 }