home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / unix / uxproces.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  17.6 KB  |  716 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20.  
  21. #include <sys/types.h>
  22. #include <unistd.h>
  23. #include <fcntl.h>
  24. #include <signal.h>
  25. #include <sys/wait.h>
  26.  
  27. /*
  28.  **********************************************************************
  29.  *
  30.  * The Unix process routines
  31.  *
  32.  **********************************************************************
  33.  */
  34.  
  35. #define _PR_SIGNALED_EXITSTATUS 256
  36.  
  37. typedef enum pr_PidState {
  38.     _PR_PID_DETACHED,
  39.     _PR_PID_REAPED,
  40.     _PR_PID_WAITING
  41. } pr_PidState;
  42.  
  43. typedef struct pr_PidRecord {
  44.     pid_t pid;
  45.     int exitStatus;
  46.     pr_PidState state;
  47.     PRCondVar *reapedCV;
  48.     struct pr_PidRecord *next;
  49. } pr_PidRecord;
  50.  
  51. /*
  52.  * Irix sprocs and LinuxThreads are actually a kind of processes
  53.  * that can share the virtual address space and file descriptors.
  54.  */
  55. #if (defined(IRIX) && !defined(_PR_PTHREADS)) \
  56.         || (defined(LINUX) && defined(_PR_PTHREADS))
  57. #define _PR_SHARE_CLONES
  58. #endif
  59.  
  60. /*
  61.  * The macro _PR_NATIVE_THREADS indicates that we are
  62.  * using native threads only, so waitpid() blocks just the
  63.  * calling thread, not the process.  In this case, the waitpid
  64.  * daemon thread can safely block in waitpid().  So we don't
  65.  * need to catch SIGCHLD, and the pipe to unblock PR_Poll() is
  66.  * also not necessary.
  67.  */
  68.  
  69. #if defined(_PR_GLOBAL_THREADS_ONLY) \
  70.     || (defined(_PR_PTHREADS) && !defined(LINUX))
  71. #define _PR_NATIVE_THREADS
  72. #endif
  73.  
  74. /*
  75.  * All the static variables used by the Unix process routines are
  76.  * collected in this structure.
  77.  */
  78.  
  79. static struct {
  80.     PRCallOnceType once;
  81.     PRThread *thread;
  82.     PRLock *ml;
  83. #if defined(_PR_NATIVE_THREADS)
  84.     PRInt32 numProcs;
  85.     PRCondVar *cv;
  86. #else
  87.     int pipefd[2];
  88. #endif
  89.     pr_PidRecord **pidTable;
  90.  
  91. #ifdef _PR_SHARE_CLONES
  92.     struct pr_CreateProcOp *opHead, *opTail;
  93. #endif
  94. } pr_wp;
  95.  
  96. #ifdef _PR_SHARE_CLONES
  97. static int pr_waitpid_daemon_exit;
  98.  
  99. void
  100. _MD_unix_terminate_waitpid_daemon(void)
  101. {
  102.     if (pr_wp.thread) {
  103.         pr_waitpid_daemon_exit = 1;
  104.         write(pr_wp.pipefd[1], "", 1);
  105.         PR_JoinThread(pr_wp.thread);
  106.     }
  107. }
  108. #endif
  109.  
  110. static PRStatus _MD_InitProcesses(void);
  111. #if !defined(_PR_NATIVE_THREADS)
  112. static void pr_InstallSigchldHandler(void);
  113. #endif
  114.  
  115. static PRProcess *
  116. ForkAndExec(
  117.     const char *path,
  118.     char *const *argv,
  119.     char *const *envp,
  120.     const PRProcessAttr *attr)
  121. {
  122.     PRProcess *process;
  123.     
  124.     process = PR_NEW(PRProcess);
  125.     if (!process) {
  126.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  127.         return NULL;
  128.     }
  129.  
  130.     process->md.pid = fork();
  131.     if ((pid_t) -1 == process->md.pid) {
  132.         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
  133.         PR_DELETE(process);
  134.         return NULL;
  135.     } else if (0 == process->md.pid) {  /* the child process */
  136.         /*
  137.          * If the child process needs to exit, it must call _exit().
  138.          * Do not call exit(), because exit() will flush and close
  139.          * the standard I/O file descriptors, and hence corrupt
  140.          * the parent process's standard I/O data structures.
  141.          */
  142.  
  143.         if (attr) {
  144.             if (attr->stdinFd
  145.                     && attr->stdinFd->secret->md.osfd != 0) {
  146.                 if (dup2(attr->stdinFd->secret->md.osfd, 0) != 0) {
  147.                     _exit(1);  /* failed */
  148.                 }
  149.                 close(attr->stdinFd->secret->md.osfd);
  150.             }
  151.             if (attr->stdoutFd
  152.                     && attr->stdoutFd->secret->md.osfd != 1) {
  153.                 if (dup2(attr->stdoutFd->secret->md.osfd, 1) != 1) {
  154.                     _exit(1);  /* failed */
  155.                 }
  156.                 close(attr->stdoutFd->secret->md.osfd);
  157.             }
  158.             if (attr->stderrFd
  159.                     && attr->stderrFd->secret->md.osfd != 2) {
  160.                 if (dup2(attr->stderrFd->secret->md.osfd, 2) != 2) {
  161.                     _exit(1);  /* failed */
  162.                 }
  163.                 close(attr->stderrFd->secret->md.osfd);
  164.             }
  165.         }
  166.  
  167.         (void)execve(path, argv, envp);
  168.         /* Whoops! It returned. That's a bad sign. */
  169.         _exit(1);
  170.     }
  171.  
  172. #if defined(_PR_NATIVE_THREADS)
  173.     PR_Lock(pr_wp.ml);
  174.     if (0 == pr_wp.numProcs++) {
  175.         PR_NotifyCondVar(pr_wp.cv);
  176.     }
  177.     PR_Unlock(pr_wp.ml);
  178. #endif
  179.     return process;
  180. }
  181.  
  182. #ifdef _PR_SHARE_CLONES
  183.  
  184. struct pr_CreateProcOp {
  185.     const char *path;
  186.     char *const *argv;
  187.     char *const *envp;
  188.     const PRProcessAttr *attr;
  189.     PRProcess *process;
  190.     PRErrorCode prerror;
  191.     PRInt32 oserror;
  192.     PRBool done;
  193.     PRCondVar *doneCV;
  194.     struct pr_CreateProcOp *next;
  195. };
  196.  
  197. PRProcess *
  198. _MD_CreateUnixProcess(
  199.     const char *path,
  200.     char *const *argv,
  201.     char *const *envp,
  202.     const PRProcessAttr *attr)
  203. {
  204.     struct pr_CreateProcOp *op;
  205.     PRProcess *proc;
  206.     int rv;
  207.  
  208.     if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
  209.     return NULL;
  210.     }
  211.  
  212.     op = PR_NEW(struct pr_CreateProcOp);
  213.     if (NULL == op) {
  214.     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  215.     return NULL;
  216.     }
  217.     op->path = path;
  218.     op->argv = argv;
  219.     op->envp = envp;
  220.     op->attr = attr;
  221.     op->done = PR_FALSE;
  222.     op->doneCV = PR_NewCondVar(pr_wp.ml);
  223.     if (NULL == op->doneCV) {
  224.     PR_DELETE(op);
  225.     return NULL;
  226.     }
  227.     PR_Lock(pr_wp.ml);
  228.  
  229.     /* add to the tail of op queue */
  230.     op->next = NULL;
  231.     if (pr_wp.opTail) {
  232.     pr_wp.opTail->next = op;
  233.     pr_wp.opTail = op;
  234.     } else {
  235.     PR_ASSERT(NULL == pr_wp.opHead);
  236.     pr_wp.opHead = pr_wp.opTail = op;
  237.     }
  238.  
  239.     /* wake up the daemon thread */
  240.     do {
  241.         rv = write(pr_wp.pipefd[1], "", 1);
  242.     } while (-1 == rv && EINTR == errno);
  243.  
  244.     while (op->done == PR_FALSE) {
  245.     PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT);
  246.     }
  247.     PR_Unlock(pr_wp.ml);
  248.     PR_DestroyCondVar(op->doneCV);
  249.     proc = op->process;
  250.     if (!proc) {
  251.     PR_SetError(op->prerror, op->oserror);
  252.     }
  253.     PR_DELETE(op);
  254.     return proc;
  255. }
  256.  
  257. #else  /* ! _PR_SHARE_CLONES */
  258.  
  259. PRProcess *
  260. _MD_CreateUnixProcess(
  261.     const char *path,
  262.     char *const *argv,
  263.     char *const *envp,
  264.     const PRProcessAttr *attr)
  265. {
  266.     if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
  267.     return NULL;
  268.     }
  269.     return ForkAndExec(path, argv, envp, attr);
  270. }  /* _MD_CreateUnixProcess */
  271.  
  272. #endif  /* _PR_SHARE_CLONES */
  273.  
  274. /*
  275.  * The pid table is a hashtable.
  276.  *
  277.  * The number of buckets in the hashtable (NBUCKETS) must be a power of 2.
  278.  */
  279. #define NBUCKETS_LOG2 6
  280. #define NBUCKETS (1 << NBUCKETS_LOG2)
  281. #define PID_HASH_MASK ((pid_t) (NBUCKETS - 1))
  282.  
  283. static pr_PidRecord *
  284. FindPidTable(pid_t pid)
  285. {
  286.     pr_PidRecord *pRec;
  287.     int keyHash = (int) (pid & PID_HASH_MASK);
  288.  
  289.     pRec =  pr_wp.pidTable[keyHash];
  290.     while (pRec) {
  291.     if (pRec->pid == pid) {
  292.         break;
  293.     }
  294.     pRec = pRec->next;
  295.     }
  296.     return pRec;
  297. }
  298.  
  299. static void
  300. InsertPidTable(pr_PidRecord *pRec)
  301. {
  302.     int keyHash = (int) (pRec->pid & PID_HASH_MASK);
  303.  
  304.     pRec->next = pr_wp.pidTable[keyHash];
  305.     pr_wp.pidTable[keyHash] = pRec;
  306. }
  307.  
  308. static void
  309. DeletePidTable(pr_PidRecord *pRec)
  310. {
  311.     int keyHash = (int) (pRec->pid & PID_HASH_MASK);
  312.  
  313.     if (pr_wp.pidTable[keyHash] == pRec) {
  314.     pr_wp.pidTable[keyHash] = pRec->next;
  315.     } else {
  316.     pr_PidRecord *pred, *cur;  /* predecessor and current */
  317.  
  318.     pred = pr_wp.pidTable[keyHash];
  319.     cur = pred->next;
  320.     while (cur) {
  321.         if (cur == pRec) {
  322.         pred->next = cur->next;
  323.         break;
  324.             }
  325.         pred = cur;
  326.         cur = cur->next;
  327.         }
  328.     PR_ASSERT(cur != NULL);
  329.     }
  330. }
  331.  
  332. static int
  333. ExtractExitStatus(int rawExitStatus)
  334. {
  335.     /*
  336.      * We did not specify the WCONTINUED and WUNTRACED options
  337.      * for waitpid, so these two events should not be reported.
  338.      */
  339.     PR_ASSERT(!WIFSTOPPED(rawExitStatus));
  340. #ifdef WIFCONTINUED
  341.     PR_ASSERT(!WIFCONTINUED(rawExitStatus));
  342. #endif
  343.     if (WIFEXITED(rawExitStatus)) {
  344.     return WEXITSTATUS(rawExitStatus);
  345.     } else {
  346.     PR_ASSERT(WIFSIGNALED(rawExitStatus));
  347.     return _PR_SIGNALED_EXITSTATUS;
  348.     }
  349. }
  350.  
  351. static void
  352. ProcessReapedChildInternal(pid_t pid, int status)
  353. {
  354.     pr_PidRecord *pRec;
  355.  
  356.     pRec = FindPidTable(pid);
  357.     if (NULL == pRec) {
  358.         pRec = PR_NEW(pr_PidRecord);
  359.         pRec->pid = pid;
  360.         pRec->state = _PR_PID_REAPED;
  361.         pRec->exitStatus = ExtractExitStatus(status);
  362.         pRec->reapedCV = NULL;
  363.         InsertPidTable(pRec);
  364.     } else {
  365.         PR_ASSERT(pRec->state != _PR_PID_REAPED);
  366.         if (_PR_PID_DETACHED == pRec->state) {
  367.             PR_ASSERT(NULL == pRec->reapedCV);
  368.             DeletePidTable(pRec);
  369.             PR_DELETE(pRec);
  370.         } else {
  371.             PR_ASSERT(_PR_PID_WAITING == pRec->state);
  372.             PR_ASSERT(NULL != pRec->reapedCV);
  373.             pRec->exitStatus = ExtractExitStatus(status);
  374.             pRec->state = _PR_PID_REAPED;
  375.             PR_NotifyCondVar(pRec->reapedCV);
  376.         }
  377.     }
  378. }
  379.  
  380. #if defined(_PR_NATIVE_THREADS)
  381.  
  382. /*
  383.  * If all the threads are native threads, the daemon thread is
  384.  * simpler.  We don't need to catch the SIGCHLD signal.  We can
  385.  * just have the daemon thread block in waitpid().
  386.  */
  387.  
  388. static void WaitPidDaemonThread(void *unused)
  389. {
  390.     pid_t pid;
  391.     int status;
  392.  
  393.     while (1) {
  394.         PR_Lock(pr_wp.ml);
  395.         while (0 == pr_wp.numProcs) {
  396.             PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
  397.         }
  398.         PR_Unlock(pr_wp.ml);
  399.  
  400.     while (1) {
  401.         do {
  402.             pid = waitpid((pid_t) -1, &status, 0);
  403.         } while ((pid_t) -1 == pid && EINTR == errno);
  404.  
  405.             /*
  406.              * waitpid() cannot return 0 because we did not invoke it
  407.              * with the WNOHANG option.
  408.              */ 
  409.         PR_ASSERT(0 != pid);
  410.  
  411.             /*
  412.              * The only possible error code is ECHILD.  But if we do
  413.              * our accounting correctly, we should only call waitpid()
  414.              * when there is a child process to wait for.
  415.              */
  416.             PR_ASSERT((pid_t) -1 != pid);
  417.         if ((pid_t) -1 == pid) {
  418.                 break;
  419.             }
  420.  
  421.         PR_Lock(pr_wp.ml);
  422.             ProcessReapedChildInternal(pid, status);
  423.             pr_wp.numProcs--;
  424.             while (0 == pr_wp.numProcs) {
  425.                 PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
  426.             }
  427.         PR_Unlock(pr_wp.ml);
  428.     }
  429.     }
  430. }
  431.  
  432. #else /* _PR_NATIVE_THREADS */
  433.  
  434. static void WaitPidDaemonThread(void *unused)
  435. {
  436.     PRPollDesc pd;
  437.     PRFileDesc *fd;
  438.     int rv;
  439.     char buf[128];
  440.     pid_t pid;
  441.     int status;
  442. #ifdef _PR_SHARE_CLONES
  443.     struct pr_CreateProcOp *op;
  444. #endif
  445.  
  446. #ifdef _PR_SHARE_CLONES
  447.     pr_InstallSigchldHandler();
  448. #endif
  449.  
  450.     fd = PR_ImportFile(pr_wp.pipefd[0]);
  451.     PR_ASSERT(NULL != fd);
  452.     pd.fd = fd;
  453.     pd.in_flags = PR_POLL_READ;
  454.  
  455.     while (1) {
  456.         rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
  457.         PR_ASSERT(1 == rv);
  458.  
  459. #ifdef _PR_SHARE_CLONES
  460.         if (pr_waitpid_daemon_exit) {
  461.             return;
  462.         }
  463.     PR_Lock(pr_wp.ml);
  464. #endif
  465.         
  466.         do {
  467.             rv = read(pr_wp.pipefd[0], buf, sizeof(buf));
  468.         } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno));
  469.  
  470. #ifdef _PR_SHARE_CLONES
  471.     PR_Unlock(pr_wp.ml);
  472.     while ((op = pr_wp.opHead) != NULL) {
  473.         op->process = ForkAndExec(op->path, op->argv,
  474.             op->envp, op->attr);
  475.         if (NULL == op->process) {
  476.         op->prerror = PR_GetError();
  477.         op->oserror = PR_GetOSError();
  478.         }
  479.         PR_Lock(pr_wp.ml);
  480.         pr_wp.opHead = op->next;
  481.         if (NULL == pr_wp.opHead) {
  482.         pr_wp.opTail = NULL;
  483.         }
  484.         op->done = PR_TRUE;
  485.         PR_NotifyCondVar(op->doneCV);
  486.         PR_Unlock(pr_wp.ml);
  487.     }
  488. #endif
  489.  
  490.     while (1) {
  491.         do {
  492.             pid = waitpid((pid_t) -1, &status, WNOHANG);
  493.         } while ((pid_t) -1 == pid && EINTR == errno);
  494.         if (0 == pid) break;
  495.         if ((pid_t) -1 == pid) {
  496.         /* must be because we have no child processes */
  497.         PR_ASSERT(ECHILD == errno);
  498.         break;
  499.             }
  500.  
  501.         PR_Lock(pr_wp.ml);
  502.             ProcessReapedChildInternal(pid, status);
  503.         PR_Unlock(pr_wp.ml);
  504.     }
  505.     }
  506. }
  507.  
  508. static void pr_SigchldHandler(int sig)
  509. {
  510.     int errnoCopy;
  511.     int rv;
  512.  
  513.     errnoCopy = errno;
  514.  
  515.     do {
  516.         rv = write(pr_wp.pipefd[1], "", 1);
  517.     } while (-1 == rv && EINTR == errno);
  518.  
  519. #ifdef DEBUG
  520.     if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) {
  521.         char *msg = "cannot write to pipe\n";
  522.         write(2, msg, strlen(msg) + 1);
  523.         _exit(1);
  524.     }
  525. #endif
  526.  
  527.     errno = errnoCopy;
  528. }
  529.  
  530. static void pr_InstallSigchldHandler()
  531. {
  532. #if defined(HPUX) && defined(_PR_DCETHREADS)
  533. #error "HP-UX DCE threads have their own SIGCHLD handler"
  534. #endif
  535.  
  536.     struct sigaction act, oact;
  537.     int rv;
  538.  
  539.     act.sa_handler = pr_SigchldHandler;
  540.     sigemptyset(&act.sa_mask);
  541.     act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
  542.     rv = sigaction(SIGCHLD, &act, &oact);
  543.     PR_ASSERT(0 == rv);
  544.     /* Make sure we are not overriding someone else's SIGCHLD handler */
  545. #ifndef _PR_SHARE_CLONES
  546.     PR_ASSERT(oact.sa_handler == SIG_DFL);
  547. #endif
  548. }
  549.  
  550. #endif  /* !defined(_PR_NATIVE_THREADS) */
  551.  
  552. static PRStatus _MD_InitProcesses()
  553. {
  554. #if !defined(_PR_NATIVE_THREADS)
  555.     int rv;
  556.     int flags;
  557. #endif
  558. #ifdef SUNOS4
  559. #define _PR_NBIO_FLAG FNDELAY
  560. #else
  561. #define _PR_NBIO_FLAG O_NONBLOCK
  562. #endif
  563.  
  564.     pr_wp.ml = PR_NewLock();
  565.     PR_ASSERT(NULL != pr_wp.ml);
  566.  
  567. #if defined(_PR_NATIVE_THREADS)
  568.     pr_wp.numProcs = 0;
  569.     pr_wp.cv = PR_NewCondVar(pr_wp.ml);
  570.     PR_ASSERT(NULL != pr_wp.cv);
  571. #else
  572.     rv = pipe(pr_wp.pipefd);
  573.     PR_ASSERT(0 == rv);
  574.     flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0);
  575.     fcntl(pr_wp.pipefd[0], F_SETFL, flags | _PR_NBIO_FLAG);
  576.     flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0);
  577.     fcntl(pr_wp.pipefd[1], F_SETFL, flags | _PR_NBIO_FLAG);
  578.  
  579. #ifndef _PR_SHARE_CLONES
  580.     pr_InstallSigchldHandler();
  581. #endif
  582. #endif  /* !_PR_NATIVE_THREADS */
  583.  
  584.     pr_wp.thread = PR_CreateThread(PR_SYSTEM_THREAD,
  585.         WaitPidDaemonThread, NULL, PR_PRIORITY_NORMAL,
  586. #ifdef _PR_SHARE_CLONES
  587.             PR_GLOBAL_THREAD,
  588. #else
  589.         PR_LOCAL_THREAD,
  590. #endif
  591.         PR_JOINABLE_THREAD, 0);
  592.     PR_ASSERT(NULL != pr_wp.thread);
  593.  
  594.     pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *));
  595.     PR_ASSERT(NULL != pr_wp.pidTable);
  596.     return PR_SUCCESS;
  597. }
  598.  
  599. PRStatus _MD_DetachUnixProcess(PRProcess *process)
  600. {
  601.     PRStatus retVal = PR_SUCCESS;
  602.     pr_PidRecord *pRec;
  603.  
  604.     PR_Lock(pr_wp.ml);
  605.     pRec = FindPidTable(process->md.pid);
  606.     if (NULL == pRec) {
  607.     pRec = PR_NEW(pr_PidRecord);
  608.     if (NULL == pRec) {
  609.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  610.         retVal = PR_FAILURE;
  611.         goto done;
  612.     }
  613.     pRec->pid = process->md.pid;
  614.     pRec->state = _PR_PID_DETACHED;
  615.     pRec->reapedCV = NULL;
  616.     InsertPidTable(pRec);
  617.     } else {
  618.     PR_ASSERT(_PR_PID_REAPED == pRec->state);
  619.     if (_PR_PID_REAPED != pRec->state) {
  620.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  621.         retVal = PR_FAILURE;
  622.     } else {
  623.         DeletePidTable(pRec);
  624.         PR_ASSERT(NULL == pRec->reapedCV);
  625.         PR_DELETE(pRec);
  626.     }
  627.     }
  628.  
  629. done:
  630.     PR_Unlock(pr_wp.ml);
  631.     return retVal;
  632. }
  633.  
  634. PRStatus _MD_WaitUnixProcess(
  635.     PRProcess *process,
  636.     PRInt32 *exitCode)
  637. {
  638.     pr_PidRecord *pRec;
  639.     PRStatus retVal = PR_SUCCESS;
  640.     PRBool interrupted = PR_FALSE;
  641.  
  642.     PR_Lock(pr_wp.ml);
  643.     pRec = FindPidTable(process->md.pid);
  644.     if (NULL == pRec) {
  645.     pRec = PR_NEW(pr_PidRecord);
  646.     if (NULL == pRec) {
  647.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  648.         retVal = PR_FAILURE;
  649.         goto done;
  650.     }
  651.     pRec->pid = process->md.pid;
  652.     pRec->state = _PR_PID_WAITING;
  653.     pRec->reapedCV = PR_NewCondVar(pr_wp.ml);
  654.     if (NULL == pRec->reapedCV) {
  655.         PR_DELETE(pRec);
  656.         retVal = PR_FAILURE;
  657.         goto done;
  658.     }
  659.     InsertPidTable(pRec);
  660.     while (!interrupted && _PR_PID_REAPED != pRec->state) {
  661.         if (PR_WaitCondVar(pRec->reapedCV,
  662.             PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE
  663.             && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
  664.         interrupted = PR_TRUE;
  665.             }
  666.     }
  667.     if (_PR_PID_REAPED == pRec->state) {
  668.             if (exitCode) {
  669.                 *exitCode = pRec->exitStatus;
  670.             }
  671.     } else {
  672.         PR_ASSERT(interrupted);
  673.         retVal = PR_FAILURE;
  674.     }
  675.     DeletePidTable(pRec);
  676.     PR_DestroyCondVar(pRec->reapedCV);
  677.     PR_DELETE(pRec);
  678.     } else {
  679.     PR_ASSERT(_PR_PID_REAPED == pRec->state);
  680.     PR_ASSERT(NULL == pRec->reapedCV);
  681.     DeletePidTable(pRec);
  682.         if (exitCode) {
  683.             *exitCode = pRec->exitStatus;
  684.         }
  685.     PR_DELETE(pRec);
  686.     }
  687.  
  688. done:
  689.     PR_Unlock(pr_wp.ml);
  690.     return retVal;
  691. }  /* _MD_WaitUnixProcess */
  692.  
  693. PRStatus _MD_KillUnixProcess(PRProcess *process)
  694. {
  695.     PRErrorCode prerror;
  696.     PRInt32 oserror;
  697.  
  698.     if (kill(process->md.pid, SIGKILL) == 0) {
  699.     return PR_SUCCESS;
  700.     }
  701.     oserror = errno;
  702.     switch (oserror) {
  703.         case EPERM:
  704.         prerror = PR_NO_ACCESS_RIGHTS_ERROR;
  705.         break;
  706.         case ESRCH:
  707.         prerror = PR_INVALID_ARGUMENT_ERROR;
  708.         break;
  709.         default:
  710.         prerror = PR_UNKNOWN_ERROR;
  711.         break;
  712.     }
  713.     PR_SetError(prerror, oserror);
  714.     return PR_FAILURE;
  715. }  /* _MD_KillUnixProcess */
  716.