LCOV - app.info - nsprpub/pr/src/md/unix/uxproces.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/md/unix - uxproces.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 315 | 0 | 0.0 %
| Date: | 2012-04-07 | Functions: | 15 | 0 | 0.0 %

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

Generated by: LCOV version 1.7