Diff for /libaitio/src/exec.c between versions 1.1.2.4 and 1.1.2.10

version 1.1.2.4, 2013/12/05 14:12:25 version 1.1.2.10, 2013/12/05 23:43:46
Line 1 Line 1
 #include "global.h"  #include "global.h"
   
   
 extern char **environ;  
 extern int __isthreaded;  
   
 struct pid {  
         SLIST_ENTRY(pid) next;  
         FILE *fp;  
         pid_t pid;  
 };  
 static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);  
 static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;  
   
 #define THREAD_LOCK()   if (__isthreaded) pthread_mutex_lock(&pidlist_mutex)  
 #define THREAD_UNLOCK() if (__isthreaded) pthread_mutex_unlock(&pidlist_mutex)  
   
   
 /*  /*
  * io_progInit() - Init program pool   * io_progInit() - Init program pool
  *   *
Line 43  io_progInit(const char *progName, u_int initNum, u_int Line 28  io_progInit(const char *progName, u_int initNum, u_int
         prg->prog_maxn = maxNum;          prg->prog_maxn = maxNum;
         strlcpy(prg->prog_name, progName, sizeof prg->prog_name);          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);          prg->prog_fds = array_Init(prg->prog_maxn);
         if (!prg->prog_fds) {          if (!prg->prog_fds) {
                 io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());                  io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
                   e_free(prg->prog_used);
                 e_free(prg);                  e_free(prg);
                 return NULL;                  return NULL;
         }          }
   
         pthread_mutex_init(&prg->prog_mtx, NULL);          pthread_mutex_init(&prg->prog_mtx, NULL);
   
        if (io_progOpen(prg, prg->prog_inin) < 0)        if (io_progOpen(prg, prg->prog_inin) < 0) {
                 io_progDestroy(&prg);                  io_progDestroy(&prg);
                   prg = NULL;
           }
         return prg;          return prg;
 }  }
   
Line 71  io_progDestroy(prog_t ** __restrict pprg) Line 67  io_progDestroy(prog_t ** __restrict pprg)
   
         io_progClose(*pprg, 0);          io_progClose(*pprg, 0);
   
           e_free((*pprg)->prog_used);
         array_Destroy(&(*pprg)->prog_fds);          array_Destroy(&(*pprg)->prog_fds);
         pthread_mutex_destroy(&(*pprg)->prog_mtx);          pthread_mutex_destroy(&(*pprg)->prog_mtx);
   
Line 102  io_progClose(prog_t * __restrict prg, u_int closeNum) Line 99  io_progClose(prog_t * __restrict prg, u_int closeNum)
         for (i = array_Size(prg->prog_fds) - 1;           for (i = array_Size(prg->prog_fds) - 1; 
                         (closeNum ? ret < closeNum : 42) && i > -1; i--)                          (closeNum ? ret < closeNum : 42) && i > -1; i--)
                 if (array_Get(prg->prog_fds, i)) {                  if (array_Get(prg->prog_fds, i)) {
                        io_pclose(array(prg->prog_fds, i, FILE*));                        e_pclose(array(prg->prog_fds, i, FILE*));
                         array_Del(prg->prog_fds, i, 0);                          array_Del(prg->prog_fds, i, 0);
                           clrbit(prg->prog_used, i);
                         prg->prog_cnum--;                          prg->prog_cnum--;
                         ret++;                          ret++;
                 }                  }
Line 129  io_progOpen(prog_t * __restrict prg, u_int execNum) Line 127  io_progOpen(prog_t * __restrict prg, u_int execNum)
   
         if (!prg)          if (!prg)
                 return 0;                  return 0;
        if (execNum > prg->prog_maxn) {        if (prg->prog_cnum + execNum > prg->prog_maxn) {
                 io_SetErr(EINVAL, "Requested number for program execution is over pool's limit");                  io_SetErr(EINVAL, "Requested number for program execution is over pool's limit");
                 return 0;                  return 0;
         }          }
Line 137  io_progOpen(prog_t * __restrict prg, u_int execNum) Line 135  io_progOpen(prog_t * __restrict prg, u_int execNum)
         pthread_mutex_lock(&prg->prog_mtx);          pthread_mutex_lock(&prg->prog_mtx);
         for (i = 0; (execNum ? ret < execNum : 42) && i < array_Size(prg->prog_fds); i++)          for (i = 0; (execNum ? ret < execNum : 42) && i < array_Size(prg->prog_fds); i++)
                 if (!array_Get(prg->prog_fds, i)) {                  if (!array_Get(prg->prog_fds, i)) {
                        f = io_popen(prg->prog_name, "r+", &pid);                        f = e_popen(prg->prog_name, "r+", &pid);
                         if (!f) {                          if (!f) {
                                 LOGERR;                                  LOGERR;
                                ret *= -1;                                ret = -1;
                                 break;                                  break;
                        } else if (waitpid(pid, &stat, WNOHANG) > 0) {                        } else if (waitpid(pid, &stat, WNOHANG)) {
                                io_SetErr(ECHILD, "Program exit with status %d",                                 io_SetErr(ECHILD, "Program with pid=%d exit with status %d", 
                                                WIFEXITED(stat) ? WEXITSTATUS(stat) : -1);                                                pid, WIFEXITED(stat) ? WEXITSTATUS(stat) : -1);
                                ret *= -1;                                ret = -1;
                                 break;                                  break;
                         } else                          } else
                                 array_Set(prg->prog_fds, i, f);                                  array_Set(prg->prog_fds, i, f);
Line 158  io_progOpen(prog_t * __restrict prg, u_int execNum) Line 156  io_progOpen(prog_t * __restrict prg, u_int execNum)
 }  }
   
 /*  /*
    * 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   * io_progVacuum() - Vacuum pool to running number of programs
  *   *
  * @prg = program pool   * @prg = program pool
Line 181  io_progVacuum(prog_t * __restrict prg, u_int toNum) Line 201  io_progVacuum(prog_t * __restrict prg, u_int toNum)
   
         pthread_mutex_lock(&prg->prog_mtx);          pthread_mutex_lock(&prg->prog_mtx);
         for (i = array_Size(prg->prog_fds) - 1; prg->prog_cnum > toNum && i > -1; i--)          for (i = array_Size(prg->prog_fds) - 1; prg->prog_cnum > toNum && i > -1; i--)
                if (array_Get(prg->prog_fds, i)) {                if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) {
                        io_pclose(array(prg->prog_fds, i, FILE*));                        e_pclose(array(prg->prog_fds, i, FILE*));
                         array_Del(prg->prog_fds, i, 0);                          array_Del(prg->prog_fds, i, 0);
                         prg->prog_cnum--;                          prg->prog_cnum--;
                         ret++;                          ret++;
Line 192  io_progVacuum(prog_t * __restrict prg, u_int toNum) Line 212  io_progVacuum(prog_t * __restrict prg, u_int toNum)
         return ret;          return ret;
 }  }
   
   
 /*  /*
 * io_popen() - ELWIX replacement of standard popen * io_progCheck() - Check exit status of program pool
  *   *
 * @command = command * @prg = program pool
 * @type = type * return: -1 error or >-1 exited programs
 * @ppid = return pid of child program 
 * return: NULL error or !=NULL open program 
  */   */
