【问题标题】:GDB, signals and SIG_IGNGDB、信号和 SIG_IGN
【发布时间】:2019-07-06 12:51:39
【问题描述】:

将信号处理程序设置为SIG_IGN 会在正常运行程序时忽略信号,但在通过 gdb 运行时不会。

我正在使用timer_createtimer_settime 函数创建一个计时器。我不想使用信号处理程序(即函数)来处理此计时器生成的信号。我决定使用sigwait 并等待SIGALRM。我将SIGALRM 的处理程序设置为SIG_IGN 并使用sigwait

#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>

#define TRUE 1
#define ISTRUE(x) (x != 0)
#define bool int

int main() {
    struct itimerspec timer_spec;
    struct sigevent sig_event;
    timer_t timer_id;
    sigset_t sig_set;


    timer_spec.it_interval.tv_sec = 1;
    timer_spec.it_interval.tv_nsec = 0;
    timer_spec.it_value.tv_sec = 1;
    timer_spec.it_value.tv_nsec = 0;

    sig_event.sigev_signo = SIGALRM;
    sig_event.sigev_notify = SIGEV_SIGNAL;


    signal(SIGINT, SIG_IGN);
    signal(SIGALRM, SIG_IGN);


    /* Create the timer */
    timer_create(CLOCK_REALTIME, &sig_event, &timer_id);
    timer_settime(timer_id, 0, &timer_spec, NULL);

    sigemptyset(&sig_set);
    sigaddset(&sig_set, SIGALRM);

    int signal = 0;
    bool running = TRUE;

    while (ISTRUE(running)) {
        sigwait(&sig_set, &signal);
        switch(signal){
            case SIGINT:
                printf("Interrupt received.. exiting\n");
                running = 0;
                break;
            case SIGALRM:
                printf("Ticked\n");
                break;
        }
        printf("Sleeping\n");

    }
    return 0;
}

在我的 IDE (CLion) 中调试应用程序以及从 shell 使用 gdb 时,程序按预期运行。 SIGALRM 没有被忽视,这让我相信我所做的是正确的。但是,正常运行应用程序,sigwait 永远不会返回。

后来我意识到这是因为信号被忽略了,我需要阻止信号(使用sigprocmask 或类似方法)并将其设置为挂起状态。

为什么在调试时信号会通过?这应该发生吗?我错过了什么?

【问题讨论】:

  • 看来 ptrace 似乎以某种方式导致了这种情况,因为当程序在 strace 下运行时也可以观察到这种行为。看起来像是一个有趣的 Linux 怪癖。

标签: c gdb signals


【解决方案1】:

您应该查看handle gdb 命令:

(gdb) handle SIGALRM
Signal        Stop      Print   Pass to program Description
SIGALRM       No        No      Yes             Alarm clock
(gdb) handle SIGALRM ignore
Signal        Stop      Print   Pass to program Description
SIGALRM       No        No      No              Alarm clock
(gdb) help handle
... read it ;-) ...

正如ptrace(2)gdb 正在使用)的手册页中所述:

在被跟踪时,每次传递信号时被跟踪者都会停止,即使信号被忽略。

【讨论】:

  • 我在发布问题之前尝试过handle SIGALRM ignore。但是,没有任何区别。此外,手册页说:每次发送信号时tracee 都会停止 但是,这并不能解释为什么信号本身被置于“待处理”状态。或者,我理解错了吗?
  • 是的,确实无法使用 ptrace 在 gdb 或其他程序下模拟未跟踪进程的行为。这是因为 ptrace-d 进程将在每次向其发送信号时 a) 停止,即使该信号被忽略,并且 b) 重新启动跟踪跟踪器将导致任何阻塞的系统调用返回到用户空间——并不是所有的系统调用都会重新启动。如果信号在sigtimedwait()的掩码中,sigtimedwait()将返回它,否则返回-1并将errno设置为EINTR
  • 这是 glibc 库函数 sigwait(3) 正在重新启动用于实现它的 sigtimedwait(2) 系统调用,令人困惑。您可以通过从程序中删除sigaddset 调用并在strace 下运行它来轻松检查所有这些。 Linux 上的signal(7) 联机帮助页中有一节关于此:“通过停止信号中断系统调用和库函数”。
猜你喜欢
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
  • 2017-10-06
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
相关资源
最近更新 更多