Exemplo n.º 1
0
int main (int argc, char *argv[])
{
    pthread_t           th[NA_ENV_MAX];
    na_env_t           *env[NA_ENV_MAX];
    mpool_t            *env_pool;
    int                 c;
    int                 env_cnt          = 0;
    bool                is_daemon        = false;
    struct json_object *conf_obj         = NULL;
    struct json_object *environments_obj = NULL;

    while (-1 != (c = getopt(argc, argv,
           "f:" /* configuration file with JSON */
           "t:" /* check configuration file */
           "d"  /* go to background */
           "v"  /* show version and information */
           "h"  /* show help */
    )))
    {
        switch (c) {
        case 'd':
            is_daemon = true;
            break;
        case 'f':
            ConfFile         = optarg;
            conf_obj         = na_get_conf(optarg);
            environments_obj = na_get_environments(conf_obj, &env_cnt);
            break;
        case 't':
            conf_obj         = na_get_conf(optarg);
            environments_obj = na_get_environments(conf_obj, &env_cnt);
            printf("JSON configuration is OK\n");
            return 0;
            break;
        case 'v':
            na_version();
            return 0;
            break;
        case 'h':
            na_usage();
            return 0;
            break;
        default:
            break;
        }
    }

    if (is_daemon && daemon(0, 0) == -1) {
        NA_DIE_WITH_ERROR(NA_ERROR_FAILED_DAEMONIZE);
    }

    if (env_cnt > NA_ENV_MAX) {
        NA_DIE_WITH_ERROR(NA_ERROR_TOO_MANY_ENVIRONMENTS);
    }

    StartTimestamp = time(NULL);
    na_setup_signals();
    na_memproto_bm_skip_init();

    env_pool = mpool_create(0);
    if (env_cnt == 0) {
        env_cnt = 1;
        env[0]  = na_env_add(&env_pool);
        na_env_setup_default(env[0], 0);
    } else {
        for (int i=0;i<env_cnt;++i) {
            env[i] = na_env_add(&env_pool);
            na_env_setup_default(env[i], i);
            na_conf_env_init(environments_obj, env[i], i, false);
        }
    }

    json_object_put(conf_obj);

    for (int i=0;i<env_cnt;++i) {
        env[i]->current_conn      = 0;
        env[i]->is_refused_active = false;
        env[i]->is_refused_accept = false;
        env[i]->is_worker_busy    = calloc(sizeof(bool), env[i]->worker_max);
        for (int j=0;j<env[i]->worker_max;++j) {
            env[i]->is_worker_busy[j] = false;
        }
        env[i]->error_count      = 0;
        env[i]->current_conn_max = 0;
        pthread_mutex_init(&env[i]->lock_connpool, NULL);
        pthread_mutex_init(&env[i]->lock_current_conn, NULL);
        pthread_mutex_init(&env[i]->lock_tid, NULL);
        pthread_mutex_init(&env[i]->lock_loop, NULL);
        pthread_mutex_init(&env[i]->lock_error_count, NULL);
        pthread_rwlock_init(&env[i]->lock_refused, NULL);
        pthread_rwlock_init(&env[i]->lock_request_bufsize_max, NULL);
        pthread_rwlock_init(&env[i]->lock_response_bufsize_max, NULL);
        pthread_rwlock_init(&LockReconf, NULL);
        env[i]->lock_worker_busy = calloc(sizeof(pthread_rwlock_t), env[i]->worker_max);
        for (int j=0;j<env[i]->worker_max;++j) {
            pthread_rwlock_init(&env[i]->lock_worker_busy[j], NULL);
        }
        na_connpool_create(&env[i]->connpool_active, env[i]->connpool_max);
        if (env[i]->is_use_backup) {
            na_connpool_create(&env[i]->connpool_backup, env[i]->connpool_max);
        }
    }

    for (int i=0;i<env_cnt;++i) {
        pthread_create(&th[i], NULL, na_event_loop, env[i]);
    }

    // monitoring signal
    while (true) {

        if (SigExit == 1) {
            break;
        }

        if (SigReconf == 1) {
            conf_obj         = na_get_conf(ConfFile);
            environments_obj = na_get_environments(conf_obj, &env_cnt);

            pthread_rwlock_wrlock(&LockReconf);
            for (int i=0;i<env_cnt;++i) {
                na_conf_env_init(environments_obj, env[i], i, true);
            }
            pthread_rwlock_unlock(&LockReconf);

            json_object_put(conf_obj);
            SigReconf = 0;
        }

        // XXX we should sleep forever and only wake upon a signal
        sleep(1);
    }

    for (int i=0;i<env_cnt;++i) {
        na_connpool_destroy(&env[i]->connpool_active);
        if (env[i]->is_use_backup) {
            na_connpool_destroy(&env[i]->connpool_backup);
        }
        pthread_mutex_destroy(&env[i]->lock_connpool);
        pthread_mutex_destroy(&env[i]->lock_current_conn);
        pthread_mutex_destroy(&env[i]->lock_tid);
        pthread_mutex_destroy(&env[i]->lock_error_count);
        pthread_rwlock_destroy(&env[i]->lock_refused);
        pthread_rwlock_destroy(&env[i]->lock_request_bufsize_max);
        pthread_rwlock_destroy(&env[i]->lock_response_bufsize_max);
        pthread_rwlock_destroy(&LockReconf);
        for (int j=0;j<env[i]->worker_max;++j) {
            pthread_rwlock_destroy(&env[i]->lock_worker_busy[j]);
        }
        NA_FREE(env[i]->is_worker_busy);
        NA_FREE(env[i]->lock_worker_busy);
        pthread_detach(th[i]);
    }

    mpool_destroy(env_pool);

    return 0;
}
Exemplo n.º 2
0
int main (int argc, char *argv[])
{
    int                 c;
    na_env_t            env;              // for child
    na_env_t            envs[NA_ENV_MAX]; // for master
    na_ctl_env_t        env_ctl;
    pthread_t           event_th, ctl_th;
    int                 env_cnt          = 0;
    bool                is_daemon        = false;
    struct json_object *conf_obj         = NULL;
    struct json_object *environments_obj = NULL;
    struct json_object *ctl_obj          = NULL;
    pid_t pids[NA_PID_MAX];
    int pidx;
    fnv_ent_t ent_env[NA_PID_MAX];
    fnv_tbl_t *tbl_env;
    char conf_file[NA_PATH_MAX + 1];
    sigset_t ss;
    int sig;

    GracefulPhase = NA_GRACEFUL_PHASE_DISABLED;

    while (-1 != (c = getopt(argc, argv,
                             "f:" /* configuration file with JSON */
                             "t:" /* check configuration file */
                             "d"  /* go to background */
                             "v"  /* show version and information */
                             "h"  /* show help */
                             )))
    {
        switch (c) {
        case 'd':
            is_daemon = true;
            break;
        case 'f':
            strncpy(conf_file, optarg, NA_PATH_MAX + 1);
            conf_obj         = na_get_conf(optarg);
            environments_obj = na_get_environments(conf_obj, &env_cnt);
            break;
        case 't':
            conf_obj         = na_get_conf(optarg);
            environments_obj = na_get_environments(conf_obj, &env_cnt);
            printf("JSON configuration is OK\n");
            return 0;
            break;
        case 'v':
            na_version();
            return 0;
            break;
        case 'h':
            na_usage();
            return 0;
            break;
        default:
            break;
        }
    }

    if (is_daemon && daemon(0, 0) == -1) {
        NA_DIE_WITH_ERROR(NULL, NA_ERROR_FAILED_DAEMONIZE);
    }

    if (env_cnt > NA_ENV_MAX) {
        NA_DIE_WITH_ERROR(NULL, NA_ERROR_TOO_MANY_ENVIRONMENTS);
    }

    StartTimestamp = time(NULL);
    na_setup_ignore_signals();

    tbl_env   = fnv_tbl_create(ent_env, NA_PID_MAX);
    MasterPid = getpid();
    pidx      = 0;
    for (int i=0;i<env_cnt;++i) {
        pidx++;
        pid_t pid = fork();
        if (pid == -1) {
            NA_DIE_WITH_ERROR(NULL, NA_ERROR_FAILED_CREATE_PROCESS);
        } else if (pid == 0) { // child
            break;
        } else {
            pids[i] = pid;
        }
    }

    if (na_is_master_process()) {
        if (conf_obj == NULL) {
            NA_DIE_WITH_ERROR(NULL, NA_ERROR_INVALID_CONFPATH);
        }
        na_set_env_proc_name(argv[0], "master");
        for (int i=0;i<env_cnt;++i) {
            na_env_setup_default(&envs[i], i);
            na_conf_env_init(environments_obj, &envs[i], i);
            fnv_put(tbl_env, envs[i].name, &pids[i], strlen(envs[i].name), sizeof(pid_t));
        }
        memset(&env_ctl, 0, sizeof(na_ctl_env_t));
        na_ctl_env_setup_default(&env_ctl);
        ctl_obj = na_get_ctl(conf_obj);
        na_conf_ctl_init(ctl_obj, &env_ctl);
        env_ctl.tbl_env = tbl_env;
        pthread_mutex_init(&env_ctl.lock_restart, NULL);
        pthread_create(&ctl_th, NULL, na_ctl_loop, &env_ctl);
        goto MASTER_CYCLE;
    }

    na_memproto_bm_skip_init();

    memset(&env, 0, sizeof(env));
    if (env_cnt == 0) {
        na_env_setup_default(&env, 0);
    } else {
        na_env_setup_default(&env, pidx);
        na_conf_env_init(environments_obj, &env, pidx - 1);
    }

    na_set_env_proc_name(argv[0], env.name);
    na_env_init(&env);
    pthread_create(&event_th, NULL, na_event_loop, &env);

 MASTER_CYCLE:

    json_object_put(conf_obj);

    if (na_is_master_process()) {
        na_setup_signals_for_master(&ss);
    } else {
        na_setup_signals_for_worker(&ss);
    }

    // monitoring signal
    while (true) {

        if (!na_is_master_process()) {
            if (sigwait(&ss, &sig) != 0) {
                continue;
            }
            switch (sig) {
            case SIGTERM:
            case SIGINT:
            case SIGHUP:
                goto exit;
            case SIGUSR2:
                if (GracefulPhase == NA_GRACEFUL_PHASE_DISABLED) {
                    sleep(5);
                    GracefulPhase = NA_GRACEFUL_PHASE_ENABLED;
                }
                // wait until available connection becomes zero
                while (true) {
                    pthread_mutex_lock(&env.lock_current_conn);
                    if (env.current_conn == 0) {
                        pthread_mutex_unlock(&env.lock_current_conn);
                        goto exit;
                    }
                    pthread_mutex_unlock(&env.lock_current_conn);
                    sleep(1);
                }
                break;
            default:
                break;
            }
            continue;
        }

        // for master process
        if (sigwait(&ss, &sig) != 0) {
            continue;
        }

        switch (sig) {
        case SIGTERM:
        case SIGINT:
        case SIGHUP:
            na_process_shutdown(pids, env_cnt);
            goto exit;
        case SIGCONT:
            if (strlen(env_ctl.restart_envname) > 0) {
                pid_t pid = fork();
                void *th_ret;
                int ridx;
                conf_obj         = na_get_conf(conf_file);
                environments_obj = na_get_environments(conf_obj, &env_cnt);
                ridx             = na_conf_get_environment_idx(environments_obj, env_ctl.restart_envname);
                if (pid == -1) {
                    pthread_mutex_unlock(&env_ctl.lock_restart);
                    NA_CTL_DIE_WITH_ERROR(&env_ctl, NA_ERROR_FAILED_CREATE_PROCESS);
                } else if (pid == 0) { // child
                    pthread_cancel(ctl_th);
                    pthread_join(ctl_th, &th_ret);

                    na_setup_signals_for_worker(&ss);
                    
                    na_memproto_bm_skip_init();
                    
                    memset(&env, 0, sizeof(env));
                    na_env_setup_default(&env, ridx);
                    na_conf_env_init(environments_obj, &env, ridx);
                    argv[0][strlen(argv[0]) - (sizeof(": master") - 1)] = '\0';
                    na_set_env_proc_name(argv[0], env.name);
                    na_env_init(&env);
                    pthread_create(&event_th, NULL, na_event_loop, &env);
                    json_object_put(conf_obj);
                } else { // master
                    int status;
                    waitpid(pids[ridx], &status, 0);
                    pids[ridx] = pid;
                }
                env_ctl.restart_envname[0] = '\0';
            }
            break;
        case SIGWINCH:
            if (env_cnt >= NA_ENV_MAX) {
                continue;
            }
            pid_t pid = fork();
            int env_cnt_prev;
            int status;
            env_cnt_prev = env_cnt;
            conf_obj         = na_get_conf(conf_file);
            environments_obj = na_get_environments(conf_obj, &env_cnt);
            if (env_cnt_prev != env_cnt - 1) {
                if (pid == 0) {
                    NA_CTL_DIE_WITH_ERROR(&env_ctl, NA_ERROR_UNKNOWN);
                } else {
                    waitpid(pid, &status, 0);
                }
            } else {
                if (pid == -1) {
                    NA_CTL_DIE_WITH_ERROR(&env_ctl, NA_ERROR_FAILED_CREATE_PROCESS);
                } else if (pid == 0) { // child
                    na_setup_signals_for_worker(&ss);
                    na_memproto_bm_skip_init();
                    memset(&env, 0, sizeof(env));
                    na_env_setup_default(&env, env_cnt - 1);
                    na_conf_env_init(environments_obj, &env, env_cnt - 1);
                    argv[0][strlen(argv[0]) - (sizeof(": master") - 1)] = '\0';
                    na_set_env_proc_name(argv[0], env.name);
                    na_env_init(&env);
                    pthread_create(&event_th, NULL, na_event_loop, &env);
                    json_object_put(conf_obj);
                } else { // master
                    char *envname = na_conf_get_environment_name(environments_obj, env_cnt - 1);
                    pids[env_cnt - 1] = pid;
                    fnv_put(tbl_env, envname, &pids[env_cnt - 1], strlen(envname), sizeof(pid_t));
                }
            }
            break;
        case SIGUSR1:
            na_on_the_fly_update(&env_ctl, conf_file, pids, env_cnt);
            goto exit;
        case SIGCHLD:
            {
                int status;
                pid_t pid = wait(&status);
                int idx = -1;
                if (status == 0) {
                    continue;
                }
                for (int i=0;i<env_cnt;i++) {
                    if (pid == pids[i]) {
                        idx = i;
                        break;
                    }
                }
                if (idx == -1) {
                    NA_CTL_DIE_WITH_ERROR(&env_ctl, NA_ERROR_UNKNOWN);
                }
                pid = fork();
                conf_obj         = na_get_conf(conf_file);
                environments_obj = na_get_environments(conf_obj, &env_cnt);
                if (pid == -1) {
                    NA_CTL_DIE_WITH_ERROR(&env_ctl, NA_ERROR_FAILED_CREATE_PROCESS);
                } else if (pid == 0) {
                    na_setup_signals_for_worker(&ss);
                    na_memproto_bm_skip_init();
                    memset(&env, 0, sizeof(env));
                    na_env_setup_default(&env, idx);
                    na_conf_env_init(environments_obj, &env, idx);
                    argv[0][strlen(argv[0]) - (sizeof(": master") - 1)] = '\0';
                    na_set_env_proc_name(argv[0], env.name);
                    na_env_init(&env);
                    pthread_create(&event_th, NULL, na_event_loop, &env);
                    json_object_put(conf_obj);
                } else {
                    pids[idx] = pid;
                }
            }
            break;
        default:
            assert(false);
            break;
        }

    }

 exit:

    return 0;
}