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; }
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; }