NPGT M个用户态线程倚在N个核心线程身上, N个核心线程可能阻塞。每个核心态线程对应一个或多个用户态线程,至少包含一个调度线程。NGPT的用户态调度是非抢占的。
FreeBSD libkse采用了SA,出现阻塞会启用新线程upcall到UTS。UTS采用roun-robin
Solaris 2.6 之前SIGWAITING,后采用SA协调。 UTS是可抢占的。
对于M,一般只受资源或系统值限制。而对于N,一般受CPU数限制,如果核心线程阻塞,NGPT没有更多的办法,FreeBSD和Solaris会创建新的核心线程。Solaris还有lwp回收机制,其它二者似乎没有。
对于UTS,实现可能用独立线程,如NGPT. libkse则是混合的:
_kse_alloc(libpthread/thread/thr_kern.c)中有如下代码:
/*
* Create the KSE context.
* Scope system threads (one thread per KSE) are not required
* to have a stack for an unneeded kse upcall.
*/
if (!sys_scope) {
kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_multi;
kse->k_stack.ss_sp = stack;
kse->k_stack.ss_size = KSE_STACKSIZE;
} else {
kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_single;
kse->k_stack.ss_sp = NULL;
kse->k_stack.ss_size = 0;
}
kse->k_kcb->kcb_kmbx.km_udata = (void *)kse;
kse->k_kcb->kcb_kmbx.km_quantum = 20000;
/*
* We need to keep a copy of the stack in case it
* doesn't get used; a KSE running a scope system
* thread will use that thread's stack.
*/
kse->k_kcb->kcb_kmbx.km_stack = kse->k_stack;
可以看到:对应process scope 的线程,upcall将得到一个单独的栈。 而system scope的线程,upcall将使用对应线程的栈。
_thr_schedule_add()函数中有如下代码证实:
if ((newthread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
/* We use the thread's stack as the KSE's stack. */
newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_sp =
newthread->attr.stackaddr_attr;
newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_size =
newthread->attr.stacksize_attr;
这
比较好理解,system
scope的线程只有一个,而且kse_sched_single只会从核心态调用一次,所以线程的栈顶应该是kse_sched_single,下面才
是curthread->start_routine(curthread->arg)(待核实)。
阅读(2646) | 评论(0) | 转发(0) |