You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux中信号处理程序返回后系统调用重启机制及差异问题

信号处理与系统调用重启问题分析

程序1:按下CTRL+C时系统调用始终重启阻塞

当按下CTRL+C触发SIGINT信号后,信号处理完成后会自动重启被中断的getchar()调用,进程继续阻塞等待输入。

#define _GNU_SOURCE

#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <stdlib.h>
#include <ucontext.h>

void sighandler(int signo, siginfo_t *info, void *ctx) {
}

int main() {
    stack_t s;
    s.ss_flags = 0;
    s.ss_size = 40000;
    s.ss_sp = malloc(40000);
    sigaltstack(&s, NULL);

    struct sigaction action;
    action.sa_flags = SA_SIGINFO|SA_ONSTACK|SA_RESTART;

    sigfillset(&action.sa_mask);
    action.sa_sigaction = sighandler;
    sigaction(SIGINT, &action, NULL);

    getchar();
}

程序2:按下CTRL+C后打印哈哈并退出

触发SIGINT信号后,程序不会重启getchar()调用,而是执行自定义函数打印内容后直接退出。

#define _GNU_SOURCE

#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <stdlib.h>
#include <ucontext.h>

void restore_here() {
    printf("哈哈\n");
}

void sighandler(int signo, siginfo_t *info, void *ctx) {
    ucontext_t *sigctx = ctx;
    makecontext(ctx, restore_here, 0);
}

int main() {
    stack_t s;
    s.ss_flags = 0;
    s.ss_size = 40000;
    s.ss_sp = malloc(40000);
    sigaltstack(&s, NULL);

    struct sigaction action;
    action.sa_flags = SA_SIGINFO|SA_ONSTACK|SA_RESTART;

    sigfillset(&action.sa_mask);
    action.sa_sigaction = sighandler;
    sigaction(SIGINT, &action, NULL);

    getchar();
}

问题

已知信号处理程序返回后,C库会调用sigreturn系统调用,原子性设置信号掩码并跳转到ctx指定的位置。现需解答:

  1. 内核何时重启系统调用?
  2. 为何程序2在sigreturn调用后未重启系统调用?

解答

内核重启系统调用的时机

当同时满足以下两个条件时,内核会在sigreturn恢复上下文之前重启被中断的系统调用:

  • 被信号中断的是可重启类型的系统调用(如getchar、select这类阻塞式I/O调用、进程控制类调用等);
  • 注册信号处理函数时,sigaction的sa_flags参数设置了SA_RESTART标记。

此时内核会自动重新执行被中断的系统调用,进程逻辑会回到被信号打断前的状态,继续执行原系统调用。

程序2未重启系统调用的原因

程序2的信号处理函数中调用makecontext(ctx, restore_here, 0)直接修改了sigreturn要恢复的上下文ctx:

  • 原本ctx中保存着被中断的getchar()系统调用的执行状态、返回地址等关键信息,内核正是依靠这些信息判断需要重启的系统调用;
  • 修改后的上下文指向了自定义函数restore_here,sigreturn执行后会直接跳转到restore_here执行,而非回到getchar()被中断的位置;
  • 内核找不到原系统调用的执行上下文,因此不会触发系统调用重启逻辑。restore_here执行完毕后,进程没有回到原主程序的执行流,直接退出。

内容的提问来源于stack exchange,提问作者Markity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 20:57:29