blob: 47bc1a47ecb79c5827890c5bdcb8771e699eff61 [file] [log] [blame]
Index: nspr-4.8.6/mozilla/nsprpub/pr/src/md/unix/uxproces.c
===================================================================
--- nspr-4.8.6.orig/mozilla/nsprpub/pr/src/md/unix/uxproces.c
+++ nspr-4.8.6/mozilla/nsprpub/pr/src/md/unix/uxproces.c
@@ -60,6 +60,10 @@ PR_IMPORT_DATA(char **) environ;
#define SA_RESTART 0
#endif
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(ra) (sizeof(ra)/sizeof((ra)[0]))
+#endif
+
/*
**********************************************************************
*
@@ -457,6 +461,9 @@ _MD_CreateUnixProcess(
#define NBUCKETS_LOG2 6
#define NBUCKETS (1 << NBUCKETS_LOG2)
#define PID_HASH_MASK ((pid_t) (NBUCKETS - 1))
+#define BITS_PER_CHAR 8
+#define MAX_PIDS 65535
+#define MAX_ENTRIES_PER_BUCKET (MAX_PIDS / NBUCKETS)
static pr_PidRecord *
CreatePidRecord(void)
@@ -631,14 +638,90 @@ static void WaitPidDaemonThread(void *un
#else /* _PR_NATIVE_THREADS */
+// only accessed from WaitPidDaemonThread()
+static pid_t pr_wp_pids[MAX_ENTRIES_PER_BUCKET];
+
+static void WaitForPidsInArray(unsigned count)
+{
+ unsigned n;
+ pid_t pid;
+ int status;
+
+ for (n = 0; n < count; ++n) {
+ do {
+ pid = waitpid(pr_wp_pids[n], &status, WNOHANG);
+ } while ((pid_t) -1 == pid && EINTR == errno);
+
+ if (pid == 0) /* still running */
+ continue;
+
+ PR_ASSERT((pid_t) -1 != pid);
+
+ PR_Lock(pr_wp.ml);
+ ProcessReapedChildInternal(pid, status);
+ PR_Unlock(pr_wp.ml);
+ }
+}
+
+static void WaitForPidsInBucket(unsigned bucketIndex)
+{
+ pr_PidRecord *pRec = NULL;
+ unsigned count;
+ unsigned maxIteratorInvalidation = 2;
+
+ while (1)
+ {
+ count = 0;
+
+ PR_Lock(pr_wp.ml);
+
+ if (NULL == pRec) {
+ pRec = pr_wp.pidTable[bucketIndex];
+ } else {
+ // while unlocked, pRec could have been deleted.
+ pr_PidRecord *pCur = pr_wp.pidTable[bucketIndex];
+ while ((NULL != pCur) && (pCur != pRec)) {
+ pCur = pCur->next;
+ }
+
+ if (NULL == pCur) {
+ if (maxIteratorInvalidation > 0) {
+ --maxIteratorInvalidation;
+ pRec = pr_wp.pidTable[bucketIndex];
+ } else {
+ pRec = NULL;
+ }
+ }
+ // else pRec was found and is still valid
+ }
+
+ while ((NULL != pRec) && (count < ARRAY_SIZE(pr_wp_pids))) {
+ if (pRec->pid > 0 && (_PR_PID_REAPED != pRec->state)) {
+ pr_wp_pids[count] = pRec->pid;
+ ++count;
+ }
+ pRec = pRec->next;
+ }
+
+ PR_Unlock(pr_wp.ml);
+
+ if (count == 0)
+ break;
+
+ WaitForPidsInArray(count);
+
+ if (NULL == pRec)
+ break;
+ }
+}
+
static void WaitPidDaemonThread(void *unused)
{
PRPollDesc pd;
PRFileDesc *fd;
int rv;
char ctmp;
- pid_t pid;
- int status;
+ unsigned bucket;
#ifdef _PR_SHARE_CLONES
struct pr_CreateProcOp *op;
#endif
@@ -677,6 +760,18 @@ static void WaitPidDaemonThread(void *un
op->oserror = PR_GetOSError();
}
PR_Lock(pr_wp.ml);
+ if (op->process) {
+ pr_PidRecord *pRec = FindPidTable(op->process->md.pid);
+ // If someone forgets to detach or wait for their process,
+ // the stale entry hangs around until the OS re-uses the PID
+ PR_ASSERT(NULL == pRec);
+ pRec = CreatePidRecord();
+ PR_ASSERT(pRec);
+ pRec->pid = op->process->md.pid;
+ pRec->state = _PR_PID_WAITING;
+ pRec->exitStatus = -1;
+ InsertPidTable(pRec);
+ }
pr_wp.opHead = op->next;
if (NULL == pr_wp.opHead) {
pr_wp.opTail = NULL;
@@ -687,20 +782,8 @@ static void WaitPidDaemonThread(void *un
}
#endif
- while (1) {
- do {
- pid = waitpid((pid_t) -1, &status, WNOHANG);
- } while ((pid_t) -1 == pid && EINTR == errno);
- if (0 == pid) break;
- if ((pid_t) -1 == pid) {
- /* must be because we have no child processes */
- PR_ASSERT(ECHILD == errno);
- break;
- }
-
- PR_Lock(pr_wp.ml);
- ProcessReapedChildInternal(pid, status);
- PR_Unlock(pr_wp.ml);
+ for (bucket = 0; bucket < NBUCKETS; ++bucket) {
+ WaitForPidsInBucket(bucket);
}
}
}
@@ -825,13 +908,14 @@ PRStatus _MD_DetachUnixProcess(PRProcess
pRec->state = _PR_PID_DETACHED;
InsertPidTable(pRec);
} else {
- PR_ASSERT(_PR_PID_REAPED == pRec->state);
- if (_PR_PID_REAPED != pRec->state) {
+ if (_PR_PID_WAITING == pRec->state) {
+ pRec->state = _PR_PID_DETACHED;
+ } else if (_PR_PID_REAPED == pRec->state) {
+ DeletePidTable(pRec);
+ DeletePidRecord(pRec);
+ } else {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
retVal = PR_FAILURE;
- } else {
- DeletePidTable(pRec);
- DeletePidRecord(pRec);
}
}
PR_DELETE(process);
@@ -879,11 +963,32 @@ PRStatus _MD_WaitUnixProcess(
DeletePidTable(pRec);
DeletePidRecord(pRec);
} else {
- PR_ASSERT(_PR_PID_REAPED == pRec->state);
+ if (_PR_PID_WAITING == pRec->state)
+ {
+ while (!interrupted && _PR_PID_REAPED != pRec->state) {
+ if (PR_WaitCondVar(pRec->reapedCV, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE
+ && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
+ interrupted = PR_TRUE;
+ }
+ }
+ } else if (_PR_PID_DETACHED == pRec->state) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ retVal = PR_FAILURE;
+ goto done;
+ } else {
+ PR_ASSERT(_PR_PID_REAPED == pRec->state);
+ }
+
+ if (_PR_PID_REAPED == pRec->state) {
+ if (exitCode) {
+ *exitCode = pRec->exitStatus;
+ }
+ } else if (retVal == PR_SUCCESS) {
+ PR_ASSERT(interrupted);
+ retVal = PR_FAILURE;
+ }
+
DeletePidTable(pRec);
- if (exitCode) {
- *exitCode = pRec->exitStatus;
- }
DeletePidRecord(pRec);
}
PR_DELETE(process);