在Linux中,接收到SIGHUP信号后如何重新启动C守护进程程序?

7

请问有没有人能够提供一些示例代码,以便我可以在守护进程接收到SIGHUP信号后重新读取配置文件并重启我的守护进程。该守护进程是在Linux上用C语言编写的用户空间程序,并不是由inetd启动。


8
人们通常不希望在收到SIGHUP信号时重启守护进程,而是进行优雅的重新加载,即加载新的配置文件但不断开已连接的客户端等类似的不良操作。 - ThiefMaster
4个回答

6

根据程序书写的清晰程度,有至少三种方法来实现这一点:

  1. 接收到信号后,在初始化阶段之前返回程序开头(可能会使用setjmp()/longjmp()或sigsetjmp()/siglongjmp()),从而重置和重新读取配置文件。

  2. 接收到信号后,让信号处理程序再次执行原始程序。这样做的好处是失去所有状态并将所有全局变量和静态变量重置为其原始状态。缺点是失去了所有先前的状态。

  3. 第三个选项可能不那么残酷; 它会注意到已接收到信号,并在主处理循环的下一个方便点返回并重新读取配置文件。

哪种方法适用取决于守护进程需要执行的任务。如果它花费时间与客户端交谈,则可能不希望使用选项1或2 - 更倾向于使用选项3。如果您正在对简单问题进行一次性回答,则采用粗暴的方法可能是有效的(并且可能更简单)。请注意,选项1需要仔细处理WIP(进行中的工作)和诸如打开文件之类的事情 - 如果不小心,您将失去资源的跟踪,守护进程将失败(内存不足,文件描述符不足 - 最可能是这两个问题之一)。


2

1

我发现这个页面是因为我自己在寻找一个例子来确保我做得正确。由于没有这方面的示例,我将发布我的尝试,并让其他人对其进行评论:

volatile sig_atomic_t g_eflag = 0;
volatile sig_atomic_t g_hupflag = 1;

static void signal_handler(int sig)
{
    switch(sig)
    {
    case SIGHUP:
        g_hupflag = 1;
        break;
    case SIGINT:
    case SIGTERM:
        g_eflag = 1;
        break;
    }
}

int main(int argc, char **argv)
{
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGHUP, signal_handler);
    signal(SIGPIPE, SIG_IGN);

    while(!g_eflag)
    {
        if(g_hupflag)
        {
            g_hupflag = 0;
            load_config();
        }

        // ... do daemon work ...
    }

    return 0;
}

0

这取决于您如何构建它;如果您在单个线程/进程中处理多个连接,则应该以某种方式通知它们在重新加载配置(或执行自身)之前退出(如果可能的话;这取决于协议)。

如果协议允许您说“走开然后稍后回来”,那么显然这样做是一个好的选择。 如果客户端需要保持连接,则可以将配置更改应用于已连接的客户端,如果它是单进程单线程的守护程序,则有意义。

如果是多进程,则情况变得更加复杂。 您必须通知进程有关新配置,或确保它们继续使用旧配置,或者在其客户端退出时可以获取新配置。

如果是多线程,则线程需要安全地能够在他们正在进行的任何操作中读取新配置,这可能需要锁定,或者您可以为新配置结构分配内存并进行某种切换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接