Skip to content

Commit e9f5a67

Browse files
committed
Improve documentation and add test for virtual thread progress in closed event loop
1 parent f8d4456 commit e9f5a67

2 files changed

Lines changed: 21 additions & 7 deletions

File tree

core/src/main/java/io/netty/loom/EventLoopScheduler.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ public EventLoopScheduler get() {
2626
}
2727

2828
/**
29-
* PerCarrier Read-Sub-Pollers are not created through the vThreadFactory and although the NettyScheduler
30-
* can dynamically assign them to this scheduler, while running, won't see this scheduler as the current one.
31-
* This means that if they try to unpark some virtual thread which belong to this scheduler,
32-
* they can still wakeup the carrier thread. It's more a performance defect, but won't affect correctness.
29+
* We currently lack a way to query the current thread's assigned scheduler: this is a workaround using ScopedValues.<br>
30+
* The same functionality could have been achieved (in a less hacky way) using ThreadLocals, which are way more expensive, for VirtualThreads.<br>
31+
* Read sub-poller(s) sadly won't work as expected with this, because are not created using the event loop scheduler factory.
3332
*/
3433
public record SchedulingContext(long vThreadId, SharedRef scheduler) {
3534

@@ -163,8 +162,8 @@ private void virtualThreadSchedulerLoop() {
163162
parkedCarrierThread = null;
164163
}
165164
}
166-
// make sure the event loop thread is fully terminated
167-
while (eventLoopThread.isAlive()) {
165+
// make sure the event loop thread is fully terminated and all tasks are run
166+
while (eventLoopThread.isAlive() || !canBlock()) {
168167
runExternalContinuations(RUNNING_YIELD_US);
169168
runEventLoopContinuation();
170169
}

core/src/test/java/io/netty/loom/VirtualMultithreadIoEventLoopGroupTest.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import static java.util.concurrent.StructuredTaskScope.Joiner.allSuccessfulOrThrow;
44
import static org.junit.jupiter.api.Assertions.*;
5-
import static org.junit.jupiter.api.Assumptions.assumeTrue;
65

76
import java.net.InetSocketAddress;
87
import java.net.URI;
@@ -367,6 +366,22 @@ void schedulerIsNotInheritedByForkedVT() throws InterruptedException, ExecutionE
367366
}
368367
}
369368

369+
@Test
370+
void virtualThreadCanMakeProgressEvenIfEventLoopIsClosed() throws InterruptedException, ExecutionException, BrokenBarrierException, TimeoutException {
371+
var group = new VirtualMultithreadIoEventLoopGroup(1, LocalIoHandler.newFactory());
372+
final var barrier = new CyclicBarrier(2);
373+
final var vThreadFactory = group.submit(group::vThreadFactory).get();
374+
vThreadFactory.newThread(() -> {
375+
try {
376+
group.shutdownGracefully().get();
377+
barrier.await();
378+
} catch (Throwable e) {
379+
// ignore
380+
}
381+
}).start();
382+
barrier.await(5, TimeUnit.SECONDS);
383+
}
384+
370385
@Test
371386
void eventLoopSchedulerCanMakeProgressIfTheEventLoopIsBlocked() throws BrokenBarrierException, InterruptedException, TimeoutException {
372387
var group = new VirtualMultithreadIoEventLoopGroup(1, NioIoHandler.newFactory());

0 commit comments

Comments
 (0)