DragonFlyBSD的userland scheduler
DragonFly使用LWKT代表内核线程,同时放弃了原先的Kernel Process机制,在加上固定优先级,使得LWKT根本没有signal和CPU统计等数据。用于内核服务的LWKT只有一个执行函数,而用于用户程序的LWKT则与相应的struct proc关联,但在POSIX语义下,线程化的程序中,每个线程都应当有独立的信号处理和CPU统计。显然进程的信号处理和CPU统计仅仅为进程服务,那么就需要让用于用户的LWKT再关联一个负责信号处理和CPU统计等工作的结构,这就是struct lwp。
前文中,我们讨论了LWKT的调度,它是固定优先级轮转,这种机制对于确定了行为和作用的内核服务来说恰好不过,但显然不适合于用户程序,动态优先级才能适合这种状况;另一方面,pthread要求程序可以选择不同的线程调度算法,不仅仅是多级反馈队列这样的单一方式。于是DragonFly引入了调度线程,也就是usched。调度线程是一个优先级很低的LWKT,它与内核服务一起分享CPU,这样首先就满足了内核服务先于用户线程执行的语义。当 LWKT调度器调度usched运行时,usched再从各个用户线程中选择要执行的线程,这样通过改变usched函数指针指向的函数,就可以动态更改用户线程调度算法,而且还不会影响内核服务的调度行为。
目前在我看到的usched中,只有bsd4,see kern/usched_bsd4.c,它包含了多个runq,分别对应idle normal realtime的线程。而按照Mathew Dillion的说法,idle normal realtime应该分布在不同的调度线程中,从而分别采用各自适当的调度算法,并且满足realtime前于normal前于idle的语义。此外, usched是struct proc中的函数指针,也就是说LWKT调度器先在内核服务和用户进程中选择一个LWKT,如果这个LWKT有相关的进程,那么它就是调度线程,它去执行这个进程的usched,usched再选择用户线程去执行。总的来说,这块我还是有一些疑惑,只能明白个大体。而且按照这个思路,DF是一个1:n的线程模型,只需要libc_r就可以了,那么系统调用就需要实现为异步,同时在返回时发布upcall,看上去msgport正适合这个模型。
有FreeBSD的committer说不实现scheduler activation就不能带来高性能,但是非阻塞调用看上去也很不错,至少内核资源是绝对的省,况且采用1:1的系统性能似乎也不差。总之还是要看Mr Dillion的工作了。