上下文切换 - makecontext 和 swapcontext 在这里工作吗 (OSX)

Context switching - Is makecontext and swapcontext working here (OSX)

我对上下文切换很感兴趣。我已将示例代码复制到一个文件中 http://pubs.opengroup.org/onlinepubs/009695399/functions/makecontext.html

我为 OSX 定义了宏 _XOPEN_SOURCE。

#define _XOPEN_SOURCE 
#include <stdio.h>
#include <ucontext.h>


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 = &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);


    swapcontext(&ctx[0], &ctx[2]);
    return 0;
}

我建

gcc -o 上下文 context.c -g

关于 get、make、swap context 被弃用的问题向我吐槽。嗯

当我 运行 它只是挂起。它似乎没有崩溃。它只是挂起。

我尝试使用 gdb,但是一旦进入交换上下文,它就是空白的。它不会跳入 f1。我一直按回车键,它只会将光标移动到控制台上的新行中?

知道发生了什么事吗?与研究 Mac/deprecate 方法有关?

谢谢

看起来您的代码只是 the ucontext documentation 中的 copy/pasted,这肯定让人沮丧,因为它无法正常工作...

据我所知,您的筹码太少了。我无法让它与任何小于 32KiB 的堆栈一起工作。

尝试进行这些更改:

#define STACK_SIZE (1<<15) // 32KiB

// . . .

    char st1[STACK_SIZE];
    char st2[STACK_SIZE];

yup fixed it. why did it fix it though?

好吧,让我们更深入地研究一下这个问题。首先,让我们看看到底发生了什么。

When I run it it just hangs. It doesn't seem to crash. It just hangs.

如果你使用一些调试器(一定要使用 lldb——gdb 在 os x 上不能正常工作),那么你会发现当应用程序是 "hanging",它实际上在你的 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]);// <---------------------+ back to here
    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); //              |
    //                                           |
    puts("about to swap...");//                  |
    //                                           |
    swapcontext(&ctx[0], &ctx[2]);// ------------+ jumps from here
    return 0;
}

请注意,我在上面的循环中间添加了一个额外的 puts 调用。如果您再次添加该行和 compile/run,那么您将看到它开始喷出字符串 "about to swap..." ad infinitum.[=,而不是程序只是挂起。 36=]

显然,根据给定的堆栈大小,有些事情正在发生,所以让我们只查找引用 ss_size 的所有地方...

(注意:Apple ucontext 实现的权威源代码位于 https://opensource.apple.com/source/, but there's a GitHub mirror,我将使用它,因为它更适合搜索和链接。)

如果我们take a look at makecontext.c,我们会看到这样的东西:

if (ucp->uc_stack.ss_size < MINSIGSTKSZ) {
   // fail without an error code since makecontext is a void function
   return;
}

嗯,太好了!什么是 MINSIGSTKSZ?好吧,让我们 a look in signal.h:

#define MINSIGSTKSZ 32768   /* (32K)minimum allowable stack */
#define SIGSTKSZ    131072  /* (128K)recommended stack size */

显然这些值实际上是 part of the POSIX standard. Although I don't see anything in the ucontext documentation that references these values, I guess it's kind of implied since

无论如何,这解释了我们所看到的古怪行为。由于 makecontext 调用因堆栈太小而失败,对 getcontext(&ctx[2]) 的调用是设置 ctx[2] 的内容,因此对 swapcontext(&ctx[0], &ctx[2]) 的调用只是最终再次换回那条线,创建无限循环...

有趣的是,MINSIGSTKSZ 在 os x 上是 32768 字节,但在我的 linux 盒子上只有 2048 字节,这解释了为什么它在 linux 上有效但在 os x.

基于所有这些,看起来更安全的选择是使用 sys/signal.h:

中推荐的堆栈大小
char st1[SIGSTKSZ];
char st2[SIGSTKSZ];

那个,或者切换到未弃用的东西。如果您不反对 C++,您可以看看 Boost.Context