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