import { Notes, PostImage } from "~/components/Markdown";
import { Tree } from "~/components/Tree";
In my quest to learn to build an async runtime in Rust, I have to learn about CPU context switching. In order to switch from one async task to another, our async runtime has to perform a context switch. This means saving the current CPU registers marked as `callee saved` by the System V ABI manual and loading the CPU registers with our new async stack.
In this article, I will show you what I have learned about jumping onto a new stack in a x86_64 CPU.
<Notes>
I'm learning about async runtimes in Rust based on the amazing book [Asynchronous Programming in Rust: Learn asynchronous programming by building working examples of futures, green threads, and runtimes](https://www.packtpub.com/en-mt/product/asynchronous-programming-in-rust-9781805128137)
It's an amazing book, don't get me wrong, but I feel like the explanation can be hand-wavy sometimes. Thus, I write this to archive my own explanation and potentially help other people who also struggle with the subject.
</Notes>
<Notes>
Most async runtimes in Rust do not use stackful coroutines (which are used by
Go's `gochannel`, Erlang's `processes`) and instead, use state machines to
manage async tasks.
</Notes>
## Contents
<hr />
## Setting the stage
Why do we need to swap the stack of async tasks in a runtime with stackful coroutines ?
Async tasks, by nature, are paused and resumed. Everytime a task is paused to move into a new task, we would have to save the current context of the task that is running and load the context of the upcoming task.
## Jumping into the new stack
Here is the code in its entirely, I'd recommend you run this on the [Rust Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024). I have left comments through out the code so you can get the general idea.