skyzh / core-os-riscv

🖥️ An xv6-like operating system on RISC-V with multi-core support. Documentation available online.
https://skyzh.github.io/core-os-riscv/
MIT License
297 stars 23 forks source link

Proposal: Async-like way in handling user process #1

Open skyzh opened 4 years ago

skyzh commented 4 years ago

In xv6, code path for trapping into user-space and back is really confusing. Typically this is done with:

forkret() -> usertrap() -> making syscalls, etc. -> usertrapret()

I've encountered the issue of RAII. As we call usertrap in forkret, any object created in forkret won't be dropped as usertrap won't return.

Previously I thought this could been done by introducing a return_to function, in which RISC-V return address register ra is rewritten with the address of that function. For example,

fn forkret() -> NeverReturn {
    return_to(usertrap)
}

Therefore, object can be correctly dropped before jumping to usertrap. However, there're many issues with that.

After that, I propose to use a k_thread() function to represent full code path for trapping into and returning from user-space.

func k_thread() {
    // forkret contents
    loop {
        // usertrap contents
        await_into_userspace(); // A function calls into user space and returns on trap
        if scause == timer { yield(); }

        syscall();

        // usertrapret contents
    }
}

And the scheduler just schedules those k_threads, which solves the RAII issue.

Furthermore, I would like to have this issue solved with async-std crate, which supports no-std environment.

wangrunji0408 commented 4 years ago

Hi! Glad to see your excellent project!

I've made some attempts on this topic:

Hope it helps! And looking forward to further communication if you have any ideas.

Thanks!

skyzh commented 4 years ago

@wangrunji0408 Thank you! That's exactly what I would like to implement!

skyzh commented 4 years ago

osblog wrote a new article on this! https://os.phil-opp.com/async-await/