C GDB、信号和信号

C GDB、信号和信号,c,gdb,signals,C,Gdb,Signals,将信号处理程序设置为SIG\u IGN会在正常运行程序时忽略该信号,但在通过gdb运行程序时不会忽略该信号 我正在使用timer\u create和timer\u settime函数创建计时器。我不想使用信号处理程序(即函数)来处理此计时器生成的信号。我决定使用sigwait并等待SIGALRM。我将SIGALRM的处理程序设置为SIG\u IGN,并使用sigwait #include <stdio.h> #include <signal.h> #include <

将信号处理程序设置为
SIG\u IGN
会在正常运行程序时忽略该信号,但在通过gdb运行程序时不会忽略该信号

我正在使用
timer\u create
timer\u settime
函数创建计时器。我不想使用信号处理程序(即函数)来处理此计时器生成的信号。我决定使用
sigwait
并等待
SIGALRM
。我将
SIGALRM
的处理程序设置为
SIG\u 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;
}
#包括
#包括
#包括
#包括
#定义真1
#定义ISTRUE(x)(x!=0)
#定义布尔整数
int main(){
结构itimerspec定时器规格;
结构sig事件sig_事件;
计时器\u t计时器\u id;
sigset_t sig_集;
计时器\u spec.it\u interval.tv\u sec=1;
计时器\u spec.it\u interval.tv\u nsec=0;
定时器规格it值tv秒=1;
定时器规格it值tv nsec=0;
sig_event.sigev_signo=SIGALRM;
sig_事件。sigev_通知=sigev_信号;
信号(信号,信号);
信号(信号灯、信号灯);
/*创建计时器*/
计时器创建(时钟实时、信号事件和计时器id);
定时器设置时间(定时器id,0和定时器规格,NULL);
sig清空设置(&sig_设置);
sigaddset(&sig_set,SIGALRM);
int信号=0;
bool running=TRUE;
while(正在运行){
信号等待(&sig_设置和信号);
开关(信号){
案例信号:
printf(“接收到中断..正在退出\n”);
运行=0;
打破
案例标志:
printf(“勾选的\n”);
打破
}
printf(“睡眠”);
}
返回0;
}
在MyIDE(CLion)中调试应用程序以及在shell中使用gdb时,程序按预期运行
SIGALRM
没有被忽视,这让我相信我所做的是正确的。但是,在正常运行应用程序时,
sigwait
永远不会返回

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


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

您应该查看
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正在使用该手册):

在跟踪过程中,每次发送信号时,跟踪对象都会停止,即使信号被忽略


ptrace似乎是某种原因造成的,因为当程序在
strace
下运行时,也可以观察到该行为。看起来像是一个有趣的Linux怪癖。在发布问题之前,我尝试了
处理SIGALRM ignore
。然而,没有区别。此外,手册页上还说:tracee将在每次发送信号时停止,但是,这并不能解释为什么信号本身被设置为“挂起”。或者,我理解错了吗?是的,确实不可能在gdb或其他使用ptrace的程序下模拟未跟踪进程的行为。这是因为ptrace-d进程将a)在每次向其发送信号时停止,即使该信号被忽略;b)跟踪器重新启动tracee将导致任何阻塞系统调用返回到userland,并且并非所有系统调用都将重新启动。如果信号在
sigtimedwait()
的掩码中,则
sigtimedwait()
将返回它,否则它将返回-1并将
errno
设置为
EINTR
。这是glibc库函数
sigwait(3)
正在重新启动用于实现它的
sigtimedwait(2)
系统调用,让事情变得混乱。通过从程序中删除
sigaddset
调用并在
strace
下运行,您可以轻松检查所有这些。Linux上的
signal(7)
manpage中有一节是关于这一点的:“通过停止信号中断系统调用和库函数”。