Pro*_*rof 2 c macos context-switch ucontext
我对上下文切换很开心.我已将示例代码复制到文件 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;
}
Run Code Online (Sandbox Code Playgroud)
我建造它
gcc -o context context.c -g
关于get,make,swap context被弃用的我.咩.
当我运行它只是挂起.它似乎没有崩溃.它只是挂起.
我尝试使用gdb,但是一旦我进入swapcontext,它就是空白.它没有跳进f1.我只是继续按Enter键,它只是将光标移动到控制台上的新行?
知道发生了什么事吗?处理Mac /弃用方法有什么关系?
谢谢
看起来您的代码只是从ucontext文档中复制/粘贴,这必然会令它感到沮丧,因为它无法工作......
据我所知,你的筹码太小了.我无法使用任何低于32KiB的堆栈.
尝试进行这些更改:
#define STACK_SIZE (1<<15) // 32KiB
// . . .
char st1[STACK_SIZE];
char st2[STACK_SIZE];
Run Code Online (Sandbox Code Playgroud)
是的修好了.为什么要修复它呢?
好吧,让我们再深入研究一下这个问题.首先,让我们看看实际发生了什么.
当我运行它只是挂起.它似乎没有崩溃.它只是挂起.
如果你使用一些debugger-fu(确保使用lldb-gdb只是在os x上不能正常工作),那么你会发现当应用程序"挂起"时,它实际上是在你的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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我puts在循环中间添加了一个额外的调用.如果你添加那行并再次编译/运行,那么你将会看到它开始喷出"about to swap..." 无限字符串而不是程序.
基于给定的堆栈大小显然会发生一些棘手的问题,所以让我们只看一下ss_size被引用的所有地方......
(注意:Apple ucontext实现的权威源代码位于https://opensource.apple.com/source/,但是我会使用GitHub镜像,因为它更适合搜索和链接.)
如果我们看一下makecontext.c,我们会看到这样的事情:
if (ucp->uc_stack.ss_size < MINSIGSTKSZ) {
// fail without an error code since makecontext is a void function
return;
}
Run Code Online (Sandbox Code Playgroud)
嗯,那很好!什么是MINSIGSTKSZ?好吧,我们来看看signal.h:
#define MINSIGSTKSZ 32768 /* (32K)minimum allowable stack */
#define SIGSTKSZ 131072 /* (128K)recommended stack size */
Run Code Online (Sandbox Code Playgroud)
显然,这些值实际上是POSIX标准的一部分.虽然我在ucontext文档中没有看到任何引用这些值的内容,但我认为这有点暗示,因为ucontext会保留当前的信号掩码.
无论如何,这解释了我们所看到的棘手行为.由于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];
Run Code Online (Sandbox Code Playgroud)
那,或切换到不被弃用的东西.如果你不反对C++,你可以看一下Boost.Context.