Implementing our own fibers 119 almost never a problem on debug builds, but in this case, our program will fail if the compiler inlines this function in a release build. The issue manifests itself by the runtime exiting before all the tasks are finished. Since we store Runtime as a static usize that we then cast as a *mut pointer (which is almost guaranteed to cause UB), it's most likely caused by the compiler making the wrong assumptions when this function is inlined and called by casting and dereferencing RUNTIME in one of the helper methods that will be outlined. Just make a note that this is probably avoidable if we change our design; it's not something worth dwelling on for too long in this specific case. More inline assembly We need to explain the new concepts we introduced here. The assembly calls the function switch (the function is tagged with #[no_mangle] so we can call it by name). The in("rdi") old and in("rsi") new arguments place the value of old and new to the rdi and rsi registers, respectively. The System V ABI for x86-64 states that the rdi register holds the first argument to a function and rsi holds the second argument. The clobber_abi("C") argument tells the compiler that it may not assume any that any general-purpose registers are preserved across the asm! block. The compiler will emit instructions to push the registers it uses to the stack and restore them when resuming after the asm! block. If you take one more look at the list in Figure 5. 1, we already know that we need to take special care with registers that are marked as callee saved. When calling a normal function, the compiler will insert code* to save/restore all the non-callee-saved, or caller saved, registers before calling a function so it can resume with the correct state when the function returns. Since we marked the function we're calling as #[naked], we explicitly told the compiler to not insert this code, so the safest thing is to make sure the compiler doesn't assume that it can rely on any register being untouched when it resumes after the call we make in our asm! block. *In some instances, the compiler will know that a register is untouched by the function call since it controls the register usage in both the caller and the callee and it will not emit any special instructions to save/restore registers they know will be untouched when the function returns The self. threads. len() > 0 line at the end is just a way for us to prevent the compiler from optimizing our code away. This happens to me on Windows but not on Linux, and it is a common problem when running benchmarks, for example. There are other ways of preventing the compiler from optimizing this code, but I chose the simplest way I could find. As long as it's commented, it should be OK to do. The code never reaches this point anyway. Next up is our spawn function. I'll present the function first and guide you through it after: pub fn spawn(&mut self, f: fn()) { let available = self . threads . iter_mut() . find(|t| t. state == State::Available) . expect("no available thread. ");