LCOV - code coverage report
Current view: top level - nsprpub/pr/src/md/unix - uxproces.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 315 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "primpl.h"
       7             : 
       8             : #include <sys/types.h>
       9             : #include <unistd.h>
      10             : #include <fcntl.h>
      11             : #include <signal.h>
      12             : #include <sys/wait.h>
      13             : #include <string.h>
      14             : #if defined(AIX)
      15             : #include <dlfcn.h>  /* For dlopen, dlsym, dlclose */
      16             : #endif
      17             : 
      18             : #if defined(DARWIN)
      19             : #if defined(HAVE_CRT_EXTERNS_H)
      20             : #include <crt_externs.h>
      21             : #endif
      22             : #else
      23             : PR_IMPORT_DATA(char **) environ;
      24             : #endif
      25             : 
      26             : /*
      27             :  * HP-UX 9 doesn't have the SA_RESTART flag.
      28             :  */
      29             : #ifndef SA_RESTART
      30             : #define SA_RESTART 0
      31             : #endif
      32             : 
      33             : /*
      34             :  **********************************************************************
      35             :  *
      36             :  * The Unix process routines
      37             :  *
      38             :  **********************************************************************
      39             :  */
      40             : 
      41             : #define _PR_SIGNALED_EXITSTATUS 256
      42             : 
      43             : typedef enum pr_PidState {
      44             :     _PR_PID_DETACHED,
      45             :     _PR_PID_REAPED,
      46             :     _PR_PID_WAITING
      47             : } pr_PidState;
      48             : 
      49             : typedef struct pr_PidRecord {
      50             :     pid_t pid;
      51             :     int exitStatus;
      52             :     pr_PidState state;
      53             :     PRCondVar *reapedCV;
      54             :     struct pr_PidRecord *next;
      55             : } pr_PidRecord;
      56             : 
      57             : /*
      58             :  * Irix sprocs and LinuxThreads are actually a kind of processes
      59             :  * that can share the virtual address space and file descriptors.
      60             :  */
      61             : #if (defined(IRIX) && !defined(_PR_PTHREADS)) \
      62             :         || ((defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)) \
      63             :         && defined(_PR_PTHREADS))
      64             : #define _PR_SHARE_CLONES
      65             : #endif
      66             : 
      67             : /*
      68             :  * The macro _PR_NATIVE_THREADS indicates that we are
      69             :  * using native threads only, so waitpid() blocks just the
      70             :  * calling thread, not the process.  In this case, the waitpid
      71             :  * daemon thread can safely block in waitpid().  So we don't
      72             :  * need to catch SIGCHLD, and the pipe to unblock PR_Poll() is
      73             :  * also not necessary.
      74             :  */
      75             : 
      76             : #if defined(_PR_GLOBAL_THREADS_ONLY) \
      77             :         || (defined(_PR_PTHREADS) \
      78             :         && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__))
      79             : #define _PR_NATIVE_THREADS
      80             : #endif
      81             : 
      82             : /*
      83             :  * All the static variables used by the Unix process routines are
      84             :  * collected in this structure.
      85             :  */
      86             : 
      87             : static struct {
      88             :     PRCallOnceType once;
      89             :     PRThread *thread;
      90             :     PRLock *ml;
      91             : #if defined(_PR_NATIVE_THREADS)
      92             :     PRInt32 numProcs;
      93             :     PRCondVar *cv;
      94             : #else
      95             :     int pipefd[2];
      96             : #endif
      97             :     pr_PidRecord **pidTable;
      98             : 
      99             : #ifdef _PR_SHARE_CLONES
     100             :     struct pr_CreateProcOp *opHead, *opTail;
     101             : #endif
     102             : 
     103             : #ifdef AIX
     104             :     pid_t (*forkptr)(void);  /* Newer versions of AIX (starting in 4.3.2)
     105             :                               * have f_fork, which is faster than the
     106             :                               * regular fork in a multithreaded process
     107             :                               * because it skips calling the fork handlers.
     108             :                               * So we look up the f_fork symbol to see if
     109             :                               * it's available and fall back on fork.
     110             :                               */
     111             : #endif /* AIX */
     112             : } pr_wp;
     113             : 
     114             : #ifdef _PR_SHARE_CLONES
     115             : static int pr_waitpid_daemon_exit;
     116             : 
     117             : void
     118           0 : _MD_unix_terminate_waitpid_daemon(void)
     119             : {
     120           0 :     if (pr_wp.thread) {
     121           0 :         pr_waitpid_daemon_exit = 1;
     122           0 :         write(pr_wp.pipefd[1], "", 1);
     123           0 :         PR_JoinThread(pr_wp.thread);
     124             :     }
     125           0 : }
     126             : #endif
     127             : 
     128             : static PRStatus _MD_InitProcesses(void);
     129             : #if !defined(_PR_NATIVE_THREADS)
     130             : static void pr_InstallSigchldHandler(void);
     131             : #endif
     132             : 
     133             : static PRProcess *
     134           0 : ForkAndExec(
     135             :     const char *path,
     136             :     char *const *argv,
     137             :     char *const *envp,
     138             :     const PRProcessAttr *attr)
     139             : {
     140             :     PRProcess *process;
     141             :     int nEnv, idx;
     142             :     char *const *childEnvp;
     143           0 :     char **newEnvp = NULL;
     144             :     int flags;
     145             : 
     146           0 :     process = PR_NEW(PRProcess);
     147           0 :     if (!process) {
     148           0 :         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     149           0 :         return NULL;
     150             :     }
     151             : 
     152           0 :     childEnvp = envp;
     153           0 :     if (attr && attr->fdInheritBuffer) {
     154           0 :         PRBool found = PR_FALSE;
     155             : 
     156           0 :         if (NULL == childEnvp) {
     157             : #ifdef DARWIN
     158             : #ifdef HAVE_CRT_EXTERNS_H
     159             :             childEnvp = *(_NSGetEnviron());
     160             : #else
     161             :             /* _NSGetEnviron() is not available on iOS. */
     162             :             PR_DELETE(process);
     163             :             PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
     164             :             return NULL;
     165             : #endif
     166             : #else
     167           0 :             childEnvp = environ;
     168             : #endif
     169             :         }
     170             : 
     171           0 :         for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
     172             :         }
     173           0 :         newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *));
     174           0 :         if (NULL == newEnvp) {
     175           0 :             PR_DELETE(process);
     176           0 :             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     177           0 :             return NULL;
     178             :         }
     179           0 :         for (idx = 0; idx < nEnv; idx++) {
     180           0 :             newEnvp[idx] = childEnvp[idx];
     181           0 :             if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
     182           0 :                 newEnvp[idx] = attr->fdInheritBuffer;
     183           0 :                 found = PR_TRUE;
     184             :             }
     185             :         }
     186           0 :         if (!found) {
     187           0 :             newEnvp[idx++] = attr->fdInheritBuffer;
     188             :         }
     189           0 :         newEnvp[idx] = NULL;
     190           0 :         childEnvp = newEnvp;
     191             :     }
     192             : 
     193             : #ifdef AIX
     194             :     process->md.pid = (*pr_wp.forkptr)();
     195             : #elif defined(NTO) || defined(SYMBIAN)
     196             :     /*
     197             :      * fork() & exec() does not work in a multithreaded process.
     198             :      * Use spawn() instead.
     199             :      */
     200             :     {
     201             :         int fd_map[3] = { 0, 1, 2 };
     202             : 
     203             :         if (attr) {
     204             :             if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) {
     205             :                 fd_map[0] = dup(attr->stdinFd->secret->md.osfd);
     206             :                 flags = fcntl(fd_map[0], F_GETFL, 0);
     207             :                 if (flags & O_NONBLOCK)
     208             :                     fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK);
     209             :             }
     210             :             if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) {
     211             :                 fd_map[1] = dup(attr->stdoutFd->secret->md.osfd);
     212             :                 flags = fcntl(fd_map[1], F_GETFL, 0);
     213             :                 if (flags & O_NONBLOCK)
     214             :                     fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK);
     215             :             }
     216             :             if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) {
     217             :                 fd_map[2] = dup(attr->stderrFd->secret->md.osfd);
     218             :                 flags = fcntl(fd_map[2], F_GETFL, 0);
     219             :                 if (flags & O_NONBLOCK)
     220             :                     fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK);
     221             :             }
     222             : 
     223             :             PR_ASSERT(attr->currentDirectory == NULL);  /* not implemented */
     224             :         }
     225             : 
     226             : #ifdef SYMBIAN
     227             :         /* In Symbian OS, we use posix_spawn instead of fork() and exec() */
     228             :         posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp);
     229             : #else
     230             :         process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp);
     231             : #endif
     232             : 
     233             :         if (fd_map[0] != 0)
     234             :             close(fd_map[0]);
     235             :         if (fd_map[1] != 1)
     236             :             close(fd_map[1]);
     237             :         if (fd_map[2] != 2)
     238             :             close(fd_map[2]);
     239             :     }
     240             : #else
     241           0 :     process->md.pid = fork();
     242             : #endif
     243           0 :     if ((pid_t) -1 == process->md.pid) {
     244           0 :         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
     245           0 :         PR_DELETE(process);
     246           0 :         if (newEnvp) {
     247           0 :             PR_DELETE(newEnvp);
     248             :         }
     249           0 :         return NULL;
     250             :     }
     251           0 :     if (0 == process->md.pid) {  /* the child process */
     252             :       /*
     253             :        * If the child process needs to exit, it must call _exit().
     254             :        * Do not call exit(), because exit() will flush and close
     255             :        * the standard I/O file descriptors, and hence corrupt
     256             :        * the parent process's standard I/O data structures.
     257             :        */
     258             : 
     259             : #if !defined(NTO) && !defined(SYMBIAN)
     260           0 :         if (attr) {
     261             :             /* the osfd's to redirect stdin, stdout, and stderr to */
     262           0 :             int in_osfd = -1, out_osfd = -1, err_osfd = -1;
     263             : 
     264           0 :             if (attr->stdinFd
     265           0 :                     && attr->stdinFd->secret->md.osfd != 0) {
     266           0 :                 in_osfd = attr->stdinFd->secret->md.osfd;
     267           0 :                 if (dup2(in_osfd, 0) != 0) {
     268           0 :                     _exit(1);  /* failed */
     269             :                 }
     270           0 :                 flags = fcntl(0, F_GETFL, 0);
     271           0 :                 if (flags & O_NONBLOCK) {
     272           0 :                     fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
     273             :                 }
     274             :             }
     275           0 :             if (attr->stdoutFd
     276           0 :                     && attr->stdoutFd->secret->md.osfd != 1) {
     277           0 :                 out_osfd = attr->stdoutFd->secret->md.osfd;
     278           0 :                 if (dup2(out_osfd, 1) != 1) {
     279           0 :                     _exit(1);  /* failed */
     280             :                 }
     281           0 :                 flags = fcntl(1, F_GETFL, 0);
     282           0 :                 if (flags & O_NONBLOCK) {
     283           0 :                     fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
     284             :                 }
     285             :             }
     286           0 :             if (attr->stderrFd
     287           0 :                     && attr->stderrFd->secret->md.osfd != 2) {
     288           0 :                 err_osfd = attr->stderrFd->secret->md.osfd;
     289           0 :                 if (dup2(err_osfd, 2) != 2) {
     290           0 :                     _exit(1);  /* failed */
     291             :                 }
     292           0 :                 flags = fcntl(2, F_GETFL, 0);
     293           0 :                 if (flags & O_NONBLOCK) {
     294           0 :                     fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
     295             :                 }
     296             :             }
     297           0 :             if (in_osfd != -1) {
     298           0 :                 close(in_osfd);
     299             :             }
     300           0 :             if (out_osfd != -1 && out_osfd != in_osfd) {
     301           0 :                 close(out_osfd);
     302             :             }
     303           0 :             if (err_osfd != -1 && err_osfd != in_osfd
     304           0 :                     && err_osfd != out_osfd) {
     305           0 :                 close(err_osfd);
     306             :             }
     307           0 :             if (attr->currentDirectory) {
     308           0 :                 if (chdir(attr->currentDirectory) < 0) {
     309           0 :                     _exit(1);  /* failed */
     310             :                 }
     311             :             }
     312             :         }
     313             : 
     314           0 :         if (childEnvp) {
     315           0 :             (void)execve(path, argv, childEnvp);
     316             :         } else {
     317             :             /* Inherit the environment of the parent. */
     318           0 :             (void)execv(path, argv);
     319             :         }
     320             :         /* Whoops! It returned. That's a bad sign. */
     321           0 :         _exit(1);
     322             : #endif /* !NTO */
     323             :     }
     324             : 
     325           0 :     if (newEnvp) {
     326           0 :         PR_DELETE(newEnvp);
     327             :     }
     328             : 
     329             : #if defined(_PR_NATIVE_THREADS)
     330             :     PR_Lock(pr_wp.ml);
     331             :     if (0 == pr_wp.numProcs++) {
     332             :         PR_NotifyCondVar(pr_wp.cv);
     333             :     }
     334             :     PR_Unlock(pr_wp.ml);
     335             : #endif
     336           0 :     return process;
     337             : }
     338             : 
     339             : #ifdef _PR_SHARE_CLONES
     340             : 
     341             : struct pr_CreateProcOp {
     342             :     const char *path;
     343             :     char *const *argv;
     344             :     char *const *envp;
     345             :     const PRProcessAttr *attr;
     346             :     PRProcess *process;
     347             :     PRErrorCode prerror;
     348             :     PRInt32 oserror;
     349             :     PRBool done;
     350             :     PRCondVar *doneCV;
     351             :     struct pr_CreateProcOp *next;
     352             : };
     353             : 
     354             : PRProcess *
     355           0 : _MD_CreateUnixProcess(
     356             :     const char *path,
     357             :     char *const *argv,
     358             :     char *const *envp,
     359             :     const PRProcessAttr *attr)
     360             : {
     361             :     struct pr_CreateProcOp *op;
     362             :     PRProcess *proc;
     363             :     int rv;
     364             : 
     365           0 :     if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
     366           0 :         return NULL;
     367             :     }
     368             : 
     369           0 :     op = PR_NEW(struct pr_CreateProcOp);
     370           0 :     if (NULL == op) {
     371           0 :         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     372           0 :         return NULL;
     373             :     }
     374           0 :     op->path = path;
     375           0 :     op->argv = argv;
     376           0 :     op->envp = envp;
     377           0 :     op->attr = attr;
     378           0 :     op->done = PR_FALSE;
     379           0 :     op->doneCV = PR_NewCondVar(pr_wp.ml);
     380           0 :     if (NULL == op->doneCV) {
     381           0 :         PR_DELETE(op);
     382           0 :         return NULL;
     383             :     }
     384           0 :     PR_Lock(pr_wp.ml);
     385             : 
     386             :     /* add to the tail of op queue */
     387           0 :     op->next = NULL;
     388           0 :     if (pr_wp.opTail) {
     389           0 :         pr_wp.opTail->next = op;
     390           0 :         pr_wp.opTail = op;
     391             :     } else {
     392           0 :         PR_ASSERT(NULL == pr_wp.opHead);
     393           0 :         pr_wp.opHead = pr_wp.opTail = op;
     394             :     }
     395             : 
     396             :     /* wake up the daemon thread */
     397             :     do {
     398           0 :         rv = write(pr_wp.pipefd[1], "", 1);
     399           0 :     } while (-1 == rv && EINTR == errno);
     400             : 
     401           0 :     while (op->done == PR_FALSE) {
     402           0 :         PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT);
     403             :     }
     404           0 :     PR_Unlock(pr_wp.ml);
     405           0 :     PR_DestroyCondVar(op->doneCV);
     406           0 :     proc = op->process;
     407           0 :     if (!proc) {
     408           0 :         PR_SetError(op->prerror, op->oserror);
     409             :     }
     410           0 :     PR_DELETE(op);
     411           0 :     return proc;
     412             : }
     413             : 
     414             : #else  /* ! _PR_SHARE_CLONES */
     415             : 
     416             : PRProcess *
     417             : _MD_CreateUnixProcess(
     418             :     const char *path,
     419             :     char *const *argv,
     420             :     char *const *envp,
     421             :     const PRProcessAttr *attr)
     422             : {
     423             :     if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
     424             :         return NULL;
     425             :     }
     426             :     return ForkAndExec(path, argv, envp, attr);
     427             : }  /* _MD_CreateUnixProcess */
     428             : 
     429             : #endif  /* _PR_SHARE_CLONES */
     430             : 
     431             : /*
     432             :  * The pid table is a hashtable.
     433             :  *
     434             :  * The number of buckets in the hashtable (NBUCKETS) must be a power of 2.
     435             :  */
     436             : #define NBUCKETS_LOG2 6
     437             : #define NBUCKETS (1 << NBUCKETS_LOG2)
     438             : #define PID_HASH_MASK ((pid_t) (NBUCKETS - 1))
     439             : 
     440             : static pr_PidRecord *
     441           0 : FindPidTable(pid_t pid)
     442             : {
     443             :     pr_PidRecord *pRec;
     444           0 :     int keyHash = (int) (pid & PID_HASH_MASK);
     445             : 
     446           0 :     pRec =  pr_wp.pidTable[keyHash];
     447           0 :     while (pRec) {
     448           0 :         if (pRec->pid == pid) {
     449           0 :             break;
     450             :         }
     451           0 :         pRec = pRec->next;
     452             :     }
     453           0 :     return pRec;
     454             : }
     455             : 
     456             : static void
     457           0 : InsertPidTable(pr_PidRecord *pRec)
     458             : {
     459           0 :     int keyHash = (int) (pRec->pid & PID_HASH_MASK);
     460             : 
     461           0 :     pRec->next = pr_wp.pidTable[keyHash];
     462           0 :     pr_wp.pidTable[keyHash] = pRec;
     463           0 : }
     464             : 
     465             : static void
     466           0 : DeletePidTable(pr_PidRecord *pRec)
     467             : {
     468           0 :     int keyHash = (int) (pRec->pid & PID_HASH_MASK);
     469             : 
     470           0 :     if (pr_wp.pidTable[keyHash] == pRec) {
     471           0 :         pr_wp.pidTable[keyHash] = pRec->next;
     472             :     } else {
     473             :         pr_PidRecord *pred, *cur;  /* predecessor and current */
     474             : 
     475           0 :         pred = pr_wp.pidTable[keyHash];
     476           0 :         cur = pred->next;
     477           0 :         while (cur) {
     478           0 :             if (cur == pRec) {
     479           0 :                 pred->next = cur->next;
     480           0 :                 break;
     481             :             }
     482           0 :             pred = cur;
     483           0 :             cur = cur->next;
     484             :         }
     485           0 :         PR_ASSERT(cur != NULL);
     486             :     }
     487           0 : }
     488             : 
     489             : static int
     490           0 : ExtractExitStatus(int rawExitStatus)
     491             : {
     492             :     /*
     493             :      * We did not specify the WCONTINUED and WUNTRACED options
     494             :      * for waitpid, so these two events should not be reported.
     495             :      */
     496           0 :     PR_ASSERT(!WIFSTOPPED(rawExitStatus));
     497             : #ifdef WIFCONTINUED
     498           0 :     PR_ASSERT(!WIFCONTINUED(rawExitStatus));
     499             : #endif
     500           0 :     if (WIFEXITED(rawExitStatus)) {
     501           0 :         return WEXITSTATUS(rawExitStatus);
     502             :     }
     503           0 :         PR_ASSERT(WIFSIGNALED(rawExitStatus));
     504           0 :         return _PR_SIGNALED_EXITSTATUS;
     505             : }
     506             : 
     507             : static void
     508           0 : ProcessReapedChildInternal(pid_t pid, int status)
     509             : {
     510             :     pr_PidRecord *pRec;
     511             : 
     512           0 :     pRec = FindPidTable(pid);
     513           0 :     if (NULL == pRec) {
     514           0 :         pRec = PR_NEW(pr_PidRecord);
     515           0 :         pRec->pid = pid;
     516           0 :         pRec->state = _PR_PID_REAPED;
     517           0 :         pRec->exitStatus = ExtractExitStatus(status);
     518           0 :         pRec->reapedCV = NULL;
     519           0 :         InsertPidTable(pRec);
     520             :     } else {
     521           0 :         PR_ASSERT(pRec->state != _PR_PID_REAPED);
     522           0 :         if (_PR_PID_DETACHED == pRec->state) {
     523           0 :             PR_ASSERT(NULL == pRec->reapedCV);
     524           0 :             DeletePidTable(pRec);
     525           0 :             PR_DELETE(pRec);
     526             :         } else {
     527           0 :             PR_ASSERT(_PR_PID_WAITING == pRec->state);
     528           0 :             PR_ASSERT(NULL != pRec->reapedCV);
     529           0 :             pRec->exitStatus = ExtractExitStatus(status);
     530           0 :             pRec->state = _PR_PID_REAPED;
     531           0 :             PR_NotifyCondVar(pRec->reapedCV);
     532             :         }
     533             :     }
     534           0 : }
     535             : 
     536             : #if defined(_PR_NATIVE_THREADS)
     537             : 
     538             : /*
     539             :  * If all the threads are native threads, the daemon thread is
     540             :  * simpler.  We don't need to catch the SIGCHLD signal.  We can
     541             :  * just have the daemon thread block in waitpid().
     542             :  */
     543             : 
     544             : static void WaitPidDaemonThread(void *unused)
     545             : {
     546             :     pid_t pid;
     547             :     int status;
     548             : 
     549             :     while (1) {
     550             :         PR_Lock(pr_wp.ml);
     551             :         while (0 == pr_wp.numProcs) {
     552             :             PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
     553             :         }
     554             :         PR_Unlock(pr_wp.ml);
     555             : 
     556             :         while (1) {
     557             :             do {
     558             :                 pid = waitpid((pid_t) -1, &status, 0);
     559             :             } while ((pid_t) -1 == pid && EINTR == errno);
     560             : 
     561             :             /*
     562             :              * waitpid() cannot return 0 because we did not invoke it
     563             :              * with the WNOHANG option.
     564             :              */ 
     565             :             PR_ASSERT(0 != pid);
     566             : 
     567             :             /*
     568             :              * The only possible error code is ECHILD.  But if we do
     569             :              * our accounting correctly, we should only call waitpid()
     570             :              * when there is a child process to wait for.
     571             :              */
     572             :             PR_ASSERT((pid_t) -1 != pid);
     573             :             if ((pid_t) -1 == pid) {
     574             :                 break;
     575             :             }
     576             : 
     577             :             PR_Lock(pr_wp.ml);
     578             :             ProcessReapedChildInternal(pid, status);
     579             :             pr_wp.numProcs--;
     580             :             while (0 == pr_wp.numProcs) {
     581             :                 PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
     582             :             }
     583             :             PR_Unlock(pr_wp.ml);
     584             :         }
     585             :     }
     586             : }
     587             : 
     588             : #else /* _PR_NATIVE_THREADS */
     589             : 
     590           0 : static void WaitPidDaemonThread(void *unused)
     591             : {
     592             :     PRPollDesc pd;
     593             :     PRFileDesc *fd;
     594             :     int rv;
     595             :     char buf[128];
     596             :     pid_t pid;
     597             :     int status;
     598             : #ifdef _PR_SHARE_CLONES
     599             :     struct pr_CreateProcOp *op;
     600             : #endif
     601             : 
     602             : #ifdef _PR_SHARE_CLONES
     603           0 :     pr_InstallSigchldHandler();
     604             : #endif
     605             : 
     606           0 :     fd = PR_ImportFile(pr_wp.pipefd[0]);
     607           0 :     PR_ASSERT(NULL != fd);
     608           0 :     pd.fd = fd;
     609           0 :     pd.in_flags = PR_POLL_READ;
     610             : 
     611             :     while (1) {
     612           0 :         rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
     613           0 :         PR_ASSERT(1 == rv);
     614             : 
     615             : #ifdef _PR_SHARE_CLONES
     616           0 :         if (pr_waitpid_daemon_exit) {
     617           0 :             return;
     618             :         }
     619           0 :         PR_Lock(pr_wp.ml);
     620             : #endif
     621             :             
     622             :         do {
     623           0 :             rv = read(pr_wp.pipefd[0], buf, sizeof(buf));
     624           0 :         } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno));
     625             : 
     626             : #ifdef _PR_SHARE_CLONES
     627           0 :         while ((op = pr_wp.opHead) != NULL) {
     628           0 :             PR_Unlock(pr_wp.ml);
     629           0 :             op->process = ForkAndExec(op->path, op->argv,
     630             :                     op->envp, op->attr);
     631           0 :             if (NULL == op->process) {
     632           0 :                 op->prerror = PR_GetError();
     633           0 :                 op->oserror = PR_GetOSError();
     634             :             }
     635           0 :             PR_Lock(pr_wp.ml);
     636           0 :             pr_wp.opHead = op->next;
     637           0 :             if (NULL == pr_wp.opHead) {
     638           0 :                 pr_wp.opTail = NULL;
     639             :             }
     640           0 :             op->done = PR_TRUE;
     641           0 :             PR_NotifyCondVar(op->doneCV);
     642             :         }
     643           0 :         PR_Unlock(pr_wp.ml);
     644             : #endif
     645             : 
     646           0 :         while (1) {
     647             :             do {
     648           0 :                 pid = waitpid((pid_t) -1, &status, WNOHANG);
     649           0 :             } while ((pid_t) -1 == pid && EINTR == errno);
     650           0 :             if (0 == pid) break;
     651           0 :             if ((pid_t) -1 == pid) {
     652             :                 /* must be because we have no child processes */
     653           0 :                 PR_ASSERT(ECHILD == errno);
     654           0 :                 break;
     655             :             }
     656             : 
     657           0 :             PR_Lock(pr_wp.ml);
     658           0 :             ProcessReapedChildInternal(pid, status);
     659           0 :             PR_Unlock(pr_wp.ml);
     660             :         }
     661             :     }
     662             : }
     663             : 
     664           0 : static void pr_SigchldHandler(int sig)
     665             : {
     666             :     int errnoCopy;
     667             :     int rv;
     668             : 
     669           0 :     errnoCopy = errno;
     670             : 
     671             :     do {
     672           0 :         rv = write(pr_wp.pipefd[1], "", 1);
     673           0 :     } while (-1 == rv && EINTR == errno);
     674             : 
     675             : #ifdef DEBUG
     676           0 :     if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) {
     677           0 :         char *msg = "cannot write to pipe\n";
     678           0 :         write(2, msg, strlen(msg) + 1);
     679           0 :         _exit(1);
     680             :     }
     681             : #endif
     682             : 
     683           0 :     errno = errnoCopy;
     684           0 : }
     685             : 
     686           0 : static void pr_InstallSigchldHandler()
     687             : {
     688             : #if defined(HPUX) && defined(_PR_DCETHREADS)
     689             : #error "HP-UX DCE threads have their own SIGCHLD handler"
     690             : #endif
     691             : 
     692             :     struct sigaction act, oact;
     693             :     int rv;
     694             : 
     695           0 :     act.sa_handler = pr_SigchldHandler;
     696           0 :     sigemptyset(&act.sa_mask);
     697           0 :     act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
     698           0 :     rv = sigaction(SIGCHLD, &act, &oact);
     699           0 :     PR_ASSERT(0 == rv);
     700             :     /* Make sure we are not overriding someone else's SIGCHLD handler */
     701             : #ifndef _PR_SHARE_CLONES
     702             :     PR_ASSERT(oact.sa_handler == SIG_DFL);
     703             : #endif
     704           0 : }
     705             : 
     706             : #endif  /* !defined(_PR_NATIVE_THREADS) */
     707             : 
     708           0 : static PRStatus _MD_InitProcesses(void)
     709             : {
     710             : #if !defined(_PR_NATIVE_THREADS)
     711             :     int rv;
     712             :     int flags;
     713             : #endif
     714             : 
     715             : #ifdef AIX
     716             :     {
     717             :         void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
     718             :         pr_wp.forkptr = (pid_t (*)(void)) dlsym(handle, "f_fork");
     719             :         if (!pr_wp.forkptr) {
     720             :             pr_wp.forkptr = fork;
     721             :         }
     722             :         dlclose(handle);
     723             :     }
     724             : #endif /* AIX */
     725             : 
     726           0 :     pr_wp.ml = PR_NewLock();
     727           0 :     PR_ASSERT(NULL != pr_wp.ml);
     728             : 
     729             : #if defined(_PR_NATIVE_THREADS)
     730             :     pr_wp.numProcs = 0;
     731             :     pr_wp.cv = PR_NewCondVar(pr_wp.ml);
     732             :     PR_ASSERT(NULL != pr_wp.cv);
     733             : #else
     734           0 :     rv = pipe(pr_wp.pipefd);
     735           0 :     PR_ASSERT(0 == rv);
     736           0 :     flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0);
     737           0 :     fcntl(pr_wp.pipefd[0], F_SETFL, flags | O_NONBLOCK);
     738           0 :     flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0);
     739           0 :     fcntl(pr_wp.pipefd[1], F_SETFL, flags | O_NONBLOCK);
     740             : 
     741             : #ifndef _PR_SHARE_CLONES
     742             :     pr_InstallSigchldHandler();
     743             : #endif
     744             : #endif  /* !_PR_NATIVE_THREADS */
     745             : 
     746           0 :     pr_wp.thread = PR_CreateThread(PR_SYSTEM_THREAD,
     747             :             WaitPidDaemonThread, NULL, PR_PRIORITY_NORMAL,
     748             : #ifdef _PR_SHARE_CLONES
     749             :             PR_GLOBAL_THREAD,
     750             : #else
     751             :             PR_LOCAL_THREAD,
     752             : #endif
     753             :             PR_JOINABLE_THREAD, 0);
     754           0 :     PR_ASSERT(NULL != pr_wp.thread);
     755             : 
     756           0 :     pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *));
     757           0 :     PR_ASSERT(NULL != pr_wp.pidTable);
     758           0 :     return PR_SUCCESS;
     759             : }
     760             : 
     761           0 : PRStatus _MD_DetachUnixProcess(PRProcess *process)
     762             : {
     763           0 :     PRStatus retVal = PR_SUCCESS;
     764             :     pr_PidRecord *pRec;
     765             : 
     766           0 :     PR_Lock(pr_wp.ml);
     767           0 :     pRec = FindPidTable(process->md.pid);
     768           0 :     if (NULL == pRec) {
     769           0 :         pRec = PR_NEW(pr_PidRecord);
     770           0 :         if (NULL == pRec) {
     771           0 :             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     772           0 :             retVal = PR_FAILURE;
     773           0 :             goto done;
     774             :         }
     775           0 :         pRec->pid = process->md.pid;
     776           0 :         pRec->state = _PR_PID_DETACHED;
     777           0 :         pRec->reapedCV = NULL;
     778           0 :         InsertPidTable(pRec);
     779             :     } else {
     780           0 :         PR_ASSERT(_PR_PID_REAPED == pRec->state);
     781           0 :         if (_PR_PID_REAPED != pRec->state) {
     782           0 :             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     783           0 :             retVal = PR_FAILURE;
     784             :         } else {
     785           0 :             DeletePidTable(pRec);
     786           0 :             PR_ASSERT(NULL == pRec->reapedCV);
     787           0 :             PR_DELETE(pRec);
     788             :         }
     789             :     }
     790           0 :     PR_DELETE(process);
     791             : 
     792             : done:
     793           0 :     PR_Unlock(pr_wp.ml);
     794           0 :     return retVal;
     795             : }
     796             : 
     797           0 : PRStatus _MD_WaitUnixProcess(
     798             :     PRProcess *process,
     799             :     PRInt32 *exitCode)
     800             : {
     801             :     pr_PidRecord *pRec;
     802           0 :     PRStatus retVal = PR_SUCCESS;
     803           0 :     PRBool interrupted = PR_FALSE;
     804             : 
     805           0 :     PR_Lock(pr_wp.ml);
     806           0 :     pRec = FindPidTable(process->md.pid);
     807           0 :     if (NULL == pRec) {
     808           0 :         pRec = PR_NEW(pr_PidRecord);
     809           0 :         if (NULL == pRec) {
     810           0 :             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     811           0 :             retVal = PR_FAILURE;
     812           0 :             goto done;
     813             :         }
     814           0 :         pRec->pid = process->md.pid;
     815           0 :         pRec->state = _PR_PID_WAITING;
     816           0 :         pRec->reapedCV = PR_NewCondVar(pr_wp.ml);
     817           0 :         if (NULL == pRec->reapedCV) {
     818           0 :             PR_DELETE(pRec);
     819           0 :             retVal = PR_FAILURE;
     820           0 :             goto done;
     821             :         }
     822           0 :         InsertPidTable(pRec);
     823           0 :         while (!interrupted && _PR_PID_REAPED != pRec->state) {
     824           0 :             if (PR_WaitCondVar(pRec->reapedCV,
     825             :                     PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE
     826           0 :                     && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
     827           0 :                 interrupted = PR_TRUE;
     828             :             }
     829             :         }
     830           0 :         if (_PR_PID_REAPED == pRec->state) {
     831           0 :             if (exitCode) {
     832           0 :                 *exitCode = pRec->exitStatus;
     833             :             }
     834             :         } else {
     835           0 :             PR_ASSERT(interrupted);
     836           0 :             retVal = PR_FAILURE;
     837             :         }
     838           0 :         DeletePidTable(pRec);
     839           0 :         PR_DestroyCondVar(pRec->reapedCV);
     840           0 :         PR_DELETE(pRec);
     841             :     } else {
     842           0 :         PR_ASSERT(_PR_PID_REAPED == pRec->state);
     843           0 :         PR_ASSERT(NULL == pRec->reapedCV);
     844           0 :         DeletePidTable(pRec);
     845           0 :         if (exitCode) {
     846           0 :             *exitCode = pRec->exitStatus;
     847             :         }
     848           0 :         PR_DELETE(pRec);
     849             :     }
     850           0 :     PR_DELETE(process);
     851             : 
     852             : done:
     853           0 :     PR_Unlock(pr_wp.ml);
     854           0 :     return retVal;
     855             : }  /* _MD_WaitUnixProcess */
     856             : 
     857           0 : PRStatus _MD_KillUnixProcess(PRProcess *process)
     858             : {
     859             :     PRErrorCode prerror;
     860             :     PRInt32 oserror;
     861             : 
     862             : #ifdef SYMBIAN
     863             :     /* In Symbian OS, we can not kill other process with Open C */
     864             :     PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, oserror);
     865             :     return PR_FAILURE;
     866             : #else
     867           0 :     if (kill(process->md.pid, SIGKILL) == 0) {
     868           0 :         return PR_SUCCESS;
     869             :     }
     870           0 :     oserror = errno;
     871           0 :     switch (oserror) {
     872             :         case EPERM:
     873           0 :             prerror = PR_NO_ACCESS_RIGHTS_ERROR;
     874           0 :             break;
     875             :         case ESRCH:
     876           0 :             prerror = PR_INVALID_ARGUMENT_ERROR;
     877           0 :             break;
     878             :         default:
     879           0 :             prerror = PR_UNKNOWN_ERROR;
     880           0 :             break;
     881             :     }
     882           0 :     PR_SetError(prerror, oserror);
     883           0 :     return PR_FAILURE;
     884             : #endif
     885             : }  /* _MD_KillUnixProcess */

Generated by: LCOV version 1.13