Fix a race condition in reference counter implementation / Reference count never goes below 0

This commit is contained in:
Trustin Lee 2013-02-10 14:22:14 +09:00
parent bd0729ac45
commit 4f6d05365a
7 changed files with 32 additions and 20 deletions

View File

@ -1032,7 +1032,7 @@ public abstract class AbstractByteBuf implements ByteBuf {
}
protected final void ensureAccessible() {
if (refCnt() <= 0) {
if (refCnt() == 0) {
throw new IllegalBufferAccessException();
}
}

View File

@ -32,15 +32,18 @@ public abstract class AbstractReferenceCounted implements ReferenceCounted {
@Override
public final void retain() {
do {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + 1));
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) {
break;
}
}
}
@Override
@ -49,22 +52,25 @@ public abstract class AbstractReferenceCounted implements ReferenceCounted {
throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)");
}
do {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}
if (refCnt > Integer.MAX_VALUE - increment) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + increment));
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + increment)) {
break;
}
}
}
@Override
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}

View File

@ -37,15 +37,18 @@ public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
@Override
public final void retain() {
do {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}
if (refCnt == Integer.MAX_VALUE) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + 1));
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) {
break;
}
}
}
@Override
@ -54,22 +57,25 @@ public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)");
}
do {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}
if (refCnt > Integer.MAX_VALUE - increment) {
throw new IllegalBufferAccessException("refCnt overflow");
}
} while (!refCntUpdater.compareAndSet(this, refCnt, refCnt + increment));
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + increment)) {
break;
}
}
}
@Override
public final boolean release() {
for (;;) {
int refCnt = this.refCnt;
if (refCnt <= 0) {
if (refCnt == 0) {
throw new IllegalBufferAccessException();
}

View File

@ -101,7 +101,7 @@ public class DefaultSpdyDataFrame extends DefaultByteBufHolder implements SpdyDa
buf.append(streamId);
buf.append(StringUtil.NEWLINE);
buf.append("--> Size = ");
if (refCnt() <= 0) {
if (refCnt() == 0) {
buf.append("(freed)");
} else {
buf.append(data().readableBytes());

View File

@ -137,7 +137,7 @@ public final class SctpMessage extends DefaultByteBufHolder {
@Override
public String toString() {
if (refCnt() <= 0) {
if (refCnt() == 0) {
return "SctpFrame{" +
"streamIdentifier=" + streamIdentifier + ", protocolIdentifier=" + protocolIdentifier +
", data=(FREED)}";

View File

@ -57,7 +57,7 @@ public final class DatagramPacket extends DefaultByteBufHolder {
@Override
public String toString() {
if (refCnt() <= 0) {
if (refCnt() == 0) {
return "DatagramPacket{remoteAddress=" + remoteAddress().toString() +
", data=(FREED)}";
}

View File

@ -254,7 +254,7 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
try {
if (buf.isReadable()) {
for (;;) {
if (buf.refCnt() <= 0) {
if (buf.refCnt() == 0) {
break;
}
// Ensure the readerIndex of the buffer is 0 before beginning an async write.
@ -370,7 +370,7 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
channel.writeInProgress = false;
ByteBuf buf = channel.unsafe().directOutboundContext().outboundByteBuffer();
if (buf.refCnt() <= 0) {
if (buf.refCnt() == 0) {
return;
}