Skip to content

Commit

Permalink
Add Blockhound exceptions for the PooledByteBufAllocator (netty#12653)
Browse files Browse the repository at this point in the history
Motivation:
In netty#12622 we replaced a number of synchronised blocks with explicit locks.
It turns out that blockhound ignores synchronised blocks for some reason, and now complain about the explicit locks.

Modification:
Add exceptions and allow blocking calls in select methods in the PooledByteBufAllocator.
Also add a test that create races inside the pooled allocator in an attempt to get the thread blocked on the locks while blockhound is watching.

Result:
No more blockhound complaints.
  • Loading branch information
chrisvest authored Jul 29, 2022
1 parent 8b2297b commit 1147628
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
20 changes: 20 additions & 0 deletions common/src/main/java/io/netty/util/internal/Hidden.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ public void applyTo(BlockHound.Builder builder) {
"confirmShutdown"
);

builder.allowBlockingCallsInside(
"io.netty.buffer.PoolArena",
"lock"
);

builder.allowBlockingCallsInside(
"io.netty.buffer.PoolSubpage",
"lock"
);

builder.allowBlockingCallsInside(
"io.netty.buffer.PoolChunk",
"allocateRun"
);

builder.allowBlockingCallsInside(
"io.netty.buffer.PoolChunk",
"free"
);

builder.allowBlockingCallsInside(
"io.netty.handler.ssl.SslHandler",
"handshake"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
Expand All @@ -42,6 +44,7 @@
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.FastThreadLocalThread;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.ImmediateExecutor;
Expand Down Expand Up @@ -72,6 +75,7 @@
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;

Expand Down Expand Up @@ -343,6 +347,36 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
}
}

@Test
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void pooledBufferAllocation() throws Exception {
AtomicLong iterationCounter = new AtomicLong();
PooledByteBufAllocator allocator = PooledByteBufAllocator.DEFAULT;
FutureTask<Void> task = new FutureTask<>(() -> {
List<ByteBuf> buffers = new ArrayList<>();
long count;
do {
count = iterationCounter.get();
} while (count == 0);
for (int i = 0; i < 13; i++) {
int size = 8 << i;
buffers.add(allocator.ioBuffer(size, size));
}
for (ByteBuf buffer : buffers) {
buffer.release();
}
return null;
});
FastThreadLocalThread thread = new FastThreadLocalThread(task);
thread.start();
do {
allocator.dumpStats(); // This will take internal pool locks and we'll race with the thread.
iterationCounter.set(1);
} while (thread.isAlive());
thread.join();
task.get();
}

@Test
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS)
public void testUnixResolverDnsServerAddressStreamProvider_Parse() throws InterruptedException {
Expand Down

0 comments on commit 1147628

Please sign in to comment.