Evil Scheduler: Mastering Concurrency Through Interactive Debugging

TLDR

Watch the video below to see how Fray debugger works!

I enjoy the concept of Deadlock Empire, an interactive game that teaches the semantics of locks and other concurrency primitives. The core idea of this game is for you to act as an evil scheduler. Your goal is to guide the execution of threads into a bad state, such as a deadlock or two threads entering a critical section simultaneously. However, you cannot do this arbitrarily; you must adhere to the semantics of locks and other concurrency primitives. To win the game, you need a deep understanding of these concepts.

While Deadlock Empire offers an excellent learning experience, I wanted to create something that bridges the gap between game-based learning and real-world programming. What if we could play this “evil scheduler” game with actual Java code in a professional IDE, seeing real-time thread behavior as we manipulate the schedule? This approach would not only make learning concurrency more engaging but also provide practical debugging skills for real-world concurrent programs.

Fray

Fray is a controlled concurrency testing platform that I have been developing. It is designed to help developers identify concurrency bugs in their JVM code. Fray systematically explores thread interleavings by running the program in a sequential order, blocking all threads and allowing only one thread to execute at a time, which is similar to deadlock empire!

Implement Games in Fray

Implementing deadlock empire games in Fray is extremely easy. You just write simple Java programs. What’s even better? You can use LLMs to translate all existing games in Java. Here is a list of translated games.

The goal of each game is simple, just trigger exceptions or deadlocks in the program.

Play the Game in Terminal?

While theoretically possible, you can utilize the replay feature provided by Fray to manually craft the thread schedule in JSON and provide it to Fray. Then, you can run the program with the recording to see if it triggers the exception.

However, this approach is not very fun. To make it more enjoyable, we developed an IntelliJ plugin that allows you to play Deadlock Empire directly in IntelliJ. The plugin is available here.

Although I love VSCode/Cursor, I still believe IntelliJ is the best IDE for Java/Kotlin development.

Play the Game in IntelliJ!

To play the game, you need to clone the Deadlock Empire repository and open it in IntelliJ.

All games are located in the src/test/java/org/deadlockempire directory. To play a game, open the file and run the test with Fray Debugger. And then select frayTest.

The first time you start the game, it will take some time to set up the environment. Please be patient.

Control Panel

When the game/test starts, you will see the control panel at the bottom of the screen. It has three panels, a scheduling panel, a timeline panel, and a resource panel.

Scheduling Panel

Scheduling panel shows all executing threads in your program. It shows the stack trace of each thread as well. You may also click a stack trace to navigate to the source code.

[!NOTE] You may only view files in the source directory. It does not open source files in JDK or library.

You may also use the drop-down menu to select a thread to view. Once you have decided which thread to run. Click the Schedule button to run the thread!

Timeline Panel

Timeline panel shows the execution timeline of the program. Each time you click Schedule button, the timeline refreshes and shows the new state of the program.

Resource Panel

When a thread acquires a lock, it will appear in the resource panel, along with the resource it is waiting for if the thread is blocked.

Editor

After you click the Schedule button, the debugger shows the executing lines of each thread in your editor.

Along with the updated timeline.

Enjoy!

Please let me know how you like the game! If you have any suggestions or feedback, feel free to open an issue in the repository.

For Educators

If you teaches concurrency and want to use Fray in your class, please let me know! I am happy to help you set up the environment and provide you with the necessary resources.

For Students

If you find this tool useful in helping you understand concurrency, please let me know! I am happy to hear your feedback and suggestions.

For Developers

Yeah, you can also use this tool to debug your code. Unfortunately, concurrency bugs in real program usually requires 10k steps to reproduce, and currently you need to click the Schedule button 10k times. But we are working on better UI/UX design! Stay tuned!

Other notes

Q: Why didn’t Fray stop at some program locations?

A: To reduce search space, Fray only reschedule threads at synchronization points, such as synchronized blocks, ReentrantLock, Semaphore, etc. This means that Fray continues executing a thread until it hits a synchronization point. If you want to interleave at specific location, you may add a Thread.yield() to enforce a context switch.

By default Fray only interleave memory operations that are atomic or volatile.

Q: Can I create new games?

A: Of course you can! Just create a new test file in the src/test/java/org/deadlockempire directory. Please add the @ExtendWith(FrayTestExtension.class) annotation to the test class, and @ConcurrencyTest to the test method to make sure Fray can recognize these games!

Please also consider patching back to the original repository so that others can enjoy your game too!

Q: Wait, Fray hangs when I run it in the test mode?

A: Yes, this is because many of these translated games have infinite loops. We are going to change them to bounded loops in the future.