【问题标题】:How are reboot handle when a process is still running进程仍在运行时如何重新启动处理
【发布时间】:2014-02-10 03:25:41
【问题描述】:

情况是这样的。我正在调试代码来执行日志记录功能。当用户登录时,日志文件将以 .part 格式创建。该文件本地保存在主机内部。我不知道为什么它被命名为.part。当用户完成他们的会话时,日志文件将仅重命名为 .username。除了本地日志文件之外,此代码还连接到服务器,该服务器还将保存日志文件。问题是日志记录仍在运行,但主机突然重新启动。重启可能是由来自 root 的命令、强制重启或硬件故障引起的。这会导致日志文件保留为 .part 并且服务器也会跟随。

所以,我的问题是:

如何在重启过程中进程被杀死或终止之前重命名文件?

我应该处理什么信号?

我认为这可能涉及竞争条件,有没有办法让我延迟重启?

我的方法

试图处理 SIGPWR,SIGSTOP,SIGTERM,SIGQUIT

创建一个 bash 脚本以在进程启动时进行重命名。

这里是主要代码:

int main(int argc, char **argv)
{
    int ch;
    int NoFork = 0;
    struct event_config *evconfig;
    struct event *signal_event_int;
    struct event *signal_event_quit;
    struct event *signal_event_term;
    struct event *signal_event_hup;
    struct event *signal_event_chld;
    struct event *signal_event_pwr;
    struct event *signal_event_stop;

    syspath_init_from_argv0(argv[0]);

    load_config();    /* load config first, the command line parameters will override */
    event_set_log_callback(my_event_log_cb);

    evconfig = event_config_new();
    if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
            log_error("event_config_require_features_failed");
    }
    while (!done) {
            /* ignore HUP first, just in case someone send us a HUP
               when we are reloading config, that will create a condition
               that makes us exit, with HangUp */
            sig_catch(SIGHUP,SIG_IGN);
            base = event_base_new_with_config(evconfig);

            local_listener = create_local_listener(base);

            if (!local_listener) {
                    log_error("Could not create a local listener!");
                    return 1;
            }
            http_listener = create_http_listener();
            if (!http_listener) {
                    log_error("Could not create a remote listener!");
                    return 1;
            }
            evhttp_set_cb(http_listener, "/mrexec", http_mrexec_cb, NULL);
            if (options.accept_remote) {
                    evhttp_set_cb(http_listener, "/rlog", http_rlog_cb, NULL);
            }
            if (pidfile_create(ACTSLOGD_PIDFILE)==-1) {
                    log_error("pidfile_create:failed:%d:%s", errno, strerror(errno));
            }
            LIST_INIT(&clientlist);
            if (options.log_remote) {
                    start_log_remote();
            }

            signal_event_int = evsignal_new(base, SIGINT, exit_cb, (void *)base);
            event_add(signal_event_int, NULL);
            signal_event_quit = evsignal_new(base, SIGQUIT, exit_cb, (void *)base);
            event_add(signal_event_quit, NULL);
            signal_event_term = evsignal_new(base, SIGTERM, exit_cb, (void *)base);
            event_add(signal_event_term, NULL);
            signal_event_hup = evsignal_new(base, SIGHUP, reload_config_cb, (void *)base);
            event_add(signal_event_hup, NULL);
            signal_event_chld = evsignal_new(base, SIGCHLD, sigchld_cb, (void *)base);
            event_add(signal_event_chld, NULL);
            signal_event_pwr = evsignal_new(base, SIGPWR, power_off_cb, (void *)base);
            event_add(signal_event_pwr, NULL);
            signal_event_stop = evsignal_new(base, SIGSTOP, power_off_cb, (void *)base);
            event_add(signal_event_chld, NULL);

            actslog_event_start(AGENT_ACTSLOGD);
            actslog_event_start(AGENT_ESCALATED);
            event_base_dispatch(base);
            printf("finished dispatch\n");

            evconnlistener_free(local_listener);

            evhttp_free(http_listener);
            http_listener = NULL;

            event_free(signal_event_int);
            event_free(signal_event_quit);
            event_free(signal_event_term);
            event_free(signal_event_hup);
            event_free(signal_event_pwr);
            event_free(signal_event_stop);

            if (options.log_remote) {
                    end_log_remote();
            }
            event_base_free(base);
            if (!done) {
                    load_config();
            }
            while (clientlist.lh_first != NULL) {
                    struct bufferevent *bev = clientlist.lh_first->bev;
                    bufferevent_free(bev);
                    LIST_REMOVE(clientlist.lh_first, clients);
            }
    }
    if (rlog) {
            rlog_close(rlog);
    }
    unlink(PATH_ACTSLOG);
    pidfile_cleanup(ACTSLOGD_PIDFILE);

    return 0;
}

