// 工作线程执行函数
TaskGroup::run_main_task() {
TaskGroup dummy
// 每次获取一个待执行的bthread,若没有在parkinglot上睡眠等待唤醒
while (wait_task(&tid)) {
// 切换到tid标记的bthread的上下文
sched_to(&dummy, tid)
// 这里工作线程得到调度,回到工作线程的上下文继续执行
// 下一个任务分配栈失败或者指定了pthread模式,直接在pthread的栈上调用task_runner()
if (cur_meta.tid != main_tid)
task_runner()
}
// 这里线程退出
}
// 此函数中发生上下文切换
sched_to(TaskGroup g, TaskMeta next_meta) {
cur_meta = g.cur_meta
if (next_meta != cur_meta) {
// 切换cur_meta和线程本地存储
g.cur_meta = next_meta
cur_meta.local_storage = tls_bls
tls_bls = next_meta.local_storage
if (cur_meta->stack != nullptr) {
if (next_meta.stack != cur_meta.stack) {
// 若next_meta有自己的栈,jump_stack切换到next_meta的栈
jump_stack(cur_meta->stack, next_meta.stack)
// cur_meta再次得到调度,从这里开始执行,由于bthread允许偷任务,可能此时是其他工作线程在执行,需要切换
g = tls_task_group
} else {
// 一个pthread_task切换到另一个pthread_task,只能在工作线程的栈上发生
CHECK(cur_meta.stack == g.main_stack)
}
}
}
while (g.last_context_remained) {
fn = g.last_context_remained
g.last_context_remained = nullptr
fn()
g = tls_task_group
}
// 到这里此函数返回,继续执行cur_meta所在的bthread任务,即该bthread中调用sched_to的下一行代码
}
// bthread栈的初始函数,第一次jump到一个bthread栈的时候调用此函数
void task_runner() {
g = tls_task_group
while (g.last_context_remained) {
fn = g.last_context_remained
fn()
g = tls_task_group
}
do {
m = g.cur_meta
m.user_func(arg) // 执行用户函数
g = tls_task_group // 可能发生过上下文切换,这里切换回来了,需要更新TaskGroup
g.set_remained(release_last_context, &m) // 用户函数已经执行完了,设置销毁栈
ending_sched(&g)
} while (g.cur_meta.tid != g.main_tid)
}
// 特殊处理的sched,已知当前bthread已经执行完成,栈等相关资源不再需要时调用
ending_sched(TaskGroup g) {
next_tid = g.next_sched_tid()
cur_meta = g.cur_meta
next_meta = address_meta(next_tid)
if (next_meta.stack == nullptr) {
// 若next_meta没有栈且需要的栈类型和cur_meta一致,那么直接让next_meta使用cur_meta的栈,节省释放和重新分配的开销
if (next_meta.stack_type() == cur_meta.stack_type())
next_meta.set_stack(cur_meta.release_stack())
else {
// 新初始化一个栈,起始函数为task_runner,第一次jump到这个栈的时候调用
stack = get_stack(next_meta.stack_type(), task_runner)
if (stack)
next_meta.set_stack(stack)
else {
// 可能没有足够的内存支持mmap或者栈类型本身就是pthread的,直接用工作线程的栈执行
next_meta.stack_type = BTHREAD_STACKTYPE_PTHREAD
next_meta.set_stack(g.main_stack)
}
}
}
sched_to(g, next_meta)
}
|