static int run_controller()

in src/native/unix/native/jsvc-unix.c [1298:1406]


static int run_controller(arg_data *args, home_data *data, uid_t uid, gid_t gid)
{
    pid_t pid = 0;
    int restarts = 0;
    struct sigaction act;

    controller_pid = getpid();

    /*
     * Install signal handlers for the parent process.
     * These will be replaced in the child process.
     */
    memset(&act, '\0', sizeof(act));
    act.sa_sigaction = controller;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;

    sigaction(SIGHUP, &act, NULL);
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGUSR2, &act, NULL);
    sigaction(SIGTERM, &act, NULL);
    sigaction(SIGINT, &act, NULL);

    /* We have to fork: this process will become the controller and the other
       will be the child */
    while ((pid = fork()) != -1) {
        time_t laststart;
        int status = 0;
        /* We forked (again), if this is the child, we go on normally */
        if (pid == 0)
            exit(child(args, data, uid, gid));
        laststart = time(NULL);

        /* We are in the controller, we have to forward all interesting signals
           to the child, and wait for it to die */
        controlled = pid;

#ifdef OS_CYGWIN
        SetTerm(cygwincontroller);
#endif

        while (waitpid(pid, &status, 0) != pid) {
            /* Wait for process */
        }

        /* The child must have exited cleanly */
        if (WIFEXITED(status)) {
            status = WEXITSTATUS(status);

            /* Delete the pid file */
            if (args->vers != true && args->chck != true && status != 122)
                remove_pid_file(args, pid);

            /* If the child got out with 123 he wants to be restarted */
            /* See java_abort123 (we use this return code to restart when the JVM aborts) */
            if (!stopping) {
                if (status == 123) {
                    if (args->restarts == 0) {
                        log_debug("Service failure, restarts disabled");
                        return 1;
                    }
                    if (args->restarts != -1 && args->restarts <= restarts) {
                        log_debug("Service failure, restart limit reached, aborting");
                        return 1;
                    }
                    log_debug("Reloading service");
                    restarts++;
                    /* prevent looping */
                    if (laststart + 60 > time(NULL)) {
                        log_debug("Waiting 60 s to prevent looping");
                        sleep(60);
                    }
                    continue;
                }
            }
            /* If the child got out with 0 he is shutting down */
            if (status == 0) {
                log_debug("Service shut down");
                return 0;
            }
            /* Otherwise we don't rerun it */
            log_error("Service exit with a return value of %d", status);
            return 1;

        }
        else {
            if (WIFSIGNALED(status)) {
                log_error("Service killed by signal %d", WTERMSIG(status));
                /* prevent looping */
                if (!stopping) {
                    if (laststart + 60 > time(NULL)) {
                        log_debug("Waiting 60 s to prevent looping");
                        sleep(60);
                    }
                    /* Normal or user controlled termination, reset restart counter */
                    restarts = 0;
                    continue;
                }
            }
            log_error("Service did not exit cleanly", status);
            return 1;
        }
    }

    /* Got out of the loop? A fork() failed then. */
    log_error("Cannot decouple controller/child processes");
    return 1;

}