uxproces.c revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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
*
* 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 the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#if defined(AIX)
#include <dlfcn.h> /* For dlopen, dlsym, dlclose */
#endif
#if defined(DARWIN)
#include <crt_externs.h>
#else
extern char **environ;
#endif
/*
* HP-UX 9 doesn't have the SA_RESTART flag.
*/
#ifndef SA_RESTART
#define SA_RESTART 0
#endif
#if defined(VMS)
#endif
/*
**********************************************************************
*
* The Unix process routines
*
**********************************************************************
*/
#define _PR_SIGNALED_EXITSTATUS 256
typedef enum pr_PidState {
} pr_PidState;
typedef struct pr_PidRecord {
int exitStatus;
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 {
#if defined(_PR_NATIVE_THREADS)
#else
int pipefd[2];
#endif
#ifdef _PR_SHARE_CLONES
#endif
#ifdef AIX
* 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
{
}
}
#endif
static PRStatus _MD_InitProcesses(void);
#if !defined(_PR_NATIVE_THREADS)
static void pr_InstallSigchldHandler(void);
#endif
static PRProcess *
const char *path,
char *const *argv,
char *const *envp,
const PRProcessAttr *attr)
{
char *const *childEnvp;
int flags;
#ifdef VMS
#endif
if (!process) {
return NULL;
}
#ifdef DARWIN
childEnvp = *(_NSGetEnviron());
#else
#endif
}
}
return NULL;
}
}
}
#ifdef VMS
/*
** 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);
/* Set up any standard streams we are given, assuming defaults */
if (attr) {
}
/*
** Put a lock around anything that isn't going to be thread-safe.
*/
/*
** Prepare the child's streams. We always do this in case a previous fork
** has left the stream assignments in some non-standard way.
*/
if (n == -1) {
if (newEnvp) {
}
return NULL;
}
/* Switch directory if we have to */
if (attr) {
if (attr->currentDirectory) {
if (newEnvp) {
}
return NULL;
}
}
}
}
#endif /* VMS */
#ifdef AIX
/*
* fork() & exec() does not work in a multithreaded process.
* Use spawn() instead.
*/
{
if (attr) {
if (flags & O_NONBLOCK)
}
if (flags & O_NONBLOCK)
}
if (flags & O_NONBLOCK)
}
}
if (fd_map[0] != 0)
}
#else
#endif
if (newEnvp) {
}
return NULL;
/*
* 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 */
}
if (flags & O_NONBLOCK) {
}
}
}
if (flags & O_NONBLOCK) {
}
}
}
if (flags & O_NONBLOCK) {
}
}
if (in_osfd != -1) {
}
}
}
if (attr->currentDirectory) {
}
}
}
#endif /* !VMS */
if (childEnvp) {
} else {
/* Inherit the environment of the parent. */
}
/* 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.
*/
if (newEnvp) {
}
if (VMScurdir[0] != '\0')
return NULL;
#else
_exit(1);
#endif /* VMS */
#endif /* !NTO */
}
if (newEnvp) {
}
#ifdef VMS
/* If we switched directories, then remember to switch back */
if (VMScurdir[0] != '\0') {
}
#endif /* VMS */
#if defined(_PR_NATIVE_THREADS)
}
#endif
return process;
}
#ifdef _PR_SHARE_CLONES
struct pr_CreateProcOp {
const char *path;
char *const *argv;
char *const *envp;
const PRProcessAttr *attr;
struct pr_CreateProcOp *next;
};
const char *path,
char *const *argv,
char *const *envp,
const PRProcessAttr *attr)
{
struct pr_CreateProcOp *op;
int rv;
return NULL;
}
return NULL;
}
return NULL;
}
/* add to the tail of op queue */
} else {
}
/* wake up the daemon thread */
do {
}
if (!proc) {
}
return proc;
}
#else /* ! _PR_SHARE_CLONES */
const char *path,
char *const *argv,
char *const *envp,
const PRProcessAttr *attr)
{
return NULL;
}
} /* _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
static pr_PidRecord *
{
while (pRec) {
break;
}
}
return pRec;
}
static void
{
}
static void
{
} else {
while (cur) {
break;
}
}
}
}
static int
{
/*
* We did not specify the WCONTINUED and WUNTRACED options
* for waitpid, so these two events should not be reported.
*/
#ifdef WIFCONTINUED
#endif
if (WIFEXITED(rawExitStatus)) {
return WEXITSTATUS(rawExitStatus);
} else {
return _PR_SIGNALED_EXITSTATUS;
}
}
static void
{
} else {
} else {
}
}
}
#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)
{
int status;
while (1) {
}
while (1) {
do {
/*
* waitpid() cannot return 0 because we did not invoke it
* with the WNOHANG option.
*/
/*
* 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.
*/
break;
}
}
}
}
}
#else /* _PR_NATIVE_THREADS */
static void WaitPidDaemonThread(void *unused)
{
PRFileDesc *fd;
int rv;
char buf[128];
int status;
#ifdef _PR_SHARE_CLONES
struct pr_CreateProcOp *op;
#endif
#ifdef _PR_SHARE_CLONES
#endif
while (1) {
#ifdef _PR_SHARE_CLONES
if (pr_waitpid_daemon_exit) {
return;
}
#endif
do {
#ifdef _PR_SHARE_CLONES
}
}
}
#endif
while (1) {
do {
if (0 == pid) break;
/* must be because we have no child processes */
break;
}
}
}
}
static void pr_SigchldHandler(int sig)
{
int errnoCopy;
int rv;
do {
#ifdef DEBUG
char *msg = "cannot write to pipe\n";
_exit(1);
}
#endif
}
static void pr_InstallSigchldHandler()
{
#if defined(HPUX) && defined(_PR_DCETHREADS)
#error "HP-UX DCE threads have their own SIGCHLD handler"
#endif
int rv;
/* Make sure we are not overriding someone else's SIGCHLD handler */
#ifndef _PR_SHARE_CLONES
#endif
}
#endif /* !defined(_PR_NATIVE_THREADS) */
static PRStatus _MD_InitProcesses(void)
{
#if !defined(_PR_NATIVE_THREADS)
int rv;
int flags;
#endif
#ifdef SUNOS4
#define _PR_NBIO_FLAG FNDELAY
#else
#define _PR_NBIO_FLAG O_NONBLOCK
#endif
#ifdef AIX
{
}
}
#endif /* AIX */
#if defined(VMS)
#endif
#if defined(_PR_NATIVE_THREADS)
#else
#ifndef _PR_SHARE_CLONES
#endif
#endif /* !_PR_NATIVE_THREADS */
#ifdef _PR_SHARE_CLONES
#else
#endif
PR_JOINABLE_THREAD, 0);
return PR_SUCCESS;
}
{
retVal = PR_FAILURE;
goto done;
}
} else {
retVal = PR_FAILURE;
} else {
}
}
done:
return retVal;
}
{
retVal = PR_FAILURE;
goto done;
}
retVal = PR_FAILURE;
goto done;
}
&& PR_GetError() == PR_PENDING_INTERRUPT_ERROR) {
}
}
if (exitCode) {
}
} else {
retVal = PR_FAILURE;
}
} else {
if (exitCode) {
}
}
done:
return retVal;
} /* _MD_WaitUnixProcess */
{
return PR_SUCCESS;
}
switch (oserror) {
case EPERM:
break;
case ESRCH:
break;
default:
break;
}
return PR_FAILURE;
} /* _MD_KillUnixProcess */