Safe user-level context switch

Hello everyone. I would like to share something I've been working on with you today. I think I have made a generalized version of a stackful coroutine (example crates would be corosensei, may or its generator library) by modifying the aforementioned corosensei library (thanks to @Amanieu). I've called it a fiber for people that are familiar with such term, and I thought it more closely suited the new concept.

It is a single type Fiber which would represent a lightweight thread of execution. There are two functions: a constructor and the switch method, which basically swaps current execution context with the execution context of a fiber. This implies that you can simply have a fiber, even if it executes the main function. You can check out its entire documentation published via github pages.

So here is an example:

use corosensei::Fiber;

struct Arg {
    exec: Fiber<Option<Yield>>,
    i: i32,
}

struct Yield {
    exec: Fiber<Arg>,
    i: i32,
}

impl Arg {
    fn new(exec: Fiber<Option<Yield>>, input: i32) -> Self {
        Self { exec, i: input }
    }
}

fn main() {
    println!("[main] creating execution");

    let mut exec = Fiber::new(|Arg { mut exec, i }| {
        println!("[execution] execution started with input {}", i);
        for mut i in 0..5 {
            println!("[execution] yielding {}", i);
            Arg { exec, i } = exec.switch(move |exec| Some(Yield { exec, i }));
            println!("[execution] got {} from parent", i)
        }
        println!("[execution] exiting execution");
        (exec, |_| None)
    });

    let mut counter = 100;
    loop {
        println!("[main] resuming execution with argument {}", counter);
        match exec.switch(move |exec| Arg::new(exec, counter)) {
            Some(Yield { exec: new, i }) => {
                exec = new;
                println!("[main] got {:?} from execution", i)
            }
            None => break,
        }

        counter += 1;
    }

    println!("[main] exiting");
}

And it prints:

[main] creating execution
[main] resuming execution with argument 100
[execution] execution started with input 100
[execution] yielding 0
[main] got 0 from execution
[main] resuming execution with argument 101
[execution] got 101 from parent
[execution] yielding 1
[main] got 1 from execution
[main] resuming execution with argument 102
[execution] got 102 from parent
[execution] yielding 2
[main] got 2 from execution
[main] resuming execution with argument 103
[execution] got 103 from parent
[execution] yielding 3
[main] got 3 from execution
[main] resuming execution with argument 104
[execution] got 104 from parent
[execution] yielding 4
[main] got 4 from execution
[main] resuming execution with argument 105
[execution] got 105 from parent
[execution] exiting execution
[main] exiting

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.