1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.util.internal;
17
18 import static io.netty.util.internal.ObjectUtil.checkPositive;
19
20 import io.netty.util.IllegalReferenceCountException;
21 import io.netty.util.ReferenceCounted;
22
23
24
25
26 public abstract class ReferenceCountUpdater<T extends ReferenceCounted> {
27
28
29
30
31
32
33
34
35
36
37
38
39 protected ReferenceCountUpdater() {
40 }
41
42 protected abstract void safeInitializeRawRefCnt(T refCntObj, int value);
43
44 protected abstract int getAndAddRawRefCnt(T refCntObj, int increment);
45
46 protected abstract int getRawRefCnt(T refCnt);
47
48 protected abstract int getAcquireRawRefCnt(T refCnt);
49
50 protected abstract void setReleaseRawRefCnt(T refCnt, int value);
51
52 protected abstract boolean casRawRefCnt(T refCnt, int expected, int value);
53
54 public final int initialValue() {
55 return 2;
56 }
57
58 public final void setInitialValue(T instance) {
59 safeInitializeRawRefCnt(instance, initialValue());
60 }
61
62 private static int realRefCnt(int rawCnt) {
63 return rawCnt != 2 && rawCnt != 4 && (rawCnt & 1) != 0 ? 0 : rawCnt >>> 1;
64 }
65
66
67
68
69 private static int toLiveRealRefCnt(int rawCnt, int decrement) {
70 if (rawCnt == 2 || rawCnt == 4 || (rawCnt & 1) == 0) {
71 return rawCnt >>> 1;
72 }
73
74 throw new IllegalReferenceCountException(0, -decrement);
75 }
76
77 public final int refCnt(T instance) {
78 return realRefCnt(getAcquireRawRefCnt(instance));
79 }
80
81 public final boolean isLiveNonVolatile(T instance) {
82 final int rawCnt = getRawRefCnt(instance);
83
84 return rawCnt == 2 || rawCnt == 4 || rawCnt == 6 || rawCnt == 8 || (rawCnt & 1) == 0;
85 }
86
87
88
89
90 public final void setRefCnt(T instance, int refCnt) {
91 int rawRefCnt = refCnt > 0 ? refCnt << 1 : 1;
92 setReleaseRawRefCnt(instance, rawRefCnt);
93 }
94
95
96
97
98 public final void resetRefCnt(T instance) {
99
100 setReleaseRawRefCnt(instance, initialValue());
101 }
102
103 public final T retain(T instance) {
104 return retain0(instance, 1, 2);
105 }
106
107 public final T retain(T instance, int increment) {
108
109 int rawIncrement = checkPositive(increment, "increment") << 1;
110 return retain0(instance, increment, rawIncrement);
111 }
112
113
114 private T retain0(T instance, final int increment, final int rawIncrement) {
115 int oldRef = getAndAddRawRefCnt(instance, rawIncrement);
116 if (oldRef != 2 && oldRef != 4 && (oldRef & 1) != 0) {
117 throw new IllegalReferenceCountException(0, increment);
118 }
119
120 if ((oldRef <= 0 && oldRef + rawIncrement >= 0)
121 || (oldRef >= 0 && oldRef + rawIncrement < oldRef)) {
122
123 getAndAddRawRefCnt(instance, -rawIncrement);
124 throw new IllegalReferenceCountException(realRefCnt(oldRef), increment);
125 }
126 return instance;
127 }
128
129 public final boolean release(T instance) {
130 int rawCnt = getRawRefCnt(instance);
131 return rawCnt == 2 ? tryFinalRelease0(instance, 2) || retryRelease0(instance, 1)
132 : nonFinalRelease0(instance, 1, rawCnt, toLiveRealRefCnt(rawCnt, 1));
133 }
134
135 public final boolean release(T instance, int decrement) {
136 int rawCnt = getRawRefCnt(instance);
137 int realCnt = toLiveRealRefCnt(rawCnt, checkPositive(decrement, "decrement"));
138 return decrement == realCnt ? tryFinalRelease0(instance, rawCnt) || retryRelease0(instance, decrement)
139 : nonFinalRelease0(instance, decrement, rawCnt, realCnt);
140 }
141
142 private boolean tryFinalRelease0(T instance, int expectRawCnt) {
143 return casRawRefCnt(instance, expectRawCnt, 1);
144 }
145
146 private boolean nonFinalRelease0(T instance, int decrement, int rawCnt, int realCnt) {
147 if (decrement < realCnt
148
149 && casRawRefCnt(instance, rawCnt, rawCnt - (decrement << 1))) {
150 return false;
151 }
152 return retryRelease0(instance, decrement);
153 }
154
155 private boolean retryRelease0(T instance, int decrement) {
156 for (;;) {
157 int rawCnt = getRawRefCnt(instance), realCnt = toLiveRealRefCnt(rawCnt, decrement);
158 if (decrement == realCnt) {
159 if (tryFinalRelease0(instance, rawCnt)) {
160 return true;
161 }
162 } else if (decrement < realCnt) {
163
164 if (casRawRefCnt(instance, rawCnt, rawCnt - (decrement << 1))) {
165 return false;
166 }
167 } else {
168 throw new IllegalReferenceCountException(realCnt, -decrement);
169 }
170 Thread.yield();
171 }
172 }
173
174 public enum UpdaterType {
175 Unsafe,
176 VarHandle,
177 Atomic
178 }
179
180 public static <T extends ReferenceCounted> UpdaterType updaterTypeOf(Class<T> clz, String fieldName) {
181 long fieldOffset = getUnsafeOffset(clz, fieldName);
182 if (fieldOffset >= 0) {
183 return UpdaterType.Unsafe;
184 }
185 if (PlatformDependent.hasVarHandle()) {
186 return UpdaterType.VarHandle;
187 }
188 return UpdaterType.Atomic;
189 }
190
191 public static long getUnsafeOffset(Class<? extends ReferenceCounted> clz, String fieldName) {
192 try {
193 if (PlatformDependent.hasUnsafe()) {
194 return PlatformDependent.objectFieldOffset(clz.getDeclaredField(fieldName));
195 }
196 } catch (Throwable ignore) {
197
198 }
199 return -1;
200 }
201 }