ucontext.h和uc_link不从主线程返回
这是我想要做的更大的线程调度api的一部分。
我想创建一个线程,当主线程(创建线程的线程)退出时,我刚刚创建的线程应该执行。 我试图用ucontext和uc_link来做这个,但它不起作用。 当我尝试为当前线程设置它时,我的uc_link似乎不起作用。
这是一个稍微修改过的例子来自这个链接,这是我厌倦了这项工作。
http://pubs.opengroup.org/onlinepubs/009695399/functions/makecontext.html
#include #include static ucontext_t ctx[3]; static void f1 (void) { puts("start f1"); swapcontext(&ctx[1], &ctx[2]); puts("finish f1"); } static void f2 (void) { puts("start f2"); swapcontext(&ctx[2], &ctx[1]); puts("finish f2"); } int main (void) { char st1[8192]; char st2[8192]; getcontext(&ctx[1]); ctx[1].uc_stack.ss_sp = st1; ctx[1].uc_stack.ss_size = sizeof st1; ctx[1].uc_link = 0; makecontext(&ctx[1], f1, 0); getcontext(&ctx[2]); ctx[2].uc_stack.ss_sp = st2; ctx[2].uc_stack.ss_size = sizeof st2; ctx[2].uc_link = &ctx[1]; makecontext(&ctx[2], f2, 0); getcontext(&ctx[0]); ctx[0].uc_link = &ctx[2]; return 0; }
预期产量:
finished main start f2 start f1 finish f2 finish f1
给定输出:
finished main
如何以有意义的方式为当前线程/进程设置uc_link?
用以下代码替换上面代码中的main产生预期输出。
int main (void) { char st1[8192]; char st2[8192]; getcontext(&ctx[1]); ctx[1].uc_stack.ss_sp = st1; ctx[1].uc_stack.ss_size = sizeof st1; ctx[1].uc_link = &ctx[0]; makecontext(&ctx[1], f1, 0); getcontext(&ctx[2]); ctx[2].uc_stack.ss_sp = st2; ctx[2].uc_stack.ss_size = sizeof st2; ctx[2].uc_link = &ctx[1]; makecontext(&ctx[2], f2, 0); getcontext(&ctx[0]); ctx[0].uc_mcontext.gregs[16] += 0x26; puts("finish main"); setcontext(&ctx[2]); return 0; }
但这不符合您的要求。
上下文函数是一种在堆栈上放置特定返回地址的方法。
- getcontext将下一条指令的地址捕获到结构中
- makecontext将结构中的地址更改为其函数参数的地址
- setcontext / swapcontext将地址放在堆栈中的结构中并返回给它
上面的程序只有一个控制线程。 我认为你真的想要多个线程,在这种情况下你不会使用这些上下文函数。
有关堆栈和C调用约定的更多信息,Eli Bendersky有两篇包含图表的好文章:
- 堆栈顶部位于x86上
- 在x86-64上堆栈框架布局
FWIW,为了在上面的代码中得到0x26常量,我不得不反汇编main来找到setcontext调用后的第一个地址。
在你提供的链接上,他们说
uc_link成员用于确定当makecontext ()修改上下文返回时应恢复的上下文。
由于您的程序没有恢复(执行) 由makecontext ()修改的任何上下文,因此上述操作不适用,程序结束而不恢复任何上下文。
要实现你想要的,你必须定义一些function
void main_context() { // do everything you yet wanted to do in main() puts("finished main"); }
并取代
return 0;
同
char st0[8192]; ctx[0].uc_stack.ss_sp = st0; ctx[0].uc_stack.ss_size = sizeof st0; makecontext(&ctx[0], main_context, 0); return -setcontext(&ctx[0]);