使用带有SIG_INFO的sigaction处理程序的第三个参数(void*context)会导致分段错误

Joh*_*cke 7 c gcc signals handler ucontext

我已经减少了一个巨大的光纤调度程序代码,该代码产生了以下几行的问题.
我期望的是每次都清理地返回上下文,传递给处理程序.
我得到的是"Handler."打印出三次,然后是分段错误.

#include <ucontext.h>
#include <signal.h>
#include <stdio.h>

ucontext_t currently_executed_context;

void handler_sigusr1(int signum, siginfo_t* siginfo, void* context)
{
    currently_executed_context = (*(ucontext_t*)context);

    printf("Handler. ");
    setcontext(&currently_executed_context);
}

int main()
{
    setbuf(stdout,0);

    struct sigaction action_handler;

    action_handler.sa_sigaction = handler_sigusr1;
    action_handler.sa_flags = SA_SIGINFO;

    sigaction(SIGUSR1,&action_handler,NULL);

    for(;;) { kill(getpid(),SIGUSR1); sleep(1); }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在两个不同的Linux发行版上使用gcc-4.4.3和gcc-4.4.5.

Joh*_*cke 1

至此,我自己对这个问题的研究可以作为部分答案。

首先,我发现这篇文章很旧,没有引用任何官方信息来源:http://zwillow.blogspot.com/2007/04/linux-signal-handling-is-broken.html。这是相关引用:

第二个问题:您不能使用 setcontext() 离开信号处理程序并跳转到另一个先前保存的上下文。(或者,就此而言,您不能使用它返回到作为参数传递给信号处理程序的完全相同的上下文。)换句话说,信号处理程序就像

static void sighandler(
   int signo, siginfo_t *psi, void *pv)
{
  memcpy(puc_old, pv, sizeof(ucontext_t));
  /* choose another context to dispatch */
  setcontext(puc_another);
}
Run Code Online (Sandbox Code Playgroud)

不起作用。它不会恢复 puc_other 中指定的信号掩码,不会重新建立备用信号堆栈等。但是,该方案在 Solaris 上完美运行。

如果有人可以确认有关 Solaris 的部分,我们将不胜感激。

其次,在与一位大学讲师交谈后,我开始了解到,从信号处理程序设置/交换上下文并不像在其他情况下那样简单。遗憾的是,向我解释这一点的人当时无法提供更多细节。

因此,我的两个消息来源似乎并不完全可靠,但仍然是线索。