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]);