// 工作线程执行函数 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) } |