FILE *int
io_popen(const char *command, const char *type, pid_t *ppid)io_progCheck(prog_t * __restrict prg)
 {  {
        struct pid *cur;        int ret = 0;
        FILE *iop;        struct tagPIOPID *p;
        int pdes[2], pid, twoway, cloexec;        register int i;
        char *argv[4]; 
        struct pid *p; 
   
        cloexec = strchr(type, 'e') != NULL;        if (!prg)
        /*                return -1;
         * Lite2 introduced two-way popen() pipes using _socketpair(). 
         * FreeBSD's pipe() is bidirectional, so we use that. 
         */ 
        if (strchr(type, '+')) { 
                twoway = 1; 
                type = "r+"; 
        } else  { 
                twoway = 0; 
                if ((*type != 'r' && *type != 'w') || 
                    (type[1] && (type[1] != 'e' || type[2]))) 
                        return (NULL); 
        } 
        if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0) 
                return (NULL); 
   
        if ((cur = e_malloc(sizeof(struct pid))) == NULL) {        pthread_mutex_lock(&prg->prog_mtx);
                close(pdes[0]);        for (i = 0; i < array_Size(prg->prog_fds); i++)
                close(pdes[1]);                if (array_Get(prg->prog_fds, i) && 
                return (NULL);                                (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);
   
        argv[0] = "sh";        return ret;
        argv[1] = "-c";}
        argv[2] = (char *)command; 
        argv[3] = NULL; 
   
        THREAD_LOCK();/*
        switch (pid = vfork()) { * io_progAttach() - Attach to open program
        case -1:                        /* Error. */ *
                THREAD_UNLOCK(); * @prg = program pool
                close(pdes[0]); * return: NULL error or !=NULL attached program handle
                close(pdes[1]); */
                e_free(cur);FILE *
                return (NULL);io_progAttach(prog_t * __restrict prg)
                /* NOTREACHED */{
        case 0:                         /* Child. */        FILE *f = NULL;
                if (*type == 'r') {        register int i;
                        /* 
                         * The _dup2() to STDIN_FILENO is repeated to avoid 
                         * writing to pdes[1], which might corrupt the 
                         * parent's copy.  This isn't good enough in 
                         * general, since the _exit() is no return, so 
                         * the compiler is free to corrupt all the local 
                         * variables. 
                         */ 
                        if (!cloexec) 
                                close(pdes[0]); 
                        if (pdes[1] != STDOUT_FILENO) { 
                                dup2(pdes[1], STDOUT_FILENO); 
                                if (!cloexec) 
                                        close(pdes[1]); 
                                if (twoway) 
                                        dup2(STDOUT_FILENO, STDIN_FILENO); 
                        } else if (twoway && (pdes[1] != STDIN_FILENO)) { 
                                dup2(pdes[1], STDIN_FILENO); 
                                if (cloexec) 
                                        fcntl(pdes[1], F_SETFD, 0); 
                        } else if (cloexec) 
                                fcntl(pdes[1], F_SETFD, 0); 
                } else { 
                        if (pdes[0] != STDIN_FILENO) { 
                                dup2(pdes[0], STDIN_FILENO); 
                                if (!cloexec) 
                                        close(pdes[0]); 
                        } else if (cloexec) 
                                fcntl(pdes[0], F_SETFD, 0); 
                        if (!cloexec) 
                                close(pdes[1]); 
                } 
                SLIST_FOREACH(p, &pidlist, next) 
                        close(fileno(p->fp)); 
                execve(_PATH_BSHELL, argv, environ); 
                _exit(127); 
                /* NOTREACHED */ 
        default: 
                if (ppid) 
                        *ppid = pid; 
        } 
        THREAD_UNLOCK(); 
   
        /* Parent; assume fdopen can't fail. */        if (!prg)
        if (*type == 'r') {                return NULL;
                iop = fdopen(pdes[0], type); 
                close(pdes[1]); 
        } else { 
                iop = fdopen(pdes[1], type); 
                close(pdes[0]); 
        } 
   
        /* Link into list of file descriptors. */        pthread_mutex_lock(&prg->prog_mtx);
        cur->fp = iop;        for (i = 0; i < array_Size(prg->prog_fds); i++)
        cur->pid = pid;                if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) {
        THREAD_LOCK();                        setbit(prg->prog_used, i);
        SLIST_INSERT_HEAD(&pidlist, cur, next);                        f = array(prg->prog_fds, i, FILE*);
        THREAD_UNLOCK();                        break;
                 }
         pthread_mutex_unlock(&prg->prog_mtx);
   
        return (iop);        return f;
 }  }
   
 /*  /*
 * io_pclose() - ELWIX replacement of standard pclose * io_progDetach() - Detch from open program
  *   *
 * @iop = popen handle * @prg= program pool
 * return: -1 error or !=-1 pid status * @pfd = attached program handle
  * return: none
  */   */
