Ejemplo n.º 1
0
static void mainloop(unsigned sleep_interval,
                     int      pipe_to_child,
                     int      pipe_from_child)
{
    int child_ping_count = 0;

    // NOTE: One should NOT do anything potentially blocking in the mainloop.
    //       Otherwise we run the risk of being late to kick the HW watchdogs.
    while (run) {
        // kick WD's right before sleep
        dsme_wd_kick();

        // sleep precisely
        struct timespec remaining_sleep_time = { sleep_interval, 0 };
        while (nanosleep(&remaining_sleep_time, &remaining_sleep_time) == -1 &&
               errno == EINTR)
        {
            // interrupt could mean that someone wants to force a WD kick;
            // also, we have to kick just before stopping running
            dsme_wd_kick();
            if (!run) {
                goto done_running;
            }

            // interrupt may have come from the dsme server; consider it alive
            child_ping_count = 0;
        }

        // kick WD's right after sleep
        dsme_wd_kick();

        // make sure the dsme server (the child) is alive
        if (pong(pipe_from_child)) {
            child_ping_count = 0;
        } else if (child_ping_count >= DSME_MAXPING) {
            // dsme server has failed to respond in due time
            fprintf(stderr, ME "dsme-server nonresponsive; quitting\n");
            run = false;
            dsme_abnormal_exit = true;
            goto done_running;
        }

        // ping the dsme server
        ping(pipe_to_child);
        ++child_ping_count;
    }

done_running:
    return;
}
Ejemplo n.º 2
0
/**
  @todo Possibility to alter priority of initial module somehow
  */
