diff nspr/pr/src/md/unix/uxproces.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nspr/pr/src/md/unix/uxproces.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,885 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "primpl.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <string.h>
+#if defined(AIX)
+#include <dlfcn.h>  /* For dlopen, dlsym, dlclose */
+#endif
+
+#if defined(DARWIN)
+#if defined(HAVE_CRT_EXTERNS_H)
+#include <crt_externs.h>
+#endif
+#else
+PR_IMPORT_DATA(char **) environ;
+#endif
+
+/*
+ * HP-UX 9 doesn't have the SA_RESTART flag.
+ */
+#ifndef SA_RESTART
+#define SA_RESTART 0
+#endif
+
+/*
+ **********************************************************************
+ *
+ * The Unix process routines
+ *
+ **********************************************************************
+ */
+
+#define _PR_SIGNALED_EXITSTATUS 256
+
+typedef enum pr_PidState {
+    _PR_PID_DETACHED,
+    _PR_PID_REAPED,
+    _PR_PID_WAITING
+} pr_PidState;
+
+typedef struct pr_PidRecord {
+    pid_t pid;
+    int exitStatus;
+    pr_PidState state;
+    PRCondVar *reapedCV;
+    struct pr_PidRecord *next;
+} pr_PidRecord;
+
+/*
+ * Irix sprocs and LinuxThreads are actually a kind of processes
+ * that can share the virtual address space and file descriptors.
+ */
+#if (defined(IRIX) && !defined(_PR_PTHREADS)) \
+        || ((defined(LINUX) || defined(__GNU__) || defined(__GLIBC__)) \
+        && defined(_PR_PTHREADS))
+#define _PR_SHARE_CLONES
+#endif
+
+/*
+ * The macro _PR_NATIVE_THREADS indicates that we are
+ * using native threads only, so waitpid() blocks just the
+ * calling thread, not the process.  In this case, the waitpid
+ * daemon thread can safely block in waitpid().  So we don't
+ * need to catch SIGCHLD, and the pipe to unblock PR_Poll() is
+ * also not necessary.
+ */
+
+#if defined(_PR_GLOBAL_THREADS_ONLY) \
+	|| (defined(_PR_PTHREADS) \
+	&& !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__))
+#define _PR_NATIVE_THREADS
+#endif
+
+/*
+ * All the static variables used by the Unix process routines are
+ * collected in this structure.
+ */
+
+static struct {
+    PRCallOnceType once;
+    PRThread *thread;
+    PRLock *ml;
+#if defined(_PR_NATIVE_THREADS)
+    PRInt32 numProcs;
+    PRCondVar *cv;
+#else
+    int pipefd[2];
+#endif
+    pr_PidRecord **pidTable;
+
+#ifdef _PR_SHARE_CLONES
+    struct pr_CreateProcOp *opHead, *opTail;
+#endif
+
+#ifdef AIX
+    pid_t (*forkptr)(void);  /* Newer versions of AIX (starting in 4.3.2)
+                              * have f_fork, which is faster than the
+                              * regular fork in a multithreaded process
+                              * because it skips calling the fork handlers.
+                              * So we look up the f_fork symbol to see if
+                              * it's available and fall back on fork.
+                              */
+#endif /* AIX */
+} pr_wp;
+
+#ifdef _PR_SHARE_CLONES
+static int pr_waitpid_daemon_exit;
+
+void
+_MD_unix_terminate_waitpid_daemon(void)
+{
+    if (pr_wp.thread) {
+        pr_waitpid_daemon_exit = 1;
+        write(pr_wp.pipefd[1], "", 1);
+        PR_JoinThread(pr_wp.thread);
+    }
+}
+#endif
+
+static PRStatus _MD_InitProcesses(void);
+#if !defined(_PR_NATIVE_THREADS)
+static void pr_InstallSigchldHandler(void);
+#endif
+
+static PRProcess *
+ForkAndExec(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    PRProcess *process;
+    int nEnv, idx;
+    char *const *childEnvp;
+    char **newEnvp = NULL;
+    int flags;
+
+    process = PR_NEW(PRProcess);
+    if (!process) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+
+    childEnvp = envp;
+    if (attr && attr->fdInheritBuffer) {
+        PRBool found = PR_FALSE;
+
+        if (NULL == childEnvp) {
+#ifdef DARWIN
+#ifdef HAVE_CRT_EXTERNS_H
+            childEnvp = *(_NSGetEnviron());
+#else
+            /* _NSGetEnviron() is not available on iOS. */
+            PR_DELETE(process);
+            PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+            return NULL;
+#endif
+#else
+            childEnvp = environ;
+#endif
+        }
+
+        for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
+        }
+        newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *));
+        if (NULL == newEnvp) {
+            PR_DELETE(process);
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return NULL;
+        }
+        for (idx = 0; idx < nEnv; idx++) {
+            newEnvp[idx] = childEnvp[idx];
+            if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
+                newEnvp[idx] = attr->fdInheritBuffer;
+                found = PR_TRUE;
+            }
+        }
+        if (!found) {
+            newEnvp[idx++] = attr->fdInheritBuffer;
+        }
+        newEnvp[idx] = NULL;
+        childEnvp = newEnvp;
+    }
+
+#ifdef AIX
+    process->md.pid = (*pr_wp.forkptr)();
+#elif defined(NTO) || defined(SYMBIAN)
+    /*
+     * fork() & exec() does not work in a multithreaded process.
+     * Use spawn() instead.
+     */
+    {
+        int fd_map[3] = { 0, 1, 2 };
+
+        if (attr) {
+            if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) {
+                fd_map[0] = dup(attr->stdinFd->secret->md.osfd);
+                flags = fcntl(fd_map[0], F_GETFL, 0);
+                if (flags & O_NONBLOCK)
+                    fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK);
+            }
+            if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) {
+                fd_map[1] = dup(attr->stdoutFd->secret->md.osfd);
+                flags = fcntl(fd_map[1], F_GETFL, 0);
+                if (flags & O_NONBLOCK)
+                    fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK);
+            }
+            if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) {
+                fd_map[2] = dup(attr->stderrFd->secret->md.osfd);
+                flags = fcntl(fd_map[2], F_GETFL, 0);
+                if (flags & O_NONBLOCK)
+                    fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK);
+            }
+
+            PR_ASSERT(attr->currentDirectory == NULL);  /* not implemented */
+        }
+
+#ifdef SYMBIAN
+        /* In Symbian OS, we use posix_spawn instead of fork() and exec() */
+        posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp);
+#else
+        process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp);
+#endif
+
+        if (fd_map[0] != 0)
+            close(fd_map[0]);
+        if (fd_map[1] != 1)
+            close(fd_map[1]);
+        if (fd_map[2] != 2)
+            close(fd_map[2]);
+    }
+#else
+    process->md.pid = fork();
+#endif
+    if ((pid_t) -1 == process->md.pid) {
+        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
+        PR_DELETE(process);
+        if (newEnvp) {
+            PR_DELETE(newEnvp);
+        }
+        return NULL;
+    } else if (0 == process->md.pid) {  /* the child process */
+        /*
+         * If the child process needs to exit, it must call _exit().
+         * Do not call exit(), because exit() will flush and close
+         * the standard I/O file descriptors, and hence corrupt
+         * the parent process's standard I/O data structures.
+         */
+
+#if !defined(NTO) && !defined(SYMBIAN)
+        if (attr) {
+            /* the osfd's to redirect stdin, stdout, and stderr to */
+            int in_osfd = -1, out_osfd = -1, err_osfd = -1;
+
+            if (attr->stdinFd
+                    && attr->stdinFd->secret->md.osfd != 0) {
+                in_osfd = attr->stdinFd->secret->md.osfd;
+                if (dup2(in_osfd, 0) != 0) {
+                    _exit(1);  /* failed */
+                }
+                flags = fcntl(0, F_GETFL, 0);
+                if (flags & O_NONBLOCK) {
+                    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
+                }
+            }
+            if (attr->stdoutFd
+                    && attr->stdoutFd->secret->md.osfd != 1) {
+                out_osfd = attr->stdoutFd->secret->md.osfd;
+                if (dup2(out_osfd, 1) != 1) {
+                    _exit(1);  /* failed */
+                }
+                flags = fcntl(1, F_GETFL, 0);
+                if (flags & O_NONBLOCK) {
+                    fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
+                }
+            }
+            if (attr->stderrFd
+                    && attr->stderrFd->secret->md.osfd != 2) {
+                err_osfd = attr->stderrFd->secret->md.osfd;
+                if (dup2(err_osfd, 2) != 2) {
+                    _exit(1);  /* failed */
+                }
+                flags = fcntl(2, F_GETFL, 0);
+                if (flags & O_NONBLOCK) {
+                    fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
+                }
+            }
+            if (in_osfd != -1) {
+                close(in_osfd);
+            }
+            if (out_osfd != -1 && out_osfd != in_osfd) {
+                close(out_osfd);
+            }
+            if (err_osfd != -1 && err_osfd != in_osfd
+                    && err_osfd != out_osfd) {
+                close(err_osfd);
+            }
+            if (attr->currentDirectory) {
+                if (chdir(attr->currentDirectory) < 0) {
+                    _exit(1);  /* failed */
+                }
+            }
+        }
+
+        if (childEnvp) {
+            (void)execve(path, argv, childEnvp);
+        } else {
+            /* Inherit the environment of the parent. */
+            (void)execv(path, argv);
+        }
+        /* Whoops! It returned. That's a bad sign. */
+        _exit(1);
+#endif /* !NTO */
+    }
+
+    if (newEnvp) {
+        PR_DELETE(newEnvp);
+    }
+
+#if defined(_PR_NATIVE_THREADS)
+    PR_Lock(pr_wp.ml);
+    if (0 == pr_wp.numProcs++) {
+        PR_NotifyCondVar(pr_wp.cv);
+    }
+    PR_Unlock(pr_wp.ml);
+#endif
+    return process;
+}
+
+#ifdef _PR_SHARE_CLONES
+
+struct pr_CreateProcOp {
+    const char *path;
+    char *const *argv;
+    char *const *envp;
+    const PRProcessAttr *attr;
+    PRProcess *process;
+    PRErrorCode prerror;
+    PRInt32 oserror;
+    PRBool done;
+    PRCondVar *doneCV;
+    struct pr_CreateProcOp *next;
+};
+
+PRProcess *
+_MD_CreateUnixProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    struct pr_CreateProcOp *op;
+    PRProcess *proc;
+    int rv;
+
+    if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
+	return NULL;
+    }
+
+    op = PR_NEW(struct pr_CreateProcOp);
+    if (NULL == op) {
+	PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	return NULL;
+    }
+    op->path = path;
+    op->argv = argv;
+    op->envp = envp;
+    op->attr = attr;
+    op->done = PR_FALSE;
+    op->doneCV = PR_NewCondVar(pr_wp.ml);
+    if (NULL == op->doneCV) {
+	PR_DELETE(op);
+	return NULL;
+    }
+    PR_Lock(pr_wp.ml);
+
+    /* add to the tail of op queue */
+    op->next = NULL;
+    if (pr_wp.opTail) {
+	pr_wp.opTail->next = op;
+	pr_wp.opTail = op;
+    } else {
+	PR_ASSERT(NULL == pr_wp.opHead);
+	pr_wp.opHead = pr_wp.opTail = op;
+    }
+
+    /* wake up the daemon thread */
+    do {
+        rv = write(pr_wp.pipefd[1], "", 1);
+    } while (-1 == rv && EINTR == errno);
+
+    while (op->done == PR_FALSE) {
+	PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT);
+    }
+    PR_Unlock(pr_wp.ml);
+    PR_DestroyCondVar(op->doneCV);
+    proc = op->process;
+    if (!proc) {
+	PR_SetError(op->prerror, op->oserror);
+    }
+    PR_DELETE(op);
+    return proc;
+}
+
+#else  /* ! _PR_SHARE_CLONES */
+
+PRProcess *
+_MD_CreateUnixProcess(
+    const char *path,
+    char *const *argv,
+    char *const *envp,
+    const PRProcessAttr *attr)
+{
+    if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) {
+	return NULL;
+    }
+    return ForkAndExec(path, argv, envp, attr);
+}  /* _MD_CreateUnixProcess */
+
+#endif  /* _PR_SHARE_CLONES */
+
+/*
+ * The pid table is a hashtable.
+ *
+ * The number of buckets in the hashtable (NBUCKETS) must be a power of 2.
+ */
+#define NBUCKETS_LOG2 6
+#define NBUCKETS (1 << NBUCKETS_LOG2)
+#define PID_HASH_MASK ((pid_t) (NBUCKETS - 1))
+
+static pr_PidRecord *
+FindPidTable(pid_t pid)
+{
+    pr_PidRecord *pRec;
+    int keyHash = (int) (pid & PID_HASH_MASK);
+
+    pRec =  pr_wp.pidTable[keyHash];
+    while (pRec) {
+	if (pRec->pid == pid) {
+	    break;
+	}
+	pRec = pRec->next;
+    }
+    return pRec;
+}
+
+static void
+InsertPidTable(pr_PidRecord *pRec)
+{
+    int keyHash = (int) (pRec->pid & PID_HASH_MASK);
+
+    pRec->next = pr_wp.pidTable[keyHash];
+    pr_wp.pidTable[keyHash] = pRec;
+}
+
+static void
+DeletePidTable(pr_PidRecord *pRec)
+{
+    int keyHash = (int) (pRec->pid & PID_HASH_MASK);
+
+    if (pr_wp.pidTable[keyHash] == pRec) {
+	pr_wp.pidTable[keyHash] = pRec->next;
+    } else {
+	pr_PidRecord *pred, *cur;  /* predecessor and current */
+
+	pred = pr_wp.pidTable[keyHash];
+	cur = pred->next;
+	while (cur) {
+	    if (cur == pRec) {
+		pred->next = cur->next;
+		break;
+            }
+	    pred = cur;
+	    cur = cur->next;
+        }
+	PR_ASSERT(cur != NULL);
+    }
+}
+
+static int
+ExtractExitStatus(int rawExitStatus)
+{
+    /*
+     * We did not specify the WCONTINUED and WUNTRACED options
+     * for waitpid, so these two events should not be reported.
+     */
+    PR_ASSERT(!WIFSTOPPED(rawExitStatus));
+#ifdef WIFCONTINUED
+    PR_ASSERT(!WIFCONTINUED(rawExitStatus));
+#endif
+    if (WIFEXITED(rawExitStatus)) {
+	return WEXITSTATUS(rawExitStatus);
+    } else {
+	PR_ASSERT(WIFSIGNALED(rawExitStatus));
+	return _PR_SIGNALED_EXITSTATUS;
+    }
+}
+
+static void
+ProcessReapedChildInternal(pid_t pid, int status)
+{
+    pr_PidRecord *pRec;
+
+    pRec = FindPidTable(pid);
+    if (NULL == pRec) {
+        pRec = PR_NEW(pr_PidRecord);
+        pRec->pid = pid;
+        pRec->state = _PR_PID_REAPED;
+        pRec->exitStatus = ExtractExitStatus(status);
+        pRec->reapedCV = NULL;
+        InsertPidTable(pRec);
+    } else {
+        PR_ASSERT(pRec->state != _PR_PID_REAPED);
+        if (_PR_PID_DETACHED == pRec->state) {
+            PR_ASSERT(NULL == pRec->reapedCV);
+            DeletePidTable(pRec);
+            PR_DELETE(pRec);
+        } else {
+            PR_ASSERT(_PR_PID_WAITING == pRec->state);
+            PR_ASSERT(NULL != pRec->reapedCV);
+            pRec->exitStatus = ExtractExitStatus(status);
+            pRec->state = _PR_PID_REAPED;
+            PR_NotifyCondVar(pRec->reapedCV);
+        }
+    }
+}
+
+#if defined(_PR_NATIVE_THREADS)
+
+/*
+ * If all the threads are native threads, the daemon thread is
+ * simpler.  We don't need to catch the SIGCHLD signal.  We can
+ * just have the daemon thread block in waitpid().
+ */
+
+static void WaitPidDaemonThread(void *unused)
+{
+    pid_t pid;
+    int status;
+
+    while (1) {
+        PR_Lock(pr_wp.ml);
+        while (0 == pr_wp.numProcs) {
+            PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
+        }
+        PR_Unlock(pr_wp.ml);
+
+	while (1) {
+	    do {
+	        pid = waitpid((pid_t) -1, &status, 0);
+	    } while ((pid_t) -1 == pid && EINTR == errno);
+
+            /*
+             * waitpid() cannot return 0 because we did not invoke it
+             * with the WNOHANG option.
+             */ 
+	    PR_ASSERT(0 != pid);
+
+            /*
+             * The only possible error code is ECHILD.  But if we do
+             * our accounting correctly, we should only call waitpid()
+             * when there is a child process to wait for.
+             */
+            PR_ASSERT((pid_t) -1 != pid);
+	    if ((pid_t) -1 == pid) {
+                break;
+            }
+
+	    PR_Lock(pr_wp.ml);
+            ProcessReapedChildInternal(pid, status);
+            pr_wp.numProcs--;
+            while (0 == pr_wp.numProcs) {
+                PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT);
+            }
+	    PR_Unlock(pr_wp.ml);
+	}
+    }
+}
+
+#else /* _PR_NATIVE_THREADS */
+
+static void WaitPidDaemonThread(void *unused)
+{
+    PRPollDesc pd;
+    PRFileDesc *fd;
+    int rv;
+    char buf[128];
+    pid_t pid;
+    int status;
+#ifdef _PR_SHARE_CLONES
+    struct pr_CreateProcOp *op;
+#endif
+
+#ifdef _PR_SHARE_CLONES
+    pr_InstallSigchldHandler();
+#endif
+
+    fd = PR_ImportFile(pr_wp.pipefd[0]);
+    PR_ASSERT(NULL != fd);
+    pd.fd = fd;
+    pd.in_flags = PR_POLL_READ;
+
+    while (1) {
+        rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+        PR_ASSERT(1 == rv);
+
+#ifdef _PR_SHARE_CLONES
+        if (pr_waitpid_daemon_exit) {
+            return;
+        }
+	PR_Lock(pr_wp.ml);
+#endif
+	    
+        do {
+            rv = read(pr_wp.pipefd[0], buf, sizeof(buf));
+        } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno));
+
+#ifdef _PR_SHARE_CLONES
+	PR_Unlock(pr_wp.ml);
+	while ((op = pr_wp.opHead) != NULL) {
+	    op->process = ForkAndExec(op->path, op->argv,
+		    op->envp, op->attr);
+	    if (NULL == op->process) {
+		op->prerror = PR_GetError();
+		op->oserror = PR_GetOSError();
+	    }
+	    PR_Lock(pr_wp.ml);
+	    pr_wp.opHead = op->next;
+	    if (NULL == pr_wp.opHead) {
+		pr_wp.opTail = NULL;
+	    }
+	    op->done = PR_TRUE;
+	    PR_NotifyCondVar(op->doneCV);
+	    PR_Unlock(pr_wp.ml);
+	}
+#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);
+	}
+    }
+}
+
+static void pr_SigchldHandler(int sig)
+{
+    int errnoCopy;
+    int rv;
+
+    errnoCopy = errno;
+
+    do {
+        rv = write(pr_wp.pipefd[1], "", 1);
+    } while (-1 == rv && EINTR == errno);
+
+#ifdef DEBUG
+    if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) {
+        char *msg = "cannot write to pipe\n";
+        write(2, msg, strlen(msg) + 1);
+        _exit(1);
+    }
+#endif
+
+    errno = errnoCopy;
+}
+
+static void pr_InstallSigchldHandler()
+{
+#if defined(HPUX) && defined(_PR_DCETHREADS)
+#error "HP-UX DCE threads have their own SIGCHLD handler"
+#endif
+
+    struct sigaction act, oact;
+    int rv;
+
+    act.sa_handler = pr_SigchldHandler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+    rv = sigaction(SIGCHLD, &act, &oact);
+    PR_ASSERT(0 == rv);
+    /* Make sure we are not overriding someone else's SIGCHLD handler */
+#ifndef _PR_SHARE_CLONES
+    PR_ASSERT(oact.sa_handler == SIG_DFL);
+#endif
+}
+
+#endif  /* !defined(_PR_NATIVE_THREADS) */
+
+static PRStatus _MD_InitProcesses(void)
+{
+#if !defined(_PR_NATIVE_THREADS)
+    int rv;
+    int flags;
+#endif
+
+#ifdef AIX
+    {
+        void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
+        pr_wp.forkptr = (pid_t (*)(void)) dlsym(handle, "f_fork");
+        if (!pr_wp.forkptr) {
+            pr_wp.forkptr = fork;
+        }
+        dlclose(handle);
+    }
+#endif /* AIX */
+
+    pr_wp.ml = PR_NewLock();
+    PR_ASSERT(NULL != pr_wp.ml);
+
+#if defined(_PR_NATIVE_THREADS)
+    pr_wp.numProcs = 0;
+    pr_wp.cv = PR_NewCondVar(pr_wp.ml);
+    PR_ASSERT(NULL != pr_wp.cv);
+#else
+    rv = pipe(pr_wp.pipefd);
+    PR_ASSERT(0 == rv);
+    flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0);
+    fcntl(pr_wp.pipefd[0], F_SETFL, flags | O_NONBLOCK);
+    flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0);
+    fcntl(pr_wp.pipefd[1], F_SETFL, flags | O_NONBLOCK);
+
+#ifndef _PR_SHARE_CLONES
+    pr_InstallSigchldHandler();
+#endif
+#endif  /* !_PR_NATIVE_THREADS */
+
+    pr_wp.thread = PR_CreateThread(PR_SYSTEM_THREAD,
+	    WaitPidDaemonThread, NULL, PR_PRIORITY_NORMAL,
+#ifdef _PR_SHARE_CLONES
+            PR_GLOBAL_THREAD,
+#else
+	    PR_LOCAL_THREAD,
+#endif
+	    PR_JOINABLE_THREAD, 0);
+    PR_ASSERT(NULL != pr_wp.thread);
+
+    pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *));
+    PR_ASSERT(NULL != pr_wp.pidTable);
+    return PR_SUCCESS;
+}
+
+PRStatus _MD_DetachUnixProcess(PRProcess *process)
+{
+    PRStatus retVal = PR_SUCCESS;
+    pr_PidRecord *pRec;
+
+    PR_Lock(pr_wp.ml);
+    pRec = FindPidTable(process->md.pid);
+    if (NULL == pRec) {
+	pRec = PR_NEW(pr_PidRecord);
+	if (NULL == pRec) {
+	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	    retVal = PR_FAILURE;
+	    goto done;
+	}
+	pRec->pid = process->md.pid;
+	pRec->state = _PR_PID_DETACHED;
+	pRec->reapedCV = NULL;
+	InsertPidTable(pRec);
+    } else {
+	PR_ASSERT(_PR_PID_REAPED == pRec->state);
+	if (_PR_PID_REAPED != pRec->state) {
+	    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+	    retVal = PR_FAILURE;
+	} else {
+	    DeletePidTable(pRec);
+	    PR_ASSERT(NULL == pRec->reapedCV);
+	    PR_DELETE(pRec);
+	}
+    }
+    PR_DELETE(process);
+
+done:
+    PR_Unlock(pr_wp.ml);
+    return retVal;
+}
+
+PRStatus _MD_WaitUnixProcess(
+    PRProcess *process,
+    PRInt32 *exitCode)
+{
+    pr_PidRecord *pRec;
+    PRStatus retVal = PR_SUCCESS;
+    PRBool interrupted = PR_FALSE;
+
+    PR_Lock(pr_wp.ml);
+    pRec = FindPidTable(process->md.pid);
+    if (NULL == pRec) {
+	pRec = PR_NEW(pr_PidRecord);
+	if (NULL == pRec) {
+	    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+	    retVal = PR_FAILURE;
+	    goto done;
+	}
+	pRec->pid = process->md.pid;
+	pRec->state = _PR_PID_WAITING;
+	pRec->reapedCV = PR_NewCondVar(pr_wp.ml);
+	if (NULL == pRec->reapedCV) {
+	    PR_DELETE(pRec);
+	    retVal = PR_FAILURE;
+	    goto done;
+	}
+	InsertPidTable(pRec);
+	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;
+            }
+	}
+	if (_PR_PID_REAPED == pRec->state) {
+            if (exitCode) {
+                *exitCode = pRec->exitStatus;
+            }
+	} else {
+	    PR_ASSERT(interrupted);
+	    retVal = PR_FAILURE;
+	}
+	DeletePidTable(pRec);
+	PR_DestroyCondVar(pRec->reapedCV);
+	PR_DELETE(pRec);
+    } else {
+	PR_ASSERT(_PR_PID_REAPED == pRec->state);
+	PR_ASSERT(NULL == pRec->reapedCV);
+	DeletePidTable(pRec);
+        if (exitCode) {
+            *exitCode = pRec->exitStatus;
+        }
+	PR_DELETE(pRec);
+    }
+    PR_DELETE(process);
+
+done:
+    PR_Unlock(pr_wp.ml);
+    return retVal;
+}  /* _MD_WaitUnixProcess */
+
+PRStatus _MD_KillUnixProcess(PRProcess *process)
+{
+    PRErrorCode prerror;
+    PRInt32 oserror;
+
+#ifdef SYMBIAN
+    /* In Symbian OS, we can not kill other process with Open C */
+    PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, oserror);
+    return PR_FAILURE;
+#else
+    if (kill(process->md.pid, SIGKILL) == 0) {
+	return PR_SUCCESS;
+    }
+    oserror = errno;
+    switch (oserror) {
+        case EPERM:
+	    prerror = PR_NO_ACCESS_RIGHTS_ERROR;
+	    break;
+        case ESRCH:
+	    prerror = PR_INVALID_ARGUMENT_ERROR;
+	    break;
+        default:
+	    prerror = PR_UNKNOWN_ERROR;
+	    break;
+    }
+    PR_SetError(prerror, oserror);
+    return PR_FAILURE;
+#endif
+}  /* _MD_KillUnixProcess */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)