当进程仍在运行时,如何处理重新启动

时间:2014-02-10 03:25:41

标签: c linux signals reboot libevent

这是情况。我正在调试代码来执行日志记录功能。当用户登录时,将使用.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上测试过。日志记录过程是一个新兴的过程。任何评论或建议都非常感谢。

1 个答案:

答案 0 :(得分:1)

  

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

命令引起的

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

  

,或者a   强制重启,或者可能是硬件故障。这会导致记录文件   保留为.part,服务器也随之而来。

您无法预测未来,也无法预测操作系统。如果由电源或硬件故障引起重启,则无法预测它。