int main(int argc, char *argv[])
{
    fprintf(stderr, "DSME %s starting up\n", STRINGIFY(PRG_VERSION));

    // lock to ram (will not be inherited)
    if (mlockall(MCL_FUTURE) == -1) {
        fprintf(stderr, ME "Couldn't lock to RAM: %s\n", strerror(errno));
    }

    // do the first kick right away
    if (!dsme_wd_init()) {
        fprintf(stderr, ME "no WD's opened; WD kicking disabled\n");
    }
    dsme_wd_kick();

    // set up signal handler
    signal(SIGHUP,  signal_handler);
    signal(SIGINT,  signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGPIPE, signal_handler);
    signal(SIGCHLD, signal_handler);


    // protect from oom
    if (!protect_from_oom()) {
        fprintf(stderr, ME "Couldn't protect from oom: %s\n", strerror(errno));
    }

    // set priority/niceness (will be inherited)
    if (setpriority(PRIO_PROCESS, 0, DSME_NICE) == -1) {
        fprintf(stderr, ME "Couldn't set the priority: %s\n", strerror(errno));
    }

    // set scheduler (will be inherited)
    struct sched_param sch;
    memset(&sch, 0, sizeof(sch));
    sch.sched_priority = sched_get_priority_max(DSME_HB_SCHEDULER);
    if (sched_setscheduler(0, DSME_HB_SCHEDULER, &sch) == -1) {
        fprintf(stderr, ME "Couldn't set the scheduler: %s\n", strerror(errno));
    }

    // parse command line options
    int daemon = 0;
    parse_options(argc, argv, &daemon);

    // daemonize
    if (daemon && daemonize() == -1) {
        return EXIT_FAILURE;
    }

    // set running directory
    if (chdir("/") == -1) {
        fprintf(stderr, ME "chdir failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    // open communication pipes
    int to_child[2];
    int from_child[2];
    if (pipe(to_child) != 0 || pipe(from_child) != 0) {
        fprintf(stderr, ME "pipe failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    // fork and exec the dsme server
    pid_t pid;
    if ((pid = fork()) == -1) {
        fprintf(stderr, ME "fork failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    } else if (pid == 0) {
        // child

        // TODO: lower priority
        // TODO: restore scheduler

        // child gets the pipes in stdin & stdout
        if (dup2(to_child[0], STDIN_FILENO) != STDIN_FILENO) {
            fprintf(stderr, ME "dup2 failed: %s\n", strerror(errno));
            return EXIT_FAILURE;
        }
        if (dup2(from_child[1], STDOUT_FILENO) != STDOUT_FILENO) {
            fprintf(stderr, ME "dup2 failed: %s\n", strerror(errno));
            return EXIT_FAILURE;
        }

        // close all the other descriptors
        int max_fd_count = getdtablesize();
        if (max_fd_count == -1) {
            max_fd_count = 256;
        }
        for (int i = 3; i < max_fd_count; ++i) {
            (void)close(i);
        }

        // exec dsme server core
        char* newargv[argc+1];
        newargv[0] = (char*)DSME_SERVER_PATH;
        for (int i = 1; i < argc; ++i) {
            newargv[i] = argv[i];
        }
        newargv[argc] = 0;
        execv(DSME_SERVER_PATH, newargv);
        fprintf(stderr, ME "execv failed: %s\n", strerror(errno));
        return EXIT_FAILURE;

    } else {
        // parent

        // close child ends of pipes & set parent ends of pipes non-blocking
        close(to_child[0]);
        close(from_child[1]);
        set_nonblocking(to_child[1]);
        set_nonblocking(from_child[0]);
    }

    unsigned sleep_interval = DSME_HEARTBEAT_INTERVAL;
    fprintf(stderr,
            ME "Entering main loop, with %u s interval\n",
            sleep_interval);
    mainloop(sleep_interval, to_child[1], from_child[0]);
    fprintf(stderr, ME "Exited main loop, quitting\n");

    // also bring dsme server down
    kill(pid, SIGTERM);
    (void)waitpid(pid, 0, 0);

    if (remove(DSME_PID_FILE) < 0) {
        fprintf(stderr, ME "Couldn't remove lockfile\n");
    }

    return EXIT_SUCCESS;
}
Ejemplo n.º 3
0
/**
  @todo Possibility to alter priority of initial module somehow
  */
int main(int argc, char *argv[])
{
    fprintf(stderr, "DSME %s starting up\n", STRINGIFY(PRG_VERSION));

    // do the first kick right away
    if (!dsme_wd_init()) {
        fprintf(stderr, ME "no WD's opened; WD kicking disabled\n");
    }
    dsme_wd_kick();

    trap_terminating_signals();

    // set up signal handler
    signal(SIGHUP,  signal_handler);
    signal(SIGINT,  signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGPIPE, signal_handler);
    signal(SIGCHLD, signal_handler);
#ifdef DSME_SYSTEMD_ENABLE
    signal(SIGUSR1, signal_handler);
#endif


    // protect from oom
    if (!protect_from_oom()) {
        fprintf(stderr, ME "Couldn't protect from oom: %s\n", strerror(errno));
    }

    // set priority/niceness (will be inherited)
    if (setpriority(PRIO_PROCESS, 0, DSME_NICE) == -1) {
        fprintf(stderr, ME "Couldn't set the priority: %s\n", strerror(errno));
    }

    // set scheduler (will be inherited)
    struct sched_param sch;
    memset(&sch, 0, sizeof(sch));
    sch.sched_priority = sched_get_priority_max(DSME_HB_SCHEDULER);
    if (sched_setscheduler(0, DSME_HB_SCHEDULER, &sch) == -1) {
        fprintf(stderr, ME "Couldn't set the scheduler: %s\n", strerror(errno));
    }

    // lock to ram (will not be inherited)
    if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
        fprintf(stderr, ME "Couldn't lock to RAM: %s\n", strerror(errno));
    }


    // parse command line options
    int daemon = 0;
    parse_options(argc, argv, &daemon);

    // daemonize
    if (daemon && daemonize() == -1) {
        return EXIT_FAILURE;
    }

    // set running directory
    if (chdir("/") == -1) {
        fprintf(stderr, ME "chdir failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    // open communication pipes
    int to_child[2];
    int from_child[2];
    if (pipe(to_child) != 0 || pipe(from_child) != 0) {
        fprintf(stderr, ME "pipe failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    // fork and exec the dsme server
    pid_t pid;
    if ((pid = fork()) == -1) {
        fprintf(stderr, ME "fork failed: %s\n", strerror(errno));
        return EXIT_FAILURE;
    } else if (pid == 0) {
        // child

        // TODO: lower priority
        // TODO: restore scheduler

        // child gets the pipes in stdin & stdout
        if (dup2(to_child[0], STDIN_FILENO) != STDIN_FILENO) {
            fprintf(stderr, ME "dup2 failed: %s\n", strerror(errno));
            _exit(EXIT_FAILURE);
        }
        if (dup2(from_child[1], STDOUT_FILENO) != STDOUT_FILENO) {
            fprintf(stderr, ME "dup2 failed: %s\n", strerror(errno));
            _exit(EXIT_FAILURE);
        }

        // close all the other descriptors
        int max_fd_count = getdtablesize();
        if (max_fd_count == -1) {
            max_fd_count = 256;
        }
        for (int i = 3; i < max_fd_count; ++i) {
            (void)close(i);
        }

        // exec dsme server core
        char* newargv[argc+1];
        newargv[0] = (char*)DSME_SERVER_PATH;
        for (int i = 1; i < argc; ++i) {
            newargv[i] = argv[i];
        }
        newargv[argc] = 0;
        execv(DSME_SERVER_PATH, newargv);
        fprintf(stderr,
                ME "execv failed: %s: %s\n",
                DSME_SERVER_PATH,
                strerror(errno));
        _exit(EXIT_FAILURE);

    } else {
        // parent

        // close child ends of pipes & set parent ends of pipes non-blocking
        close(to_child[0]);
        close(from_child[1]);
        set_nonblocking(to_child[1]);
        set_nonblocking(from_child[0]);
    }

    /* Before entering the mainloop, clear wakelock that might be set if dsme
     * is restarting after signal / watchdog pingpong failure */
    release_restart_wakelock();

    unsigned sleep_interval = DSME_HEARTBEAT_INTERVAL;
    mainloop(sleep_interval, to_child[1], from_child[0]);
    fprintf(stderr, ME "Exited main loop, quitting\n");

    /* Get wakelock after exiting the mainloop, will be cleared
     * if we make orderly normal exit */
    obtain_restart_wakelock();

    /* Bring down the dsme-server child process
     *
     * Note: The maximum duration we can spend here must be shorter
     *       than both hw watchdog kick period and the time systemd
     *       allows for dsme itself to exit.
     */

    // kick watchdogs so we have time to wait for dsme-server to exit
    dsme_wd_kick();

    if( kill_and_wait(pid, SIGTERM, 8) || kill_and_wait(pid, SIGKILL, 3) ) {
        // clear nowayout states and close watchdog files
        dsme_wd_quit();
    }
    else {
        // leave the nowayout states on so that we will get a wd reboot
        // shortly after dsme exits, but kick the watchdogs one more time
        // to give the system some time to make orderly shutdown
        dsme_wd_kick();
        fprintf(stderr, ME "dsme-server stop failed, leaving watchdogs"
                " active\n");
        dsme_abnormal_exit = true;
    }

    /* Remove the PID file */
    if (remove(DSME_PID_FILE) < 0 && errno != ENOENT) {
        fprintf(stderr, ME "Couldn't remove lockfile: %m\n");
    }

    /* Clear wakelock on normal, successful exit */
    if( dsme_abnormal_exit )
        fprintf(stderr, ME "abnormal exit, leaving wakelock active\n");
    else
        release_restart_wakelock();

    fprintf(stderr, "DSME %s terminating\n", STRINGIFY(PRG_VERSION));
    return dsme_abnormal_exit ? EXIT_FAILURE : EXIT_SUCCESS;
}