struct iobroker_set *iobroker_create(void) { iobroker_set *iobs = NULL; iobs = calloc(1, sizeof(*iobs)); if (!iobs) { goto error_out; } iobs->max_fds = iobroker_max_usable_fds(); iobs->iobroker_fds = calloc(iobs->max_fds, sizeof(iobroker_fd *)); if (!iobs->iobroker_fds) { goto error_out; } #ifdef IOBROKER_USES_EPOLL { int flags; iobs->ep_events = calloc(iobs->max_fds, sizeof(struct epoll_event)); if (!iobs->ep_events) { goto error_out; } iobs->epfd = epoll_create(iobs->max_fds); if (iobs->epfd < 0) { goto error_out; } flags = fcntl(iobs->epfd, F_GETFD); flags |= FD_CLOEXEC; fcntl(iobs->epfd, F_SETFD, flags); } #elif !defined(IOBROKER_USES_SELECT) iobs->pfd = calloc(iobs->max_fds, sizeof(struct pollfd)); if (!iobs->pfd) goto error_out; #endif return iobs; error_out: if (iobs) { int errsv = errno; #ifdef IOBROKER_USES_EPOLL close(iobs->epfd); if (iobs->ep_events) free(iobs->ep_events); #endif if (iobs->iobroker_fds) free(iobs->iobroker_fds); free(iobs); errno = errsv; } return NULL; }
struct worker_process *spawn_worker(void (*init_func)(void *), void *init_arg) { int sv[2]; int pid; if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) return NULL; pid = fork(); if (pid < 0) { close(sv[0]); close(sv[1]); return NULL; } /* parent leaves the child */ if (pid) { worker_process *worker = calloc(1, sizeof(worker_process)); close(sv[1]); if (!worker) { kill(SIGKILL, pid); close(sv[0]); return NULL; } worker->sd = sv[0]; worker->pid = pid; worker->ioc = iocache_create(1 * 1024 * 1024); /* 1 socket for master, 2 fd's for each child */ worker->max_jobs = (iobroker_max_usable_fds() - 1) / 2; worker->jobs = calloc(worker->max_jobs, sizeof(worker_job *)); return worker; } /* child closes parent's end of socket and gets busy */ close(sv[0]); if (init_func) { init_func(init_arg); } enter_worker(sv[1]); /* not reached, ever */ exit(EXIT_FAILURE); }
/* a service for registering workers */ static int register_worker(int sd, char *buf, unsigned int len) { int i, is_global = 1; struct kvvec *info; struct wproc_worker *worker; logit(NSLOG_INFO_MESSAGE, TRUE, "wproc: Registry request: %s\n", buf); if (!(worker = calloc(1, sizeof(*worker)))) { logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to allocate worker: %s\n", strerror(errno)); return 500; } info = buf2kvvec(buf, len, '=', ';', 0); if (info == NULL) { free(worker); logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to parse registration request\n"); return 500; } worker->sd = sd; worker->ioc = iocache_create(1 * 1024 * 1024); iobroker_unregister(nagios_iobs, sd); iobroker_register(nagios_iobs, sd, worker, handle_worker_result); for(i = 0; i < info->kv_pairs; i++) { struct key_value *kv = &info->kv[i]; if (!strcmp(kv->key, "name")) { worker->name = strdup(kv->value); } else if (!strcmp(kv->key, "pid")) { worker->pid = atoi(kv->value); } else if (!strcmp(kv->key, "max_jobs")) { worker->max_jobs = atoi(kv->value); } else if (!strcmp(kv->key, "plugin")) { struct wproc_list *command_handlers; is_global = 0; if (!(command_handlers = dkhash_get(specialized_workers, kv->value, NULL))) { command_handlers = calloc(1, sizeof(struct wproc_list)); command_handlers->wps = calloc(1, sizeof(struct wproc_worker**)); command_handlers->len = 1; command_handlers->wps[0] = worker; dkhash_insert(specialized_workers, strdup(kv->value), NULL, command_handlers); } else { command_handlers->len++; command_handlers->wps = realloc(command_handlers->wps, command_handlers->len * sizeof(struct wproc_worker**)); command_handlers->wps[command_handlers->len - 1] = worker; } worker->wp_list = command_handlers; } } if (!worker->max_jobs) { /* * each worker uses two filedescriptors per job, one to * connect to the master and about 13 to handle libraries * and memory allocation, so this guesstimate shouldn't * be too far off (for local workers, at least). */ worker->max_jobs = (iobroker_max_usable_fds() / 2) - 50; } worker->jobs = fanout_create(worker->max_jobs); if (is_global) { workers.len++; workers.wps = realloc(workers.wps, workers.len * sizeof(struct wproc_worker *)); workers.wps[workers.len - 1] = worker; worker->wp_list = &workers; } wproc_num_workers_online++; kvvec_destroy(info, 0); nsock_printf_nul(sd, "OK"); /* signal query handler to release its iocache for this one */ return QH_TAKEOVER; }