第二阶段我的学习方法是先看完 v3 book 对应章节,然后再做实验题。v3 book 写得循序渐进,质量上乘,读懂后做实验题都比较轻松。第二阶段的精华都在 v3 book 中,十分建议精读一遍,我自己精读一遍后发现了若干内容和文字错误,还提交了 19 个 pr 修复。这期间我还写了篇博客分析有栈协程示例代码。
/// Returns a new builder with the multi thread scheduler selected. /// /// Configuration methods can be chained on the return value. #[cfg(feature = "rt-multi-thread")] #[cfg_attr(docsrs, doc(cfg(feature = "rt-multi-thread")))] pubfnnew_multi_thread() -> Builder { // The number `61` is fairly arbitrary. I believe this value was copied from golang. Builder::new(Kind::MultiThread, 61) }
/// Enables both I/O and time drivers. /// /// Doing this is a shorthand for calling `enable_io` and `enable_time` /// individually. If additional components are added to Tokio in the future, /// `enable_all` will include these future components. pubfnenable_all(&mutself) -> &mutSelf { #[cfg(any( feature = "net", all(unix, feature = "process"), all(unix, feature = "signal") ))] self.enable_io(); #[cfg(feature = "time")] self.enable_time();
self }
操作成员变量,使能运行时I/O和定时器
build
1 2 3 4 5 6 7 8 9 10 11 12
/// Creates the configured `Runtime`. /// /// The returned `Runtime` instance is ready to spawn tasks. pubfnbuild(&mutself) -> io::Result<Runtime> { match &self.kind { Kind::CurrentThread => self.build_current_thread_runtime(), #[cfg(feature = "rt-multi-thread")] Kind::MultiThread => self.build_threaded_runtime(), #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))] Kind::MultiThreadAlt => self.build_alt_threaded_runtime(), } }
fnbuild_threaded_runtime(&mutself) -> io::Result<Runtime> { use crate::loom::sys::num_cpus; use crate::runtime::{Config, runtime::Scheduler}; use crate::runtime::scheduler::{self, MultiThread};
let core_threads = self.worker_threads.unwrap_or_else(num_cpus);
let (driver, driver_handle) = driver::Driver::new(self.get_cfg(core_threads))?;
// Create the blocking pool let blocking_pool = blocking::create_blocking_pool(self, self.max_blocking_threads + core_threads); let blocking_spawner = blocking_pool.spawner().clone();
// Generate a rng seed for this runtime. let seed_generator_1 = self.seed_generator.next_generator(); let seed_generator_2 = self.seed_generator.next_generator();
(1) POST( Power On Self Test):上电自检,BIOS 对计算机硬件(CPU、主板、内存等)的检测。 (2) POST 之后的初始化与启动相关硬件(磁盘、键盘控制器等)。 (3) 为 OS 创建一些参数,如 ACPI、E820 表等。 (4) 选择引导设备,从设备中加载 BootLoader,进而启动操作系统。
VmcsGuestNW::RIP.write(entry.as_usize() & 0xffff)?; VmcsGuest16::CS_SELECTOR.write(((entry.as_usize() >> 4) & 0xf000) asu16)?; // On Intel requires 'base' to be 'selector * 16' in real mode. VmcsGuestNW::CS_BASE.write(entry.as_usize() & 0xf0000)?;
实现了clone,但是具体的flags没有处理,只按照fork的语义+返回并且用给定的栈。这个位置应该加上Copy on Write的支持,在MemorySet的Backend里加上这个,给每个页一个标记,然后在处理Page Fault的时候如果这个标记有了,就把这个页给复制一份,然后取消共享(虽然因为时间的关系没有实现)。我觉得Backend这个设计很好,在一些库里可以看到。这个设计让我们可以很方便地扩展三方库给的一些功能,同时不破坏这个库本身的代码和结构。
协作式调度的特点是,任务若不主动让出执行权(yield),就会持续执行下去。与之相反,抢占式调度则是任务随时可能被切换出去。现代操作系统出于避免恶意程序长时间占用 CPU 的考量,大多采用抢占式调度方式。然而,抢占式调度存在明显缺点,由于任务随时可能被切换,所以必须保存任务的堆栈,如此一来,当任务再次被切回时,才能恢复到切换出去时的状态。这就导致在大规模并发场景下,需要耗费大量内存来保存众多任务的堆栈。