⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uxproces.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//*  * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape Portable Runtime (NSPR). *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1998-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "primpl.h"#include <sys/types.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>#include <sys/wait.h>#if defined(AIX)#include <dlfcn.h>  /* For dlopen, dlsym, dlclose */#endif#if defined(DARWIN)#include <crt_externs.h>#elseextern char **environ;#endif/* * HP-UX 9 doesn't have the SA_RESTART flag. */#ifndef SA_RESTART#define SA_RESTART 0#endif#if defined(VMS)static PRLock *_pr_vms_fork_lock = NULL;#endif/* ********************************************************************** * * The Unix process routines * ********************************************************************** */#define _PR_SIGNALED_EXITSTATUS 256typedef 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(_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))#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_CLONESstatic 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);    }}#endifstatic PRStatus _MD_InitProcesses(void);#if !defined(_PR_NATIVE_THREADS)static void pr_InstallSigchldHandler(void);#endifstatic 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;#ifdef VMS    char VMScurdir[FILENAME_MAX+1] = { '\0' } ;#endif	    process = PR_NEW(PRProcess);    if (!process) {        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);        return NULL;    }    childEnvp = envp;    if (attr && attr->fdInheritBuffer) {        if (NULL == childEnvp) {#ifdef DARWIN            childEnvp = *(_NSGetEnviron());#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];        }        newEnvp[idx++] = attr->fdInheritBuffer;        newEnvp[idx] = NULL;        childEnvp = newEnvp;    }#ifdef VMS/*** Since vfork/exec is implemented VERY differently on OpenVMS, we have to** handle the setting up of the standard streams very differently. And since** none of this code can ever execute in the context of the child, we have** to perform the chdir in the parent so the child is born into the correct** directory (and then switch the parent back again).*/{    int decc$set_child_standard_streams(int,int,int);    int n, fd_stdin=0, fd_stdout=1, fd_stderr=2;    /* Set up any standard streams we are given, assuming defaults */    if (attr) {       if (attr->stdinFd)           fd_stdin = attr->stdinFd->secret->md.osfd;       if (attr->stdoutFd)           fd_stdout = attr->stdoutFd->secret->md.osfd;       if (attr->stderrFd)           fd_stderr = attr->stderrFd->secret->md.osfd;    }    /*    ** Put a lock around anything that isn't going to be thread-safe.    */    PR_Lock(_pr_vms_fork_lock);    /*    ** Prepare the child's streams. We always do this in case a previous fork    ** has left the stream assignments in some non-standard way.    */    n = decc$set_child_standard_streams(fd_stdin,fd_stdout,fd_stderr);    if (n == -1) {       PR_SetError(PR_BAD_DESCRIPTOR_ERROR, errno);       PR_DELETE(process);       if (newEnvp) {           PR_DELETE(newEnvp);       }       PR_Unlock(_pr_vms_fork_lock);       return NULL;    }    /* Switch directory if we have to */    if (attr) {       if (attr->currentDirectory) {           if ( (getcwd(VMScurdir,sizeof(VMScurdir)) == NULL) ||                (chdir(attr->currentDirectory) < 0) ) {               PR_SetError(PR_DIRECTORY_OPEN_ERROR, errno);               PR_DELETE(process);               if (newEnvp) {                   PR_DELETE(newEnvp);               }               PR_Unlock(_pr_vms_fork_lock);               return NULL;           }       }    }}#endif /* VMS */#ifdef AIX    process->md.pid = (*pr_wp.forkptr)();#elif defined(NTO)    /*     * 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 */        }        process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp);        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)#ifdef VMS       /* OpenVMS has already handled all this above */#else        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 */                }            }        }#endif /* !VMS */        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. */#ifdef VMS       /*       ** On OpenVMS we are still in the context of the parent, and so we       ** can (and should!) perform normal error handling.       */       PR_SetError(PR_UNKNOWN_ERROR, errno);       PR_DELETE(process);       if (newEnvp) {           PR_DELETE(newEnvp);       }       if (VMScurdir[0] != '\0')           chdir(VMScurdir);       PR_Unlock(_pr_vms_fork_lock);       return NULL;#else        _exit(1);#endif /* VMS */#endif /* !NTO */    }    if (newEnvp) {        PR_DELETE(newEnvp);    }#ifdef VMS    /* If we switched directories, then remember to switch back */    if (VMScurdir[0] != '\0') {       chdir(VMScurdir); /* can't do much if it fails */    }    PR_Unlock(_pr_vms_fork_lock);#endif /* VMS */#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_CLONESstruct 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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -