struct json_object *na_get_conf (const char *conf_file_json) { struct json_object *conf_obj; char json_buf[NA_JSON_BUF_MAX + 1]; int json_fd, size; if ((json_fd = open(conf_file_json, O_RDONLY)) < 0) { NA_DIE_WITH_ERROR(NA_ERROR_INVALID_CONFPATH); } memset(json_buf, 0, NA_JSON_BUF_MAX + 1); if ((size = read(json_fd, json_buf, NA_JSON_BUF_MAX)) < 0) { NA_DIE_WITH_ERROR(NA_ERROR_INVALID_CONFPATH); } conf_obj = json_tokener_parse(json_buf); if (is_error(conf_obj)) { NA_DIE_WITH_ERROR(NA_ERROR_PARSE_JSON_CONFIG); } close(json_fd); return conf_obj; }
static void na_setup_signals (void) { struct sigaction sig_exit_handler; struct sigaction sig_clear_handler; struct sigaction sig_reconf_handler; sigemptyset(&sig_exit_handler.sa_mask); sigemptyset(&sig_clear_handler.sa_mask); sigemptyset(&sig_reconf_handler.sa_mask); sig_exit_handler.sa_handler = na_signal_exit_handler; sig_clear_handler.sa_handler = na_signal_clear_handler; sig_reconf_handler.sa_handler = na_signal_reconf_handler; sig_exit_handler.sa_flags = 0; sig_clear_handler.sa_flags = 0; sig_reconf_handler.sa_flags = 0; if (sigaction(SIGTERM, &sig_exit_handler, NULL) == -1 || sigaction(SIGINT, &sig_exit_handler, NULL) == -1 || sigaction(SIGALRM, &sig_exit_handler, NULL) == -1 || sigaction(SIGHUP, &sig_exit_handler, NULL) == -1 || sigaction(SIGUSR1, &sig_clear_handler, NULL) == -1 || sigaction(SIGUSR2, &sig_reconf_handler, NULL) == -1) { NA_DIE_WITH_ERROR(NA_ERROR_FAILED_SETUP_SIGNAL); } if (sigignore(SIGPIPE) == -1) { NA_DIE_WITH_ERROR(NA_ERROR_FAILED_IGNORE_SIGNAL); } SigExit = 0; SigClear = 0; SigReconf = 0; }
void na_connpool_init (na_env_t *env) { for (int i=0;i<env->connpool_max;++i) { env->connpool_active.fd_pool[i] = na_target_server_tcpsock_init(); na_target_server_tcpsock_setup(env->connpool_active.fd_pool[i], true); if (env->connpool_active.fd_pool[i] <= 0) { NA_DIE_WITH_ERROR(env, NA_ERROR_INVALID_FD); } } }
void na_connpool_assign_internal (na_env_t *env, na_connpool_t *connpool, int i, int *cur, int *fd, na_server_t *server) { if (connpool->active[i] == 0) { connpool->active[i] = 1; if (!na_server_connect(connpool->fd_pool[i], &server->addr)) { if (errno != EINPROGRESS && errno != EALREADY) { NA_DIE_WITH_ERROR(env, NA_ERROR_CONNECTION_FAILED); } } } connpool->mark[i] = 1; *fd = connpool->fd_pool[i]; *cur = i; }
void na_connpool_switch (na_env_t *env) { na_connpool_t *connpool; if (env->is_refused_active) { na_connpool_deactivate(&env->connpool_active); connpool = &env->connpool_backup; } else { na_connpool_deactivate(&env->connpool_backup); connpool = &env->connpool_active; } for (int i=0;i<env->connpool_max;++i) { connpool->fd_pool[i] = na_target_server_tcpsock_init(); na_target_server_tcpsock_setup(connpool->fd_pool[i], true); if (connpool->fd_pool[i] <= 0) { NA_DIE_WITH_ERROR(env, NA_ERROR_INVALID_FD); } } }
void na_conf_env_init(struct json_object *environments_obj, na_env_t *na_env, int idx, bool reconf) { char *e; char host_buf[NA_HOSTNAME_MAX + 1]; na_host_t host; struct json_object *environment_obj; struct json_object *param_obj; environment_obj = json_object_array_get_idx(environments_obj, idx); for (int i=0;i<NA_PARAM_MAX;++i) { param_obj = json_object_object_get(environment_obj, na_param_name(i)); if (param_obj == NULL) { continue; } // runtime-reconfigurable parameters switch (i) { case NA_PARAM_IS_CONNPOOL_ONLY: NA_PARAM_TYPE_CHECK(param_obj, json_type_boolean); na_env->is_connpool_only = json_object_get_boolean(param_obj) == 1 ? true : false; continue; case NA_PARAM_REQUEST_BUFSIZE: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->request_bufsize = json_object_get_int(param_obj); continue; case NA_PARAM_REQUEST_BUFSIZE_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->request_bufsize_max = json_object_get_int(param_obj); continue; case NA_PARAM_RESPONSE_BUFSIZE: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->response_bufsize = json_object_get_int(param_obj); continue; case NA_PARAM_RESPONSE_BUFSIZE_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->response_bufsize_max = json_object_get_int(param_obj); continue; case NA_PARAM_CONN_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->conn_max = json_object_get_int(param_obj); continue; case NA_PARAM_ERROR_COUNT_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->error_count_max = json_object_get_int(param_obj); continue; default: break; } // if we didn't find a reconfigurable parameter, try the others if (!reconf) { switch (i) { case NA_PARAM_NAME: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->name, json_object_get_string(param_obj), NA_NAME_MAX); break; case NA_PARAM_SOCKPATH: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->fssockpath, json_object_get_string(param_obj), NA_SOCKPATH_MAX); break; case NA_PARAM_TARGET_SERVER: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(host_buf, json_object_get_string(param_obj), NA_HOSTNAME_MAX); host = na_create_host(host_buf); memcpy(&na_env->target_server.host, &host, sizeof(host)); na_set_sockaddr(&host, &na_env->target_server.addr); break; case NA_PARAM_BACKUP_SERVER: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(host_buf, json_object_get_string(param_obj), NA_HOSTNAME_MAX); host = na_create_host(host_buf); memcpy(&na_env->backup_server.host, &host, sizeof(host)); na_set_sockaddr(&host, &na_env->backup_server.addr); na_env->is_use_backup = true; break; case NA_PARAM_PORT: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->fsport = json_object_get_int(param_obj); break; case NA_PARAM_STPORT: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->stport = json_object_get_int(param_obj); break; case NA_PARAM_STSOCKPATH: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->stsockpath, json_object_get_string(param_obj), NA_SOCKPATH_MAX); break; case NA_PARAM_ACCESS_MASK: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); na_env->access_mask = (mode_t)strtol(json_object_get_string(param_obj), &e, 8); break; case NA_PARAM_WORKER_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->worker_max = json_object_get_int(param_obj); break; case NA_PARAM_CONNPOOL_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->connpool_max = json_object_get_int(param_obj); break; case NA_PARAM_CONNPOOL_USE_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->connpool_use_max = json_object_get_int(param_obj); break; case NA_PARAM_CLIENT_POOL_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->client_pool_max = json_object_get_int(param_obj); break; case NA_PARAM_LOOP_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->loop_max = json_object_get_int(param_obj); break; case NA_PARAM_EVENT_MODEL: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); na_env->event_model = na_detect_event_model(json_object_get_string(param_obj)); if (na_env->event_model == NA_EVENT_MODEL_UNKNOWN) { NA_DIE_WITH_ERROR(NA_ERROR_INVALID_JSON_CONFIG); } break; default: // no through assert(false); break; } } } na_env->is_extensible_request_buf = na_env->request_bufsize < na_env->request_bufsize_max ? true : false; na_env->is_extensible_response_buf = na_env->response_bufsize < na_env->response_bufsize_max ? true : false; }
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; }
void na_conf_env_init(struct json_object *environments_obj, na_env_t *na_env, int idx) { char *e; char host_buf[NA_HOSTNAME_MAX + 1]; na_host_t host; struct json_object *environment_obj; struct json_object *param_obj; bool have_log_path_opt; bool have_slow_query_log_path_opt; have_log_path_opt = false; have_slow_query_log_path_opt = false; environment_obj = json_object_array_get_idx(environments_obj, idx); for (int i=0;i<NA_PARAM_MAX;++i) { double slow_query_sec; param_obj = json_object_object_get(environment_obj, na_param_name(i)); if (param_obj == NULL) { continue; } // runtime-reconfigurable parameters switch (i) { case NA_PARAM_REQUEST_BUFSIZE: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->request_bufsize = json_object_get_int(param_obj); break; case NA_PARAM_RESPONSE_BUFSIZE: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->response_bufsize = json_object_get_int(param_obj); break; case NA_PARAM_CONN_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->conn_max = json_object_get_int(param_obj); break; case NA_PARAM_LOG_ACCESS_MASK: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); na_env->log_access_mask = (mode_t)strtol(json_object_get_string(param_obj), &e, 8); break; case NA_PARAM_SLOW_QUERY_SEC: NA_PARAM_TYPE_CHECK(param_obj, json_type_double); slow_query_sec = json_object_get_double(param_obj); na_env->slow_query_sec.tv_sec = slow_query_sec; na_env->slow_query_sec.tv_nsec = 1000000000L * (slow_query_sec - (long)slow_query_sec); break; case NA_PARAM_SLOW_QUERY_LOG_PATH: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->slow_query_log_path, json_object_get_string(param_obj), NA_PATH_MAX); have_slow_query_log_path_opt = true; break; case NA_PARAM_LOGPATH: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->logpath, json_object_get_string(param_obj), NA_PATH_MAX); have_log_path_opt = true; break; case NA_PARAM_SLOW_QUERY_LOG_ACCESS_MASK: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); na_env->slow_query_log_access_mask = (mode_t)strtol(json_object_get_string(param_obj), &e, 8); break; case NA_PARAM_NAME: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->name, json_object_get_string(param_obj), NA_NAME_MAX); break; case NA_PARAM_SOCKPATH: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->fssockpath, json_object_get_string(param_obj), NA_PATH_MAX); break; case NA_PARAM_TARGET_SERVER: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(host_buf, json_object_get_string(param_obj), NA_HOSTNAME_MAX); host = na_create_host(host_buf); memcpy(&na_env->target_server.host, &host, sizeof(host)); na_set_sockaddr(&host, &na_env->target_server.addr); break; case NA_PARAM_BACKUP_SERVER: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(host_buf, json_object_get_string(param_obj), NA_HOSTNAME_MAX); host = na_create_host(host_buf); memcpy(&na_env->backup_server.host, &host, sizeof(host)); na_set_sockaddr(&host, &na_env->backup_server.addr); na_env->is_use_backup = true; break; case NA_PARAM_PORT: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->fsport = json_object_get_int(param_obj); break; case NA_PARAM_STPORT: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->stport = json_object_get_int(param_obj); break; case NA_PARAM_STSOCKPATH: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); strncpy(na_env->stsockpath, json_object_get_string(param_obj), NA_PATH_MAX); break; case NA_PARAM_ACCESS_MASK: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); na_env->access_mask = (mode_t)strtol(json_object_get_string(param_obj), &e, 8); break; case NA_PARAM_WORKER_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->worker_max = json_object_get_int(param_obj); break; case NA_PARAM_CONNPOOL_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->connpool_max = json_object_get_int(param_obj); break; case NA_PARAM_CLIENT_POOL_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->client_pool_max = json_object_get_int(param_obj); break; case NA_PARAM_LOOP_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->loop_max = json_object_get_int(param_obj); break; case NA_PARAM_EVENT_MODEL: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); na_env->event_model = na_detect_event_model(json_object_get_string(param_obj)); if (na_env->event_model == NA_EVENT_MODEL_UNKNOWN) { NA_DIE_WITH_ERROR(na_env, NA_ERROR_INVALID_JSON_CONFIG); } break; case NA_PARAM_SLOW_QUERY_LOG_FORMAT: NA_PARAM_TYPE_CHECK(param_obj, json_type_string); na_env->slow_query_log_format = na_detect_log_format(json_object_get_string(param_obj)); if (na_env->slow_query_log_format == NA_LOG_FORMAT_UNKNOWN) { NA_DIE_WITH_ERROR(na_env, NA_ERROR_INVALID_JSON_CONFIG); } break; case NA_PARAM_TRY_MAX: NA_PARAM_TYPE_CHECK(param_obj, json_type_int); na_env->try_max = json_object_get_int(param_obj); break; default: // no through assert(false); break; } } // open log, if enabled if (have_log_path_opt) { na_log_open(na_env); } // open slow query log, if enabled if (((na_env->slow_query_sec.tv_sec != 0) || (na_env->slow_query_sec.tv_nsec != 0))) { if (!have_slow_query_log_path_opt) { NA_DIE_WITH_ERROR(na_env, NA_ERROR_INVALID_JSON_CONFIG); } else { na_slow_query_open(na_env); } } }
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; }