<div dir="ltr"><div>Hi, </div>I have also been looking into deterministic simulation on the side and belatedly saw some interest about it on the loom email list with the "Custom scheduler: Customize current time and timed waits" thread. I wanted to briefly expand on the topic of using Loom to make deterministic simulation testing more easily available to the java community.<div><br></div><div><div>BLUF:
Deterministic simulation testing makes multi threaded logic single threaded and fuzz tests the execution order, greatly simplifying discovery of race conditions and deadlocks. See this blog post by <a href="https://aoli.al/blogs/jdk-bug/">Ao Li</a> for an example doing this in java and the paper behind it <a href="https://arxiv.org/abs/2501.12618"> Fray: An Efficient General-Purpose Concurrency Testing Platform for the JVM</a>.</div><div><br></div><div>The above explanation omits how hard it is to actually make java or any language deterministic. This is where<a href="https://jbaker.io/2022/05/09/project-loom-for-distributed-systems/"> James Baker had a clever idea</a> of using Loom, since we could replace the virtual thread scheduler with a deterministic one, Loom does most of the work for us without any extra frameworks. This works brilliantly, however there are three main caveats:</div><div><ol><li>Its not easy to replace the virtual thread scheduler</li><li>The aforementioned scheduler has no understanding of delays so any Thread.sleep or Object.wait introduces continuations back into the scheduled execution pool non-deterministically. This affects the execution order so bugs can't always be reproduced.</li><li>IO also introduces continuations back to the scheduler execution pool non-deterministically.</li></ol><div>The first issue can currently be solved by using reflection to make the <a href="https://github.com/ryeats/loom-dst/blob/main/src/main/java/org/example/SchedulableVirtualThreadFactory.java">virtual thread constructor public</a>. The second issue can currently be solved by controlling system time by replacing the byte code for all calls to System.nanoTime(), System.onCurrentTimeMillis() and Instant.now() <a href="https://github.com/cmu-pasta/fray/blob/main/instrumentation/base/src/main/kotlin/org/pastalab/fray/instrumentation/base/visitors/TimeInstrumenter.kt">using an agent at runtime</a>. The third likely has no general solution but I am interested in hearing ideas.</div></div><div><br></div><div>Even if there is no solution to IO non-determinism and developers have to stub out all IO, deterministic simulation is still an incredibly promising tool for making concurrent and distributed systems programing much simpler and safer. I think because of this use case there would be a lot of benefit if the Loom API allowed instrumenting the scheduler, even better if we could access the DELAYED_TASK_SCHEDULERS which understand delays. </div><div><br></div><div>Thank you for your time, I have been super excited to use virtual threads and amazed by the ingenuity that brought them to java.</div><div><br></div><div>Ryan</div><div><br></div><div><br></div></div></div>