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
27
28 @Deprecated
29 public abstract class ReferenceCountUpdater<T extends ReferenceCounted> {
30
31
32
33
34
35
36
37
38 protected ReferenceCountUpdater() {
39 }
40
41 protected abstract void safeInitializeRawRefCnt(T refCntObj, int value);
42
43 protected abstract int getAndAddRawRefCnt(T refCntObj, int increment);
44
45 protected abstract int getRawRefCnt(T refCnt);
46
47 protected abstract int getAcquireRawRefCnt(T refCnt);
48
49 protected abstract void setReleaseRawRefCnt(T refCnt, int value);
50
51 protected abstract boolean casRawRefCnt(T refCnt, int expected, int value);
52
53 public final int initialValue() {
54 return 2;
55 }
56
57 public final void setInitialValue(T instance) {
58 safeInitializeRawRefCnt(instance, initialValue());
59 }
60
61 private static int realRefCnt(int rawCnt) {
62 return rawCnt >>> 1;
63 }
64
65 public final int refCnt(T instance) {
66 return realRefCnt(getAcquireRawRefCnt(instance));
67 }
68
69 public final boolean isLiveNonVolatile(T instance) {
70 final int rawCnt = getRawRefCnt(instance);
71 if (rawCnt == 2) {
72 return true;
73 }
74 return (rawCnt & 1) == 0;
75 }
76
77
78
79
80 public final void setRefCnt(T instance, int refCnt) {
81 int rawRefCnt = refCnt > 0 ? refCnt << 1 : 1;
82 setReleaseRawRefCnt(instance, rawRefCnt);
83 }
84
85
86
87
88 public final void resetRefCnt(T instance) {
89
90 setReleaseRawRefCnt(instance, initialValue());
91 }
92
93 public final T retain(T instance) {
94 return retain0(instance, 2);
95 }
96
97 public final T retain(T instance, int increment) {
98 return retain0(instance, checkPositive(increment, "increment") << 1);
99 }
100
101 private T retain0(T instance, int increment) {
102 int oldRef = getAndAddRawRefCnt(instance, increment);
103
104
105
106 if ((oldRef & 0x80000001) != 0 || oldRef > Integer.MAX_VALUE - increment) {
107 getAndAddRawRefCnt(instance, -increment);
108 throw new IllegalReferenceCountException(0, increment >>> 1);
109 }
110 return instance;
111 }
112
113 public final boolean release(T instance) {
114 return release0(instance, 2);
115 }
116
117 public final boolean release(T instance, int decrement) {
118 return release0(instance, checkPositive(decrement, "decrement") << 1);
119 }
120
121 private boolean release0(final T instance, final int decrement) {
122 int curr, next;
123 do {
124 curr = getRawRefCnt(instance);
125 if (curr == decrement) {
126 next = 1;
127 } else {
128 if (curr < decrement || (curr & 1) == 1) {
129 throwIllegalRefCountOnRelease(decrement, curr);
130 }
131 next = curr - decrement;
132 }
133 } while (!casRawRefCnt(instance, curr, next));
134 return (next & 1) == 1;
135 }
136
137 private static void throwIllegalRefCountOnRelease(int decrement, int curr) {
138 throw new IllegalReferenceCountException(curr >>> 1, -(decrement >>> 1));
139 }
140
141 public enum UpdaterType {
142 Unsafe,
143 VarHandle,
144 Atomic
145 }
146
147 public static <T extends ReferenceCounted> UpdaterType updaterTypeOf(Class<T> clz, String fieldName) {
148 long fieldOffset = getUnsafeOffset(clz, fieldName);
149 if (fieldOffset >= 0) {
150 return UpdaterType.Unsafe;
151 }
152 if (PlatformDependent.hasVarHandle()) {
153 return UpdaterType.VarHandle;
154 }
155 return UpdaterType.Atomic;
156 }
157
158 public static long getUnsafeOffset(Class<? extends ReferenceCounted> clz, String fieldName) {
159 try {
160 if (PlatformDependent.hasUnsafe()) {
161 return PlatformDependent.objectFieldOffset(clz.getDeclaredField(fieldName));
162 }
163 } catch (Throwable ignore) {
164
165 }
166 return -1;
167 }
168 }