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

发布于 2024-09-03 19:40:55 字数 97 浏览 6 评论 0原文

任何人都可以发布一些示例代码,了解如何在守护进程收到 SIGHUP 信号后重新读取配置文件并重新启动我的守护进程。守护进程是Linux上用C编写的用户空间程序,不由inetd启动。

Can anybody please post some example code on how I can reread a configuration file and restart my daemon after the daemon receives a SIGHUP signal. The daemon is a user space program written in C on Linux and is not started by inetd.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心病无药医 2024-09-10 19:40:55

根据程序编写的干净程度,(至少)有三种方法可以做到这一点:

  1. 收到信号后,在初始化阶段之前返回到程序的开头(可能 - 但不一定 - 通过setjmp()/longjmp() 或 sigsetjmp()/siglongjmp() 对),从而重置并重新读取配置文件。

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

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

什么有效部分取决于您的守护进程必须做什么。如果它花时间与客户对话,您可能不想使用选项 1 或 2 - 您更愿意使用选项 3。如果您正在对简单问题进行一次性回答,那么残酷的方法可能是有效(并且可能更易于编程)。请注意,选项 1 需要仔细处理 WIP(进行中的工作)和打开文件等内容 - 如果不小心,您将失去对资源的跟踪,并且守护进程将失败(内存不足、文件描述符不足 -最有可能是这两者之一)。

Depending on how cleanly your program is written, there are (at least) three ways to do that:

  1. On receipt of the signal, return to the start of the program, before the initialization phase (possibly - but not necessarily - via a setjmp()/longjmp() or sigsetjmp()/siglongjmp() pair), thus resetting and rereading the configuration file.

  2. On receipt of the signal, have the signal handler exec the original program again. This has the merit of losing all the state and resetting all globals and static variables back to their original state. It has the demerit of losing all previous state.

  3. The third option is less brutal, perhaps; it would note that the signal has been received and at the next convenient point in the main processing loop, would go back and reread the configuration file.

What works depends in part on what your daemon has to do. If it spends time in a conversation with its clients, you may not want to use either of the options 1 or 2 - you would prefer to use option 3. If you are doing one-shot answers to simple questions, the brutal approaches may be effective (and are probably simpler to program). Note that option 1 requires careful handling of the WIP (work in progress) and things such as open files - if you are not careful, you will lose track of resources, and the daemon will fail (out of memory, out of file descriptors - most likely one of these two).

迷雾森÷林ヴ 2024-09-10 19:40:55

另一个稍微详细一点的示例在这里:

http://man7 .org/tlpi/code/online/dist/daemons/daemon_SIGHUP.c.html

Another, slightly more elaborate, example is here:

http://man7.org/tlpi/code/online/dist/daemons/daemon_SIGHUP.c.html

樱娆 2024-09-10 19:40:55

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

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;
}

I found this page as I was looking for an example myself to make sure I'm doing it correctly. Since there is no example for this I'll post my attempt and let others comment on it:

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;
}
我不是你的备胎 2024-09-10 19:40:55

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

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

如果是多进程,事情就会变得更加复杂。您必须通知进程有关新配置的信息,或确保它们继续使用旧配置,或者当客户端退出时它们可以选择新配置。

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

Depends how you structure it; if you handle multiple connections in a single thread / process, then you should probably somehow notify them to quit (if you can; depends on the protocol) before reloading the config (or exec itself).

If the protocol allows you to say "go away and come back later", then clearly doing that is a good win. If the clients need to remain connected, you could apply the config changes to already-connected clients, if it's a single-process-single-thread daemon, if that makes sense.

If it's multi process, things get more complex. You'd have to notify the processes about the new config, or ensure that they continue with the old config, or that they can pick the new config up when their client quits.

If it's multi thread, the threads would need to safely be able to read the new config in the middle of whatever they happened to be doing, which might need locking, or you could allocate memory for a new config structure and do a switch-over somehow,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文