intvoid
io_pclose(FILE *iop)io_progDetach(prog_t * __restrict prg, FILE *pfd)
 {  {
        struct pid *cur, *last = NULL;        register int i;
        int pstat; 
        pid_t pid; 
   
        /*        if (!prg || !pfd)
         * Find the appropriate file pointer and remove it from the list.                return;
         */ 
        THREAD_LOCK(); 
        SLIST_FOREACH(cur, &pidlist, next) { 
                if (cur->fp == iop) 
                        break; 
                last = cur; 
        } 
        if (cur == NULL) { 
                THREAD_UNLOCK(); 
                return (-1); 
        } 
        if (last == NULL) 
                SLIST_REMOVE_HEAD(&pidlist, next); 
        else 
                SLIST_REMOVE_AFTER(last, next); 
        THREAD_UNLOCK(); 
   
        fclose(iop);        pthread_mutex_lock(&prg->prog_mtx);
        for (i = 0; i < array_Size(prg->prog_fds); i++)
        do {                if (array(prg->prog_fds, i, FILE*) == pfd) {
                pid = wait4(cur->pid, &pstat, 0, (struct rusage *)0);                        clrbit(prg->prog_used, i);
        } while (pid == -1 && errno == EINTR);                        break;
                }
        e_free(cur);        pthread_mutex_unlock(&prg->prog_mtx);
 
        return (pid == -1 ? -1 : pstat); 
 }  }

Removed from v.1.1.2.4  
changed lines
  Added in v.1.1.2.10


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>