nsprpub/pr/src/md/unix/uxproces.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 #include "primpl.h"
     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
    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
    26 /*
    27  * HP-UX 9 doesn't have the SA_RESTART flag.
    28  */
    29 #ifndef SA_RESTART
    30 #define SA_RESTART 0
    31 #endif
    33 /*
    34  **********************************************************************
    35  *
    36  * The Unix process routines
    37  *
    38  **********************************************************************
    39  */
    41 #define _PR_SIGNALED_EXITSTATUS 256
    43 typedef enum pr_PidState {
    44     _PR_PID_DETACHED,
    45     _PR_PID_REAPED,
    46     _PR_PID_WAITING
    47 } pr_PidState;
    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;
    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
    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  */
    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
    82 /*
    83  * All the static variables used by the Unix process routines are
    84  * collected in this structure.
    85  */
    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;
    99 #ifdef _PR_SHARE_CLONES
   100     struct pr_CreateProcOp *opHead, *opTail;
   101 #endif
   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;
   114 #ifdef _PR_SHARE_CLONES
   115 static int pr_waitpid_daemon_exit;
   117 void
   118 _MD_unix_terminate_waitpid_daemon(void)
   119 {
   120     if (pr_wp.thread) {
   121         pr_waitpid_daemon_exit = 1;
   122         write(pr_wp.pipefd[1], "", 1);
   123         PR_JoinThread(pr_wp.thread);
   124     }
   125 }
   126 #endif
   128 static PRStatus _MD_InitProcesses(void);
   129 #if !defined(_PR_NATIVE_THREADS)
   130 static void pr_InstallSigchldHandler(void);
   131 #endif
   133 static PRProcess *
   134 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     char **newEnvp = NULL;
   144     int flags;
   146     process = PR_NEW(PRProcess);
   147     if (!process) {
   148         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   149         return NULL;
   150     }
   152     childEnvp = envp;
   153     if (attr && attr->fdInheritBuffer) {
   154         PRBool found = PR_FALSE;
   156         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             childEnvp = environ;
   168 #endif
   169         }
   171         for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
   172         }
   173         newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *));
   174         if (NULL == newEnvp) {
   175             PR_DELETE(process);
   176             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   177             return NULL;
   178         }
   179         for (idx = 0; idx < nEnv; idx++) {
   180             newEnvp[idx] = childEnvp[idx];
   181             if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
   182                 newEnvp[idx] = attr->fdInheritBuffer;
   183                 found = PR_TRUE;
   184             }
   185         }
   186         if (!found) {
   187             newEnvp[idx++] = attr->fdInheritBuffer;
   188         }
   189         newEnvp[idx] = NULL;
   190         childEnvp = newEnvp;
   191     }
   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 };
   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             }
   223             PR_ASSERT(attr->currentDirectory == NULL);  /* not implemented */
   224         }
   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
   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     process->md.pid = fork();
   242 #endif
   243     if ((pid_t) -1 == process->md.pid) {
   244         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
   245         PR_DELETE(process);
   246         if (newEnvp) {
   247             PR_DELETE(newEnvp);
   248         }
   249         return NULL;
   250     } else if (0 == process->md.pid) {  /* the child process */
   251         /*
   252          * If the child process needs to exit, it must call _exit().
   253          * Do not call exit(), because exit() will flush and close
   254          * the standard I/O file descriptors, and hence corrupt
   255          * the parent process's standard I/O data structures.
   256          */
   258 #if !defined(NTO) && !defined(SYMBIAN)
   259         if (attr) {
   260             /* the osfd's to redirect stdin, stdout, and stderr to */
   261             int in_osfd = -1, out_osfd = -1, err_osfd = -1;
   263             if (attr->stdinFd
   264                     && attr->stdinFd->secret->md.osfd != 0) {
   265                 in_osfd = attr->stdinFd->secret->md.osfd;
   266                 if (dup2(in_osfd, 0) != 0) {
   267                     _exit(1);  /* failed */
   268                 }
   269                 flags = fcntl(0, F_GETFL, 0);
   270                 if (flags & O_NONBLOCK) {
   271                     fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
   272                 }
   273             }
   274             if (attr->stdoutFd
   275                     && attr->stdoutFd->secret->md.osfd != 1) {
   276                 out_osfd = attr->stdoutFd->secret->md.osfd;
   277                 if (dup2(out_osfd, 1) != 1) {
   278                     _exit(1);  /* failed */
   279                 }
   280                 flags = fcntl(1, F_GETFL, 0);
   281                 if (flags & O_NONBLOCK) {
   282                     fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
   283                 }
   284             }
   285             if (attr->stderrFd
   286                     && attr->stderrFd->secret->md.osfd != 2) {
   287                 err_osfd = attr->stderrFd->secret->md.osfd;
   288                 if (dup2(err_osfd, 2) != 2) {
   289                     _exit(1);  /* failed */
   290                 }
   291                 flags = fcntl(2, F_GETFL, 0);
   292                 if (flags & O_NONBLOCK) {
   293                     fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
   294                 }
   295             }
   296             if (in_osfd != -1) {
   297                 close(in_osfd);
   298             }
   299             if (out_osfd != -1 && out_osfd != in_osfd) {
   300                 close(out_osfd);
   301             }
   302             if (err_osfd != -1 && err_osfd != in_osfd
   303                     && err_osfd != out_osfd) {
   304                 close(err_osfd);
   305             }
   306             if (attr->currentDirectory) {
   307                 if (chdir(attr->currentDirectory) < 0) {
   308                     _exit(1);  /* failed */
   309                 }
   310             }
   311         }
   313         if (childEnvp) {
   314             (void)execve(path, argv, childEnvp);
   315         } else {
   316             /* Inherit the environment of the parent. */
   317             (void)execv(path, argv);
   318         }
   319         /* Whoops! It returned. That's a bad sign. */
   320         _exit(1);
   321 #endif /* !NTO */
   322     }
   324     if (newEnvp) {
   325         PR_DELETE(newEnvp);
   326     }
   328 #if defined(_PR_NATIVE_THREADS)
   329     PR_Lock(pr_wp.ml);
   330     if (0 == pr_wp.numProcs++) {
   331         PR_NotifyCondVar(pr_wp.cv);
   332     }
   333     PR_Unlock(pr_wp.ml);
   334 #endif
   335     return process;
   336 }
   338 #ifdef _PR_SHARE_CLONES
   340 struct pr_CreateProcOp {
   341     const char *path;
   342     char *const *argv;
   343     char *const *envp;
   344     const PRProcessAttr *attr;
   345     PRProcess *process;
   346     PRErrorCode prerror;
   347     PRInt32 oserror;
   348     PRBool done;
   349     PRCondVar *doneCV;
   350     struct pr_CreateProcOp *next;
   351 };
   353 PRProcess *
   354 _MD_CreateUnixProcess(
   355     const char *path,
   356     char *const *argv,
   357     char *const *envp,
   358     const PRProcessAttr *attr)
   359 {
   360     struct pr_CreateProcOp *op;
   361     PRProcess *proc;
   362     int rv;
   364     if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
   365 	return NULL;
   366     }
   368     op = PR_NEW(struct pr_CreateProcOp);
   369     if (NULL == op) {
   370 	PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   371 	return NULL;
   372     }
   373     op->path = path;
   374     op->argv = argv;
   375     op->envp = envp;
   376     op->attr = attr;
   377     op->done = PR_FALSE;
   378     op->doneCV = PR_NewCondVar(pr_wp.ml);
   379     if (NULL == op->doneCV) {
   380 	PR_DELETE(op);
   381 	return NULL;
   382     }
   383     PR_Lock(pr_wp.ml);
   385     /* add to the tail of op queue */
   386     op->next = NULL;
   387     if (pr_wp.opTail) {
   388 	pr_wp.opTail->next = op;
   389 	pr_wp.opTail = op;
   390     } else {
   391 	PR_ASSERT(NULL == pr_wp.opHead);
   392 	pr_wp.opHead = pr_wp.opTail = op;
   393     }
   395     /* wake up the daemon thread */
   396     do {
   397         rv = write(pr_wp.pipefd[1], "", 1);
   398     } while (-1 == rv && EINTR == errno);
   400     while (op->done == PR_FALSE) {
   401 	PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT);
   402     }
   403     PR_Unlock(pr_wp.ml);
   404     PR_DestroyCondVar(op->doneCV);
   405     proc = op->process;
   406     if (!proc) {
   407 	PR_SetError(op->prerror, op->oserror);
   408     }
   409     PR_DELETE(op);
   410     return proc;
   411 }
   413 #else  /* ! _PR_SHARE_CLONES */
   415 PRProcess *
   416 _MD_CreateUnixProcess(
   417     const char *path,
   418     char *const *argv,
   419     char *const *envp,
   420     const PRProcessAttr *attr)
   421 {
   422     if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
   423 	return NULL;
   424     }
   425     return ForkAndExec(path, argv, envp, attr);
   426 }  /* _MD_CreateUnixProcess */
   428 #endif  /* _PR_SHARE_CLONES */
   430 /*
   431  * The pid table is a hashtable.
   432  *
   433  * The number of buckets in the hashtable (NBUCKETS) must be a power of 2.
   434  */
   435 #define NBUCKETS_LOG2 6
   436 #define NBUCKETS (1 << NBUCKETS_LOG2)
   437 #define PID_HASH_MASK ((pid_t) (NBUCKETS - 1))
   439 static pr_PidRecord *
   440 FindPidTable(pid_t pid)
   441 {
   442     pr_PidRecord *pRec;
   443     int keyHash = (int) (pid & PID_HASH_MASK);
   445     pRec =  pr_wp.pidTable[keyHash];
   446     while (pRec) {
   447 	if (pRec->pid == pid) {
   448 	    break;
   449 	}
   450 	pRec = pRec->next;
   451     }
   452     return pRec;
   453 }
   455 static void
   456 InsertPidTable(pr_PidRecord *pRec)
   457 {
   458     int keyHash = (int) (pRec->pid & PID_HASH_MASK);
   460     pRec->next = pr_wp.pidTable[keyHash];
   461     pr_wp.pidTable[keyHash] = pRec;
   462 }
   464 static void
   465 DeletePidTable(pr_PidRecord *pRec)
   466 {
   467     int keyHash = (int) (pRec->pid & PID_HASH_MASK);
   469     if (pr_wp.pidTable[keyHash] == pRec) {
   470 	pr_wp.pidTable[keyHash] = pRec->next;
   471     } else {
   472 	pr_PidRecord *pred, *cur;  /* predecessor and current */
   474 	pred = pr_wp.pidTable[keyHash];
   475 	cur = pred->next;
   476 	while (cur) {
   477 	    if (cur == pRec) {
   478 		pred->next = cur->next;
   479 		break;
   480             }
   481 	    pred = cur;
   482 	    cur = cur->next;
   483         }
   484 	PR_ASSERT(cur != NULL);
   485     }
   486 }
   488 static int
   489 ExtractExitStatus(int rawExitStatus)
   490 {
   491     /*
   492      * We did not specify the WCONTINUED and WUNTRACED options
   493      * for waitpid, so these two events should not be reported.
   494      */
   495     PR_ASSERT(!WIFSTOPPED(rawExitStatus));
   496 #ifdef WIFCONTINUED
   497     PR_ASSERT(!WIFCONTINUED(rawExitStatus));
   498 #endif
   499     if (WIFEXITED(rawExitStatus)) {
   500 	return WEXITSTATUS(rawExitStatus);
   501     } else {
   502 	PR_ASSERT(WIFSIGNALED(rawExitStatus));
   503 	return _PR_SIGNALED_EXITSTATUS;
   504     }
   505 }
   507 static void
   508 ProcessReapedChildInternal(pid_t pid, int status)
   509 {
   510     pr_PidRecord *pRec;
   512     pRec = FindPidTable(pid);
   513     if (NULL == pRec) {
   514         pRec = PR_NEW(pr_PidRecord);
   515         pRec->pid = pid;
   516         pRec->state = _PR_PID_REAPED;
   517         pRec->exitStatus = ExtractExitStatus(status);
   518         pRec->reapedCV = NULL;
   519         InsertPidTable(pRec);
   520     } else {
   521         PR_ASSERT(pRec->state != _PR_PID_REAPED);
   522         if (_PR_PID_DETACHED == pRec->state) {
   523             PR_ASSERT(NULL == pRec->reapedCV);
   524             DeletePidTable(pRec);
   525             PR_DELETE(pRec);
   526         } else {
   527             PR_ASSERT(_PR_PID_WAITING == pRec->state);
   528             PR_ASSERT(NULL != pRec->reapedCV);
   529             pRec->exitStatus = ExtractExitStatus(status);
   530             pRec->state = _PR_PID_REAPED;
   531             PR_NotifyCondVar(pRec->reapedCV);
   532         }
   533     }
   534 }
   536 #if defined(_PR_NATIVE_THREADS)
   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  */
   544 static void WaitPidDaemonThread(void *unused)
   545 {
   546     pid_t pid;
   547     int status;
   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);
   556 	while (1) {
   557 	    do {
   558 	        pid = waitpid((pid_t) -1, &status, 0);
   559 	    } while ((pid_t) -1 == pid && EINTR == errno);
   561             /*
   562              * waitpid() cannot return 0 because we did not invoke it
   563              * with the WNOHANG option.
   564              */ 
   565 	    PR_ASSERT(0 != pid);
   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             }
   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 }
   588 #else /* _PR_NATIVE_THREADS */
   590 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
   602 #ifdef _PR_SHARE_CLONES
   603     pr_InstallSigchldHandler();
   604 #endif
   606     fd = PR_ImportFile(pr_wp.pipefd[0]);
   607     PR_ASSERT(NULL != fd);
   608     pd.fd = fd;
   609     pd.in_flags = PR_POLL_READ;
   611     while (1) {
   612         rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
   613         PR_ASSERT(1 == rv);
   615 #ifdef _PR_SHARE_CLONES
   616         if (pr_waitpid_daemon_exit) {
   617             return;
   618         }
   619 	PR_Lock(pr_wp.ml);
   620 #endif
   622         do {
   623             rv = read(pr_wp.pipefd[0], buf, sizeof(buf));
   624         } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno));
   626 #ifdef _PR_SHARE_CLONES
   627 	PR_Unlock(pr_wp.ml);
   628 	while ((op = pr_wp.opHead) != NULL) {
   629 	    op->process = ForkAndExec(op->path, op->argv,
   630 		    op->envp, op->attr);
   631 	    if (NULL == op->process) {
   632 		op->prerror = PR_GetError();
   633 		op->oserror = PR_GetOSError();
   634 	    }
   635 	    PR_Lock(pr_wp.ml);
   636 	    pr_wp.opHead = op->next;
   637 	    if (NULL == pr_wp.opHead) {
   638 		pr_wp.opTail = NULL;
   639 	    }
   640 	    op->done = PR_TRUE;
   641 	    PR_NotifyCondVar(op->doneCV);
   642 	    PR_Unlock(pr_wp.ml);
   643 	}
   644 #endif
   646 	while (1) {
   647 	    do {
   648 	        pid = waitpid((pid_t) -1, &status, WNOHANG);
   649 	    } while ((pid_t) -1 == pid && EINTR == errno);
   650 	    if (0 == pid) break;
   651 	    if ((pid_t) -1 == pid) {
   652 		/* must be because we have no child processes */
   653 		PR_ASSERT(ECHILD == errno);
   654 		break;
   655             }
   657 	    PR_Lock(pr_wp.ml);
   658             ProcessReapedChildInternal(pid, status);
   659 	    PR_Unlock(pr_wp.ml);
   660 	}
   661     }
   662 }
   664 static void pr_SigchldHandler(int sig)
   665 {
   666     int errnoCopy;
   667     int rv;
   669     errnoCopy = errno;
   671     do {
   672         rv = write(pr_wp.pipefd[1], "", 1);
   673     } while (-1 == rv && EINTR == errno);
   675 #ifdef DEBUG
   676     if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) {
   677         char *msg = "cannot write to pipe\n";
   678         write(2, msg, strlen(msg) + 1);
   679         _exit(1);
   680     }
   681 #endif
   683     errno = errnoCopy;
   684 }
   686 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
   692     struct sigaction act, oact;
   693     int rv;
   695     act.sa_handler = pr_SigchldHandler;
   696     sigemptyset(&act.sa_mask);
   697     act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
   698     rv = sigaction(SIGCHLD, &act, &oact);
   699     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 }
   706 #endif  /* !defined(_PR_NATIVE_THREADS) */
   708 static PRStatus _MD_InitProcesses(void)
   709 {
   710 #if !defined(_PR_NATIVE_THREADS)
   711     int rv;
   712     int flags;
   713 #endif
   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 */
   726     pr_wp.ml = PR_NewLock();
   727     PR_ASSERT(NULL != pr_wp.ml);
   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     rv = pipe(pr_wp.pipefd);
   735     PR_ASSERT(0 == rv);
   736     flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0);
   737     fcntl(pr_wp.pipefd[0], F_SETFL, flags | O_NONBLOCK);
   738     flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0);
   739     fcntl(pr_wp.pipefd[1], F_SETFL, flags | O_NONBLOCK);
   741 #ifndef _PR_SHARE_CLONES
   742     pr_InstallSigchldHandler();
   743 #endif
   744 #endif  /* !_PR_NATIVE_THREADS */
   746     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     PR_ASSERT(NULL != pr_wp.thread);
   756     pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *));
   757     PR_ASSERT(NULL != pr_wp.pidTable);
   758     return PR_SUCCESS;
   759 }
   761 PRStatus _MD_DetachUnixProcess(PRProcess *process)
   762 {
   763     PRStatus retVal = PR_SUCCESS;
   764     pr_PidRecord *pRec;
   766     PR_Lock(pr_wp.ml);
   767     pRec = FindPidTable(process->md.pid);
   768     if (NULL == pRec) {
   769 	pRec = PR_NEW(pr_PidRecord);
   770 	if (NULL == pRec) {
   771 	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   772 	    retVal = PR_FAILURE;
   773 	    goto done;
   774 	}
   775 	pRec->pid = process->md.pid;
   776 	pRec->state = _PR_PID_DETACHED;
   777 	pRec->reapedCV = NULL;
   778 	InsertPidTable(pRec);
   779     } else {
   780 	PR_ASSERT(_PR_PID_REAPED == pRec->state);
   781 	if (_PR_PID_REAPED != pRec->state) {
   782 	    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   783 	    retVal = PR_FAILURE;
   784 	} else {
   785 	    DeletePidTable(pRec);
   786 	    PR_ASSERT(NULL == pRec->reapedCV);
   787 	    PR_DELETE(pRec);
   788 	}
   789     }
   790     PR_DELETE(process);
   792 done:
   793     PR_Unlock(pr_wp.ml);
   794     return retVal;
   795 }
   797 PRStatus _MD_WaitUnixProcess(
   798     PRProcess *process,
   799     PRInt32 *exitCode)
   800 {
   801     pr_PidRecord *pRec;
   802     PRStatus retVal = PR_SUCCESS;
   803     PRBool interrupted = PR_FALSE;
   805     PR_Lock(pr_wp.ml);
   806     pRec = FindPidTable(process->md.pid);
   807     if (NULL == pRec) {
   808 	pRec = PR_NEW(pr_PidRecord);
   809 	if (NULL == pRec) {
   810 	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   811 	    retVal = PR_FAILURE;
   812 	    goto done;
   813 	}
   814 	pRec->pid = process->md.pid;
   815 	pRec->state = _PR_PID_WAITING;
   816 	pRec->reapedCV = PR_NewCondVar(pr_wp.ml);
   817 	if (NULL == pRec->reapedCV) {
   818 	    PR_DELETE(pRec);
   819 	    retVal = PR_FAILURE;
   820 	    goto done;
   821 	}
   822 	InsertPidTable(pRec);
   823 	while (!interrupted && _PR_PID_REAPED != pRec->state) {
   824 	    if (PR_WaitCondVar(pRec->reapedCV,
   825 		    PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE
   826 		    && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
   827 		interrupted = PR_TRUE;
   828             }
   829 	}
   830 	if (_PR_PID_REAPED == pRec->state) {
   831             if (exitCode) {
   832                 *exitCode = pRec->exitStatus;
   833             }
   834 	} else {
   835 	    PR_ASSERT(interrupted);
   836 	    retVal = PR_FAILURE;
   837 	}
   838 	DeletePidTable(pRec);
   839 	PR_DestroyCondVar(pRec->reapedCV);
   840 	PR_DELETE(pRec);
   841     } else {
   842 	PR_ASSERT(_PR_PID_REAPED == pRec->state);
   843 	PR_ASSERT(NULL == pRec->reapedCV);
   844 	DeletePidTable(pRec);
   845         if (exitCode) {
   846             *exitCode = pRec->exitStatus;
   847         }
   848 	PR_DELETE(pRec);
   849     }
   850     PR_DELETE(process);
   852 done:
   853     PR_Unlock(pr_wp.ml);
   854     return retVal;
   855 }  /* _MD_WaitUnixProcess */
   857 PRStatus _MD_KillUnixProcess(PRProcess *process)
   858 {
   859     PRErrorCode prerror;
   860     PRInt32 oserror;
   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     if (kill(process->md.pid, SIGKILL) == 0) {
   868 	return PR_SUCCESS;
   869     }
   870     oserror = errno;
   871     switch (oserror) {
   872         case EPERM:
   873 	    prerror = PR_NO_ACCESS_RIGHTS_ERROR;
   874 	    break;
   875         case ESRCH:
   876 	    prerror = PR_INVALID_ARGUMENT_ERROR;
   877 	    break;
   878         default:
   879 	    prerror = PR_UNKNOWN_ERROR;
   880 	    break;
   881     }
   882     PR_SetError(prerror, oserror);
   883     return PR_FAILURE;
   884 #endif
   885 }  /* _MD_KillUnixProcess */

mercurial