View Javadoc
1   /*
2    * Copyright 2013 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    *   https://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  
17  package io.netty.buffer;
18  
19  import java.lang.invoke.MethodHandles;
20  import java.lang.invoke.VarHandle;
21  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
22  
23  import io.netty.util.internal.AtomicReferenceCountUpdater;
24  import io.netty.util.internal.PlatformDependent;
25  import io.netty.util.internal.ReferenceCountUpdater;
26  import io.netty.util.internal.ReferenceCountUpdater.UpdaterType;
27  import io.netty.util.internal.UnsafeReferenceCountUpdater;
28  import io.netty.util.internal.VarHandleReferenceCountUpdater;
29  
30  import static io.netty.util.internal.ReferenceCountUpdater.getUnsafeOffset;
31  import static java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater;
32  
33  /**
34   * Abstract base class for {@link ByteBuf} implementations that count references.
35   */
36  public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
37      private static final long REFCNT_FIELD_OFFSET;
38      private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> AIF_UPDATER;
39      private static final Object REFCNT_FIELD_VH;
40      private static final ReferenceCountUpdater<AbstractReferenceCountedByteBuf> updater;
41  
42      static {
43          UpdaterType updaterType = ReferenceCountUpdater.updaterTypeOf(AbstractReferenceCountedByteBuf.class, "refCnt");
44          switch (updaterType) {
45              case Atomic:
46                  AIF_UPDATER = newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");
47                  REFCNT_FIELD_OFFSET = -1;
48                  REFCNT_FIELD_VH = null;
49                  updater = new AtomicReferenceCountUpdater<AbstractReferenceCountedByteBuf>() {
50                      @Override
51                      protected AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> updater() {
52                          return AIF_UPDATER;
53                      }
54                  };
55                  break;
56              case Unsafe:
57                  AIF_UPDATER = null;
58                  REFCNT_FIELD_OFFSET = getUnsafeOffset(AbstractReferenceCountedByteBuf.class, "refCnt");
59                  REFCNT_FIELD_VH = null;
60                  updater = new UnsafeReferenceCountUpdater<AbstractReferenceCountedByteBuf>() {
61                      @Override
62                      protected long refCntFieldOffset() {
63                          return REFCNT_FIELD_OFFSET;
64                      }
65                  };
66                  break;
67              case VarHandle:
68                  AIF_UPDATER = null;
69                  REFCNT_FIELD_OFFSET = -1;
70                  REFCNT_FIELD_VH = PlatformDependent.findVarHandleOfIntField(MethodHandles.lookup(),
71                          AbstractReferenceCountedByteBuf.class, "refCnt");
72                  updater = new VarHandleReferenceCountUpdater<AbstractReferenceCountedByteBuf>() {
73                      @Override
74                      protected VarHandle varHandle() {
75                          return (VarHandle) REFCNT_FIELD_VH;
76                      }
77                  };
78                  break;
79              default:
80                  throw new Error("Unexpected updater type for AbstractReferenceCountedByteBuf: " + updaterType);
81          }
82      }
83  
84      // Value might not equal "real" reference count, all access should be via the updater
85      @SuppressWarnings({"unused", "FieldMayBeFinal"})
86      private volatile int refCnt;
87  
88      protected AbstractReferenceCountedByteBuf(int maxCapacity) {
89          super(maxCapacity);
90          updater.setInitialValue(this);
91      }
92  
93      @Override
94      boolean isAccessible() {
95          // Try to do non-volatile read for performance as the ensureAccessible() is racy anyway and only provide
96          // a best-effort guard.
97          return updater.isLiveNonVolatile(this);
98      }
99  
100     @Override
101     public int refCnt() {
102         return updater.refCnt(this);
103     }
104 
105     /**
106      * An unsafe operation intended for use by a subclass that sets the reference count of the buffer directly
107      */
108     protected final void setRefCnt(int refCnt) {
109         updater.setRefCnt(this, refCnt);
110     }
111 
112     /**
113      * An unsafe operation intended for use by a subclass that resets the reference count of the buffer to 1
114      */
115     protected final void resetRefCnt() {
116         updater.resetRefCnt(this);
117     }
118 
119     @Override
120     public ByteBuf retain() {
121         return updater.retain(this);
122     }
123 
124     @Override
125     public ByteBuf retain(int increment) {
126         return updater.retain(this, increment);
127     }
128 
129     @Override
130     public ByteBuf touch() {
131         return this;
132     }
133 
134     @Override
135     public ByteBuf touch(Object hint) {
136         return this;
137     }
138 
139     @Override
140     public boolean release() {
141         return handleRelease(updater.release(this));
142     }
143 
144     @Override
145     public boolean release(int decrement) {
146         return handleRelease(updater.release(this, decrement));
147     }
148 
149     private boolean handleRelease(boolean result) {
150         if (result) {
151             deallocate();
152         }
153         return result;
154     }
155 
156     /**
157      * Called once {@link #refCnt()} is equals 0.
158      */
159     protected abstract void deallocate();
160 }