我在上下文切换方面有一些乐趣。我已将示例代码复制到文件中 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 context.c -g
关于get,make,swap context被弃用的问题。 MEH。当我跑它时,它只是挂起。它似乎没有崩溃。它只是挂起。
我尝试使用gdb,但是一旦我进入swapcontext,它就是空白。它没有跳进f1。我只是继续按Enter键,它只是将光标移动到控制台上的新行?
知道发生了什么事吗?处理Mac /弃用方法有什么用?
由于
答案 0 :(得分:7)
看起来您的代码只是从the ucontext documentation进行了复制/粘贴,这必然让它感到沮丧,因为它不起作用......
据我所知,你的筹码太小了。我无法让你的筹码少于32KiB。
尝试进行这些更改:
#define STACK_SIZE (1<<15) // 32KiB
// . . .
char st1[STACK_SIZE];
char st2[STACK_SIZE];
是的,修好了。为什么它会修复它?
好吧,让我们再深入研究一下这个问题。首先,让我们找出实际发生的事情。
当我跑它时,它只是挂起。它似乎没有崩溃。它只是挂起。
如果你使用一些debugger-fu(确保使用lldb-gdb只是不能在os x上正常工作),那么你会发现当应用程序是&#34;挂起&#34;时,它& #39; s实际上在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
调用。如果您添加该行并再次编译/运行,那么只需挂起您的程序,就会看到它开始喷出字符串"about to swap..."
ad infinitum 。
显然基于给定的堆栈大小会发生一些棘手的事情,所以让我们只是寻找引用ss_size
的所有地方...
(注意:Apple ucontext实施的权威源代码位于https://opensource.apple.com/source/,但是我会使用a GitHub mirror take a look at makecontext.c
,因为它更适合搜索和链接。)
如果我们a look in signal.h
,我们会看到类似的内容:
if (ucp->uc_stack.ss_size < MINSIGSTKSZ) {
// fail without an error code since makecontext is a void function
return;
}
嗯,真好!什么是MINSIGSTKSZ
?好吧,让我们来part of the POSIX standard:
#define MINSIGSTKSZ 32768 /* (32K)minimum allowable stack */
#define SIGSTKSZ 131072 /* (128K)recommended stack size */
显然这些值实际上是ucontext preserves the current signal mask。虽然我在ucontext文档中没有看到任何引用这些值的内容,但我认为这是Boost.Context以来的暗示。
无论如何,这解释了我们所看到的棘手行为。由于makecontext
调用由于堆栈大小太小而失败,因此调用getcontext(&ctx[2])
即设置ctx[2]
的内容,因此调用swapcontext(&ctx[0], &ctx[2])
最后再次换回那条线,创造无限循环......
有趣的是,{x}上的MINSIGSTKSZ
是32768字节,但我的linux盒子上只有2048字节,这解释了为什么它可以在linux上运行而不是os x。
基于所有这些,看起来更安全的选择是使用sys/signal.h
建议的堆栈大小:
char st1[SIGSTKSZ];
char st2[SIGSTKSZ];
那,或切换到不被弃用的东西。如果您不反对C ++,可以查看{{3}}。