Open ShuochengWang opened 3 years ago
The results of the discussion with @tatetian :
A Rust async runtime with no_std
, for LibOS, In particular, for SGX LibOS.
Take ngo as an example, ngo need rust async runtime with following features:
If one thread is idle, this thread will sleep. When a new task is ready, the sleeping thread will be waked up.
There are different kinds of tasks in LibOS, e.g. user tasks and LibOS tasks. User tasks generally have higher priority, while LibOS tasks maybe running in the background and with lower priority.
Firstly, thanks to tokio's blog https://tokio.rs/blog/2019-10-scheduler, those ideas are very usefull.
Task priority affects how to select tasks in the thread.
Task type affects how to assign task to threads.
In our async runtime, the thead is called vcpu. Since user can bind threads to specific cpu set in OS, we allow user to bind tasks to specific vcpu set.
If one task is bound to a vcpu set, then the task can only run in those vcpus. vcpu outside the set can not steal the task.
Each thread has three local queues. All threads share one global queue.
When accept one task, we need to decide which thread to run the task.
In the assign algorithm, we consider following factors:
wait_time = global_tick - queue.front().assign_tick
. we find a thread with short wait time.
The Problem
NGO uses Rust async / await to reconstruct the code and realize asynchronous. Because Rust async / await needs to be executed through Rust async runtime, NGO has implemented a basic version of Rust async runtime, namely async-rt.
With async-rt, NGO implements M : N : P in-enclave scheduling. Specifically, there are M user threads, N LibOS coroutines, and P host threads. The executor of Rust async runtime runs on P host threads (that is, P Linux threads). The executor schedules N LibOS coroutines (that is, N Rust async tasks). N LibOS coroutines contain M user threads and N - M LibOS system tasks.
However, there is no scheduler for async-rt at present. The executor of async-rt can only run tasks in its local queue. This will lead to the following problems for NGO:
In addition, in async-rt, if the task is in the pending state, the corresponding waker will be set. Invoking waker.wake() will rejoin the task to the local queue. If wake() is invoked repeatedly (It is feasible at the API level), the queue will contain multiple identical tasks, which will affect performance and scheduling.
Design Goals
Add scheduler to the Rust async runtime async-rt and make async-rt a production-level Rust async runtime with no_std. The scheduler should meet the following requirements:
The priorities of these requirements decrease in turn. We will implement these requirements in order of priority.