#include "global.h" /* * io_progInit() - Init program pool * * @progName = program name for execution * @initNum = initial started programs * @maxNum = maximum started programs * return: NULL error or !=NULL allocated pool (must destroied with io_progDestroy()) */ prog_t * io_progInit(const char *progName, u_int initNum, u_int maxNum) { prog_t *prg = NULL; if (initNum > maxNum) return NULL; prg = e_malloc(sizeof(prog_t)); if (!prg) { io_SetErr(elwix_GetErrno(), "%s", elwix_GetError()); return NULL; } else memset(prg, 0, sizeof(prog_t)); prg->prog_inin = initNum; prg->prog_maxn = maxNum; strlcpy(prg->prog_name, progName, sizeof prg->prog_name); prg->prog_used = e_malloc(E_ALIGN(prg->prog_maxn, sizeof *prg->prog_used) / sizeof *prg->prog_used); if (!prg->prog_used) { io_SetErr(elwix_GetErrno(), "%s", elwix_GetError()); e_free(prg); return NULL; } prg->prog_fds = array_Init(prg->prog_maxn); if (!prg->prog_fds) { io_SetErr(elwix_GetErrno(), "%s", elwix_GetError()); e_free(prg->prog_used); e_free(prg); return NULL; } pthread_mutex_init(&prg->prog_mtx, NULL); if (io_progOpen(prg, prg->prog_inin) < 0) { io_progDestroy(&prg); prg = NULL; } return prg; } /* * io_progDestroy() - Destroy entire program pool * * @pprg = program pool * return: none */ void io_progDestroy(prog_t ** __restrict pprg) { if (!pprg || !*pprg) return; io_progClose(*pprg, 0); e_free((*pprg)->prog_used); array_Destroy(&(*pprg)->prog_fds); pthread_mutex_destroy(&(*pprg)->prog_mtx); e_free(*pprg); *pprg = NULL; } /* * io_progClose() - Close all programs in pool * * @prg = program pool * @closeNum = close program(s) (0 all) * return: 0 error, >0 closed programs */ int io_progClose(prog_t * __restrict prg, u_int closeNum) { register int i; int ret = 0; if (!prg) return 0; if (closeNum > prg->prog_maxn) { io_SetErr(EINVAL, "Requested number for close program is over pool's limit"); return 0; } pthread_mutex_lock(&prg->prog_mtx); for (i = array_Size(prg->prog_fds) - 1; (closeNum ? ret < closeNum : 42) && i > -1; i--) if (array_Get(prg->prog_fds, i)) { e_pclose(array(prg->prog_fds, i, FILE*)); array_Del(prg->prog_fds, i, 0); clrbit(prg->prog_used, i); prg->prog_cnum--; ret++; } pthread_mutex_unlock(&prg->prog_mtx); return ret; } /* * io_progOpen() - Execute number of program(s) * * @prg = program pool * @execNum = execute program(s) (0 max) * return: 0 error, >0 executed programs and abs(<0) executed programs with logged error */ int io_progOpen(prog_t * __restrict prg, u_int execNum) { FILE *f; int stat, ret = 0; register int i; pid_t pid; if (!prg) return 0; if (prg->prog_cnum + execNum > prg->prog_maxn) { io_SetErr(EINVAL, "Requested number for program execution is over pool's limit"); return 0; } pthread_mutex_lock(&prg->prog_mtx); for (i = 0; (execNum ? ret < execNum : 42) && i < array_Size(prg->prog_fds); i++) if (!array_Get(prg->prog_fds, i)) { f = e_popen(prg->prog_name, "r+", &pid); if (!f) { LOGERR; ret = -1; break; } else if (waitpid(pid, &stat, WNOHANG)) { io_SetErr(ECHILD, "Program with pid=%d exit with status %d", pid, WIFEXITED(stat) ? WEXITSTATUS(stat) : -1); ret = -1; break; } else array_Set(prg->prog_fds, i, f); prg->prog_cnum++; ret++; } pthread_mutex_unlock(&prg->prog_mtx); return ret; } /* * io_progGrow() - Execute to number of programs in pool * * @prg = program pool * @toNum = execute to number of programs (0 max) * return: 0 error, >0 executed programs and abs(<0) executed programs with logged error */ int io_progGrow(prog_t * __restrict prg, u_int toNum) { if (!prg) return 0; if (toNum > prg->prog_maxn) { io_SetErr(EINVAL, "Requested number for program execution is over pool's limit"); return 0; } if (!toNum) toNum = prg->prog_maxn; return io_progOpen(prg, toNum - prg->prog_cnum); } /* * io_progVacuum() - Vacuum pool to running number of programs * * @prg = program pool * @toNum = vacuum to number of programs (0 to init number) * return: 0 error or >0 closed programs */ int io_progVacuum(prog_t * __restrict prg, u_int toNum) { register int i; int ret = 0; if (!prg) return 0; if (toNum > prg->prog_maxn) { io_SetErr(EINVAL, "Requested number for close program is over pool's limit"); return 0; } if (!toNum) toNum = prg->prog_inin; pthread_mutex_lock(&prg->prog_mtx); for (i = array_Size(prg->prog_fds) - 1; prg->prog_cnum > toNum && i > -1; i--) if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) { e_pclose(array(prg->prog_fds, i, FILE*)); array_Del(prg->prog_fds, i, 0); prg->prog_cnum--; ret++; } pthread_mutex_unlock(&prg->prog_mtx); return ret; } /* * io_progCheck() - Check exit status of program pool * * @prg = program pool * return: -1 error or >-1 exited programs */ int io_progCheck(prog_t * __restrict prg) { int ret = 0; struct tagPIOPID *p; register int i; if (!prg) return -1; pthread_mutex_lock(&prg->prog_mtx); for (i = 0; i < array_Size(prg->prog_fds); i++) if (array_Get(prg->prog_fds, i) && (p = pio_pgetpid(array(prg->prog_fds, i, FILE*)))) if (waitpid(p->pid, &p->stat, WNOHANG) > 0) { clrbit(prg->prog_used, i); ret++; } pthread_mutex_unlock(&prg->prog_mtx); return ret; } /* * io_progAttach() - Attach to open program * * @prg = program pool * return: NULL error or !=NULL attached program handle */ FILE * io_progAttach(prog_t * __restrict prg) { FILE *f = NULL; register int i; if (!prg) return NULL; pthread_mutex_lock(&prg->prog_mtx); for (i = 0; i < array_Size(prg->prog_fds); i++) if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) { setbit(prg->prog_used, i); f = array(prg->prog_fds, i, FILE*); break; } pthread_mutex_unlock(&prg->prog_mtx); return f; } /* * io_progDetach() - Detch from open program * * @prg= program pool * @pfd = attached program handle * return: none */ void io_progDetach(prog_t * __restrict prg, FILE *pfd) { register int i; if (!prg || !pfd) return; pthread_mutex_lock(&prg->prog_mtx); for (i = 0; i < array_Size(prg->prog_fds); i++) if (array(prg->prog_fds, i, FILE*) == pfd) { clrbit(prg->prog_used, i); break; } pthread_mutex_unlock(&prg->prog_mtx); }