这是信号处理程序

static void exit_cb(evutil_socket_t sig, short events, void *user_data)
{
    struct event_base *base = user_data;
    struct timeval delay = { 2, 0 };

    actslog_event_stop(AGENT_ACTSLOGD);
    actslog_event_stop(AGENT_ESCALATED);

    done = 1;    //when this is 1, there is a function that will connect to the server to tell that the logging is stopped.

    /* need to give some delay for us to send out the stop message to Logger */

    event_base_loopexit(base, &delay);
}

static void power_off_cb(evutil_socket_t sig, short events, void *user_data)
{
    struct event_base *base = user_data;
    struct timeval delay = { 5, 0 };
    char logfile_partial[MAXPATHLEN];
    char logfile_complete[MAXPATHLEN];
    char id[1024];

    done =1;     

    event_base_loopexit(base,&delay);

    snprintf(logfile_partial,    //the logfile_partial will be the one with .part file
    sizeof(logfile_partial),
    "%s/SHELL.%s.part", logpath2, id);

    snprintf(logfile_complete,   //the logfile_complete will be the complete without .part
    sizeof(logfile_complete),
    "%s/SHELL.%s", logpath2, id);

    if (rename(logfile_partial, logfile_complete)!=0) {
            if (errno==ENOENT) {
                    int tmp;
                    log_error("mastershell [%s] log is incomplete", logfile_complete);
                    tmp = creat(logfile_complete, LOG_FILE_MODE);
                    if (tmp==-1) {
                            log_error("creat:%s:failed:%d:%s!!\n", logfile_complete, errno, strerror(errno));
                    } else {
                    close(tmp);
                    }
            } else {
            log_error("rename:%s:%s:failed:%d:%s!!\n", logfile_partial, logfile_complete, errno, strerror(errno));
            }
    }

    if (rlog) {
            rlog_close(rlog);
    }
    unlink(PATH_ACTSLOG);
    pidfile_cleanup(ACTSLOGD_PIDFILE);
}

我已经测试处理 exit_cb 函数中的所有信号。 power_off_cb 函数中的所有信号也是如此。它们中的任何一个都不起作用。我已经在 CentOS 和 Ubuntu 上进行了测试。日志记录过程是一个新贵过程。任何意见或建议都非常感谢。

【问题讨论】:

    标签: c linux signals reboot libevent


    【解决方案1】:

    情况是这样的。我正在调试代码来执行日志记录功能。 当用户登录时,日志文件将以 .part 格式创建。 该文件本地保存在主机内部。我不知道为什么它的名字 作为一部分。当用户完成他们的会话时,日志文件将是 仅重命名为 .username。除了本地日志文件,这段代码也是 连接到该服务器还将保存日志记录的服务器 文件。问题是当日志仍在运行时,但主机 突然重启。重启可能是由来自 root 的命令引起的

    如果它是由来自 root 的命令引起的,您可以在 /etc/init.d/ 中创建一个脚本来处理它。

    ,或 强制重启,或者可能是硬件故障。这会导致日志文件 保持为 .part 并且服务器也跟随。

    您无法预测未来,操作系统也一样。如果由于电源或硬件故障导致重新启动,则无法预测。

    【讨论】:

    • 假设发生强制重启,系统仍然需要时间重启对吧?在此期间,日志进程是否有可能向服务器发送信号以通知会话已结束?
    • @MohdFikrie:不,不可能。 Som 重启会强行杀死所有进程
    • @MohdFikrie 如果您将“强制重启”调用为“rebo​​ot -f”,它会立即关闭系统,而无需运行任何脚本或发送任何特殊信号。检查:[unix.stackexchange.com/questions/64280/…。在正常重启关机问题后,SIGTERM SIGKILL,您可以捕获 SIGTERM 但没有保证您有足够的时间来处理它。
    • 我明白了。那么这真的让事情变得更加复杂。因为在重新启动之前我什么都做不了。也许我可以在流程开始时做点什么。谢谢你的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 2021-06-09
    • 2014-02-08
    相关资源
    最近更新 更多