简体   繁体   English

为什么信号处理程序不处理信号

[英]Why the signal handler doesn't process the signal

I'm trying to make a program that simulates the command nohup. 我正在尝试制作一个模拟命令nohup的程序。 The program gets as a first parameter, the name of a command that is gonna be executed. 该程序将作为要执行的命令的名称作为第一个参数。 The program executed by my program must not be notified when the terminal is closed, it will have to ignore the SIGHUP. 当终端关闭时,不得通知我的程序执行的程序,它将不得不忽略SIGHUP。 If I test my program with with the following command: 如果我使用以下命令测试程序:

         ./mynohup sleep 120 &

And then I try to send a SIGHUP from another terminal, sleep terminates when it should be immune to it. 然后,我尝试从另一个终端发送一个SIGHUP,当它应该不受睡眠时,睡眠终止。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

#include "utils.h"

#define NOHUP_OUT_FILE      "nohup.out"

static void handle_signal(int signum)
{
    if(signum == SIGHUP)
    {
        printf("This is ignored\n");
    }
    else
    {
        printf("Not ignored\n");
    }
    fflush(stdout);
}

/* configure handlers */
static void set_signals(void)
{
    struct sigaction sa;
    int rc;

    /* TODO - ignore SIGHUP */
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = handle_signal;
    rc = sigaction(SIGHUP, &sa, NULL);

    DIE(rc == -1, "sigaction");

}

/* execute a new program */
static void exec_func(int argc, char **argv)
{
    int rc;
    int i;
    char **exec_args;
    int fd;

    set_signals();  /* ignore SIGHUP */

    if(isatty(STDOUT_FILENO))
    {
        fd = open(NOHUP_OUT_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        DIE(fd < 0, "open");

        dup2(fd, STDOUT_FILENO);
        close(fd);
    }

    /* exec a new process */
    exec_args = malloc(argc * sizeof(*exec_args));
    DIE(exec_args == NULL, "malloc");

    for (i = 0; i < argc-1; i++)
        exec_args[i] = argv[i+1];
    exec_args[argc-1] = NULL;

    execvp(exec_args[0], exec_args);
    DIE(1, "execvp");
}

int main(int argc, char **argv)
{
    if (argc <= 1) {
        fprintf(stderr, "Usage: %s command_and_arguments\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    exec_func(argc, argv);

    return 0;
}

I tried to skip creating a new process and the signal handler works great. 我试图跳过创建新进程的过程,并且信号处理程序运行良好。 If the signal handler is in the following form the program works 如果信号处理程序具有以下格式,则程序可以运行

static void set_signals(void)
{
    struct sigaction sa;
    int rc;

    /* ignore SIGHUP */
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = SIG_IGN;

    rc = sigaction(SIGHUP, &sa, NULL);
    DIE(rc == -1, "sigaction");
}

I don't understand why when I create the first version of the signal handler the program doesn't works and with the second one it works. 我不明白为什么当我创建信号处理程序的第一个版本时该程序不起作用,而在第二个版本中它却起作用。

Thanks in advance! 提前致谢!

All exec functions reset the dispositions of caught signals to their default dispositions. 所有exec函数将捕获的信号的处理方式重置为其默认处理方式。

When you exec, your process image is destroyed and replaced by the process image of the new program. 执行时,过程映像将被破坏,并由新程序的过程映像替换。 In it, the pointer to the handle_function you passed to sigaction no longer has meaning, or the old meaning at least. 在其中,指向传递给sigaction的handle_function的指针不再具有含义,或者至少不再具有旧含义。 The only sensible thing the OS can do with handled signals upon execve is to reset them. 唯一明智的操作系统可以处理的信号时做execve是将它们重置。

The meaning of SIG_IGN is universal and independent of the current program and that's why SIG_IGN can be, and is, inherited. SIG_IGN的含义是通用的,独立于当前程序,这就是SIG_IGN可以被继承的原因。

execvp() is a front end for the execve() syscall. execvp()execve()系统调用的前端。

From its linux manpage : 从其Linux联机帮助页

All process attributes are preserved during an execve(), except the following: 除以下内容外,所有进程属性均在execve()期间保留:

  * The dispositions of any signals that are being caught are reset to the default (signal(7)). 

So the signal handler you installed is reset. 因此,您安装的信号处理程序将重置。

CORRECTION: (see history of changes for original text) 更正:(请参阅更改历史记录以获取原始文本)

The nohup(1) program just shifts the progran name ( nohup ) and the options to it, from the argc / argv parameters to main , redirects stdout / stderr to a file ( nohup.out ) in case one or both are directed to a tty device, and then just ignores SIGHUP and execvp(*argv, argv); nohup(1)程序只是将progran名称( nohup )及其选项从argc / argv参数转移到main ,将stdout / stderr重定向到文件( nohup.out ),以防一个或两个都指向一个文件。 tty设备,然后忽略SIGHUPexecvp(*argv, argv); for the original program to execute. 供原始程序执行。 It even does no fork(2) at all. 它甚至根本不提供fork(2)

The source code of FreeBSD nohup is available here . FreeBSD nohup的源代码在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM