andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: #include "primpl.h" andre@0: #include andre@0: #include andre@0: andre@0: PRLogModuleInfo *_pr_clock_lm; andre@0: PRLogModuleInfo *_pr_cmon_lm; andre@0: PRLogModuleInfo *_pr_io_lm; andre@0: PRLogModuleInfo *_pr_cvar_lm; andre@0: PRLogModuleInfo *_pr_mon_lm; andre@0: PRLogModuleInfo *_pr_linker_lm; andre@0: PRLogModuleInfo *_pr_sched_lm; andre@0: PRLogModuleInfo *_pr_thread_lm; andre@0: PRLogModuleInfo *_pr_gc_lm; andre@0: PRLogModuleInfo *_pr_shm_lm; andre@0: PRLogModuleInfo *_pr_shma_lm; andre@0: andre@0: PRFileDesc *_pr_stdin; andre@0: PRFileDesc *_pr_stdout; andre@0: PRFileDesc *_pr_stderr; andre@0: andre@0: #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) andre@0: andre@0: PRCList _pr_active_local_threadQ = andre@0: PR_INIT_STATIC_CLIST(&_pr_active_local_threadQ); andre@0: PRCList _pr_active_global_threadQ = andre@0: PR_INIT_STATIC_CLIST(&_pr_active_global_threadQ); andre@0: andre@0: _MDLock _pr_cpuLock; /* lock for the CPU Q */ andre@0: PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ); andre@0: andre@0: PRUint32 _pr_utid; andre@0: andre@0: PRInt32 _pr_userActive; andre@0: PRInt32 _pr_systemActive; andre@0: PRUintn _pr_maxPTDs; andre@0: andre@0: #ifdef _PR_LOCAL_THREADS_ONLY andre@0: andre@0: struct _PRCPU *_pr_currentCPU; andre@0: PRThread *_pr_currentThread; andre@0: PRThread *_pr_lastThread; andre@0: PRInt32 _pr_intsOff; andre@0: andre@0: #endif /* _PR_LOCAL_THREADS_ONLY */ andre@0: andre@0: /* Lock protecting all "termination" condition variables of all threads */ andre@0: PRLock *_pr_terminationCVLock; andre@0: andre@0: #endif /* !defined(_PR_PTHREADS) */ andre@0: andre@0: PRLock *_pr_sleeplock; /* used in PR_Sleep(), classic and pthreads */ andre@0: andre@0: static void _PR_InitCallOnce(void); andre@0: andre@0: PRBool _pr_initialized = PR_FALSE; andre@0: andre@0: andre@0: PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion) andre@0: { andre@0: /* andre@0: ** This is the secret handshake algorithm. andre@0: ** andre@0: ** This release has a simple version compatibility andre@0: ** check algorithm. This release is not backward andre@0: ** compatible with previous major releases. It is andre@0: ** not compatible with future major, minor, or andre@0: ** patch releases. andre@0: */ andre@0: int vmajor = 0, vminor = 0, vpatch = 0; andre@0: const char *ptr = importedVersion; andre@0: andre@0: while (isdigit(*ptr)) { andre@0: vmajor = 10 * vmajor + *ptr - '0'; andre@0: ptr++; andre@0: } andre@0: if (*ptr == '.') { andre@0: ptr++; andre@0: while (isdigit(*ptr)) { andre@0: vminor = 10 * vminor + *ptr - '0'; andre@0: ptr++; andre@0: } andre@0: if (*ptr == '.') { andre@0: ptr++; andre@0: while (isdigit(*ptr)) { andre@0: vpatch = 10 * vpatch + *ptr - '0'; andre@0: ptr++; andre@0: } andre@0: } andre@0: } andre@0: andre@0: if (vmajor != PR_VMAJOR) { andre@0: return PR_FALSE; andre@0: } andre@0: if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) { andre@0: return PR_FALSE; andre@0: } andre@0: if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) { andre@0: return PR_FALSE; andre@0: } andre@0: return PR_TRUE; andre@0: } /* PR_VersionCheck */ andre@0: andre@0: PR_IMPLEMENT(const char*) PR_GetVersion(void) andre@0: { andre@0: return PR_VERSION; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRBool) PR_Initialized(void) andre@0: { andre@0: return _pr_initialized; andre@0: } andre@0: andre@0: PRInt32 _native_threads_only = 0; andre@0: andre@0: #ifdef WINNT andre@0: static void _pr_SetNativeThreadsOnlyMode(void) andre@0: { andre@0: HMODULE mainExe; andre@0: PRBool *globalp; andre@0: char *envp; andre@0: andre@0: mainExe = GetModuleHandle(NULL); andre@0: PR_ASSERT(NULL != mainExe); andre@0: globalp = (PRBool *) GetProcAddress(mainExe, "nspr_native_threads_only"); andre@0: if (globalp) { andre@0: _native_threads_only = (*globalp != PR_FALSE); andre@0: } else if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) { andre@0: _native_threads_only = (atoi(envp) == 1); andre@0: } andre@0: } andre@0: #endif andre@0: andre@0: static void _PR_InitStuff(void) andre@0: { andre@0: andre@0: if (_pr_initialized) return; andre@0: _pr_initialized = PR_TRUE; andre@0: #ifdef _PR_ZONE_ALLOCATOR andre@0: _PR_InitZones(); andre@0: #endif andre@0: #ifdef WINNT andre@0: _pr_SetNativeThreadsOnlyMode(); andre@0: #endif andre@0: andre@0: andre@0: (void) PR_GetPageSize(); andre@0: andre@0: _pr_clock_lm = PR_NewLogModule("clock"); andre@0: _pr_cmon_lm = PR_NewLogModule("cmon"); andre@0: _pr_io_lm = PR_NewLogModule("io"); andre@0: _pr_mon_lm = PR_NewLogModule("mon"); andre@0: _pr_linker_lm = PR_NewLogModule("linker"); andre@0: _pr_cvar_lm = PR_NewLogModule("cvar"); andre@0: _pr_sched_lm = PR_NewLogModule("sched"); andre@0: _pr_thread_lm = PR_NewLogModule("thread"); andre@0: _pr_gc_lm = PR_NewLogModule("gc"); andre@0: _pr_shm_lm = PR_NewLogModule("shm"); andre@0: _pr_shma_lm = PR_NewLogModule("shma"); andre@0: andre@0: /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ andre@0: _PR_MD_EARLY_INIT(); andre@0: andre@0: _PR_InitLocks(); andre@0: _PR_InitAtomic(); andre@0: _PR_InitSegs(); andre@0: _PR_InitStacks(); andre@0: _PR_InitTPD(); andre@0: _PR_InitEnv(); andre@0: _PR_InitLayerCache(); andre@0: _PR_InitClock(); andre@0: andre@0: _pr_sleeplock = PR_NewLock(); andre@0: PR_ASSERT(NULL != _pr_sleeplock); andre@0: andre@0: _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); andre@0: andre@0: #ifdef WIN16 andre@0: { andre@0: PRInt32 top; /* artificial top of stack, win16 */ andre@0: _pr_top_of_task_stack = (char *) ⊤ andre@0: } andre@0: #endif andre@0: andre@0: #ifndef _PR_GLOBAL_THREADS_ONLY andre@0: _PR_InitCPUs(); andre@0: #endif andre@0: andre@0: /* andre@0: * XXX: call _PR_InitMem only on those platforms for which nspr implements andre@0: * malloc, for now. andre@0: */ andre@0: #ifdef _PR_OVERRIDE_MALLOC andre@0: _PR_InitMem(); andre@0: #endif andre@0: andre@0: _PR_InitCMon(); andre@0: _PR_InitIO(); andre@0: _PR_InitNet(); andre@0: _PR_InitTime(); andre@0: _PR_InitLog(); andre@0: _PR_InitLinker(); andre@0: _PR_InitCallOnce(); andre@0: _PR_InitDtoa(); andre@0: _PR_InitMW(); andre@0: _PR_InitRWLocks(); andre@0: andre@0: nspr_InitializePRErrorTable(); andre@0: andre@0: _PR_MD_FINAL_INIT(); andre@0: } andre@0: andre@0: void _PR_ImplicitInitialization(void) andre@0: { andre@0: _PR_InitStuff(); andre@0: andre@0: /* Enable interrupts */ andre@0: #if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY) andre@0: _PR_MD_START_INTERRUPTS(); andre@0: #endif andre@0: andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_DisableClockInterrupts(void) andre@0: { andre@0: #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) andre@0: if (!_pr_initialized) { andre@0: _PR_InitStuff(); andre@0: } else { andre@0: _PR_MD_DISABLE_CLOCK_INTERRUPTS(); andre@0: } andre@0: #endif andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_EnableClockInterrupts(void) andre@0: { andre@0: #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) andre@0: if (!_pr_initialized) { andre@0: _PR_InitStuff(); andre@0: } andre@0: _PR_MD_ENABLE_CLOCK_INTERRUPTS(); andre@0: #endif andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) andre@0: { andre@0: #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) andre@0: _PR_MD_BLOCK_CLOCK_INTERRUPTS(); andre@0: #endif andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void) andre@0: { andre@0: #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) andre@0: _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(); andre@0: #endif andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_Init( andre@0: PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) andre@0: { andre@0: _PR_ImplicitInitialization(); andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRIntn) PR_Initialize( andre@0: PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs) andre@0: { andre@0: PRIntn rv; andre@0: _PR_ImplicitInitialization(); andre@0: rv = prmain(argc, argv); andre@0: PR_Cleanup(); andre@0: return rv; andre@0: } /* PR_Initialize */ andre@0: andre@0: /* andre@0: *----------------------------------------------------------------------- andre@0: * andre@0: * _PR_CleanupBeforeExit -- andre@0: * andre@0: * Perform the cleanup work before exiting the process. andre@0: * We first do the cleanup generic to all platforms. Then andre@0: * we call _PR_MD_CLEANUP_BEFORE_EXIT(), where platform-dependent andre@0: * cleanup is done. This function is used by PR_Cleanup(). andre@0: * andre@0: * See also: PR_Cleanup(). andre@0: * andre@0: *----------------------------------------------------------------------- andre@0: */ andre@0: #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) andre@0: /* see ptthread.c */ andre@0: #else andre@0: static void andre@0: _PR_CleanupBeforeExit(void) andre@0: { andre@0: /* andre@0: Do not make any calls here other than to destroy resources. For example, andre@0: do not make any calls that eventually may end up in PR_Lock. Because the andre@0: thread is destroyed, can not access current thread any more. andre@0: */ andre@0: _PR_CleanupTPD(); andre@0: if (_pr_terminationCVLock) andre@0: /* andre@0: * In light of the comment above, this looks real suspicious. andre@0: * I'd go so far as to say it's just a problem waiting to happen. andre@0: */ andre@0: PR_DestroyLock(_pr_terminationCVLock); andre@0: andre@0: _PR_MD_CLEANUP_BEFORE_EXIT(); andre@0: } andre@0: #endif /* defined(_PR_PTHREADS) */ andre@0: andre@0: /* andre@0: *---------------------------------------------------------------------- andre@0: * andre@0: * PR_Cleanup -- andre@0: * andre@0: * Perform a graceful shutdown of the NSPR runtime. PR_Cleanup() may andre@0: * only be called from the primordial thread, typically at the andre@0: * end of the main() function. It returns when it has completed andre@0: * its platform-dependent duty and the process must not make any other andre@0: * NSPR library calls prior to exiting from main(). andre@0: * andre@0: * PR_Cleanup() first blocks the primordial thread until all the andre@0: * other user (non-system) threads, if any, have terminated. andre@0: * Then it performs cleanup in preparation for exiting the process. andre@0: * PR_Cleanup() does not exit the primordial thread (which would andre@0: * in turn exit the process). andre@0: * andre@0: * PR_Cleanup() only responds when it is called by the primordial andre@0: * thread. Calls by any other thread are silently ignored. andre@0: * andre@0: * See also: PR_ExitProcess() andre@0: * andre@0: *---------------------------------------------------------------------- andre@0: */ andre@0: #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) andre@0: /* see ptthread.c */ andre@0: #else andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_Cleanup() andre@0: { andre@0: PRThread *me = PR_GetCurrentThread(); andre@0: PR_ASSERT((NULL != me) && (me->flags & _PR_PRIMORDIAL)); andre@0: if ((NULL != me) && (me->flags & _PR_PRIMORDIAL)) andre@0: { andre@0: PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); andre@0: andre@0: /* andre@0: * No more recycling of threads andre@0: */ andre@0: _pr_recycleThreads = 0; andre@0: andre@0: /* andre@0: * Wait for all other user (non-system/daemon) threads andre@0: * to terminate. andre@0: */ andre@0: PR_Lock(_pr_activeLock); andre@0: while (_pr_userActive > _pr_primordialExitCount) { andre@0: PR_WaitCondVar(_pr_primordialExitCVar, PR_INTERVAL_NO_TIMEOUT); andre@0: } andre@0: if (me->flags & _PR_SYSTEM) { andre@0: _pr_systemActive--; andre@0: } else { andre@0: _pr_userActive--; andre@0: } andre@0: PR_Unlock(_pr_activeLock); andre@0: andre@0: #ifdef IRIX andre@0: _PR_MD_PRE_CLEANUP(me); andre@0: /* andre@0: * The primordial thread must now be running on the primordial cpu andre@0: */ andre@0: PR_ASSERT((_PR_IS_NATIVE_THREAD(me)) || (me->cpu->id == 0)); andre@0: #endif andre@0: andre@0: _PR_MD_EARLY_CLEANUP(); andre@0: andre@0: _PR_CleanupMW(); andre@0: _PR_CleanupTime(); andre@0: _PR_CleanupDtoa(); andre@0: _PR_CleanupCallOnce(); andre@0: _PR_ShutdownLinker(); andre@0: _PR_CleanupNet(); andre@0: _PR_CleanupIO(); andre@0: /* Release the primordial thread's private data, etc. */ andre@0: _PR_CleanupThread(me); andre@0: andre@0: _PR_MD_STOP_INTERRUPTS(); andre@0: andre@0: PR_LOG(_pr_thread_lm, PR_LOG_MIN, andre@0: ("PR_Cleanup: clean up before destroying thread")); andre@0: _PR_LogCleanup(); andre@0: andre@0: /* andre@0: * This part should look like the end of _PR_NativeRunThread andre@0: * and _PR_UserRunThread. andre@0: */ andre@0: if (_PR_IS_NATIVE_THREAD(me)) { andre@0: _PR_MD_EXIT_THREAD(me); andre@0: _PR_NativeDestroyThread(me); andre@0: } else { andre@0: _PR_UserDestroyThread(me); andre@0: PR_DELETE(me->stack); andre@0: PR_DELETE(me); andre@0: } andre@0: andre@0: /* andre@0: * XXX: We are freeing the heap memory here so that Purify won't andre@0: * complain, but we should also free other kinds of resources andre@0: * that are allocated by the _PR_InitXXX() functions. andre@0: * Ideally, for each _PR_InitXXX(), there should be a corresponding andre@0: * _PR_XXXCleanup() that we can call here. andre@0: */ andre@0: #ifdef WINNT andre@0: _PR_CleanupCPUs(); andre@0: #endif andre@0: _PR_CleanupThreads(); andre@0: _PR_CleanupCMon(); andre@0: PR_DestroyLock(_pr_sleeplock); andre@0: _pr_sleeplock = NULL; andre@0: _PR_CleanupLayerCache(); andre@0: _PR_CleanupEnv(); andre@0: _PR_CleanupStacks(); andre@0: _PR_CleanupBeforeExit(); andre@0: _pr_initialized = PR_FALSE; andre@0: return PR_SUCCESS; andre@0: } andre@0: return PR_FAILURE; andre@0: } andre@0: #endif /* defined(_PR_PTHREADS) */ andre@0: andre@0: /* andre@0: *------------------------------------------------------------------------ andre@0: * PR_ProcessExit -- andre@0: * andre@0: * Cause an immediate, nongraceful, forced termination of the process. andre@0: * It takes a PRIntn argument, which is the exit status code of the andre@0: * process. andre@0: * andre@0: * See also: PR_Cleanup() andre@0: * andre@0: *------------------------------------------------------------------------ andre@0: */ andre@0: andre@0: #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) andre@0: /* see ptthread.c */ andre@0: #else andre@0: PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) andre@0: { andre@0: _PR_MD_EXIT(status); andre@0: } andre@0: andre@0: #endif /* defined(_PR_PTHREADS) */ andre@0: andre@0: PR_IMPLEMENT(PRProcessAttr *) andre@0: PR_NewProcessAttr(void) andre@0: { andre@0: PRProcessAttr *attr; andre@0: andre@0: attr = PR_NEWZAP(PRProcessAttr); andre@0: if (!attr) { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: } andre@0: return attr; andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) andre@0: PR_ResetProcessAttr(PRProcessAttr *attr) andre@0: { andre@0: PR_FREEIF(attr->currentDirectory); andre@0: PR_FREEIF(attr->fdInheritBuffer); andre@0: memset(attr, 0, sizeof(*attr)); andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) andre@0: PR_DestroyProcessAttr(PRProcessAttr *attr) andre@0: { andre@0: PR_FREEIF(attr->currentDirectory); andre@0: PR_FREEIF(attr->fdInheritBuffer); andre@0: PR_DELETE(attr); andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) andre@0: PR_ProcessAttrSetStdioRedirect( andre@0: PRProcessAttr *attr, andre@0: PRSpecialFD stdioFd, andre@0: PRFileDesc *redirectFd) andre@0: { andre@0: switch (stdioFd) { andre@0: case PR_StandardInput: andre@0: attr->stdinFd = redirectFd; andre@0: break; andre@0: case PR_StandardOutput: andre@0: attr->stdoutFd = redirectFd; andre@0: break; andre@0: case PR_StandardError: andre@0: attr->stderrFd = redirectFd; andre@0: break; andre@0: default: andre@0: PR_ASSERT(0); andre@0: } andre@0: } andre@0: andre@0: /* andre@0: * OBSOLETE andre@0: */ andre@0: PR_IMPLEMENT(void) andre@0: PR_SetStdioRedirect( andre@0: PRProcessAttr *attr, andre@0: PRSpecialFD stdioFd, andre@0: PRFileDesc *redirectFd) andre@0: { andre@0: #if defined(DEBUG) andre@0: static PRBool warn = PR_TRUE; andre@0: if (warn) { andre@0: warn = _PR_Obsolete("PR_SetStdioRedirect()", andre@0: "PR_ProcessAttrSetStdioRedirect()"); andre@0: } andre@0: #endif andre@0: PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd); andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) andre@0: PR_ProcessAttrSetCurrentDirectory( andre@0: PRProcessAttr *attr, andre@0: const char *dir) andre@0: { andre@0: PR_FREEIF(attr->currentDirectory); andre@0: attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1); andre@0: if (!attr->currentDirectory) { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: strcpy(attr->currentDirectory, dir); andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) andre@0: PR_ProcessAttrSetInheritableFD( andre@0: PRProcessAttr *attr, andre@0: PRFileDesc *fd, andre@0: const char *name) andre@0: { andre@0: /* We malloc the fd inherit buffer in multiples of this number. */ andre@0: #define FD_INHERIT_BUFFER_INCR 128 andre@0: /* The length of "NSPR_INHERIT_FDS=" */ andre@0: #define NSPR_INHERIT_FDS_STRLEN 17 andre@0: /* The length of osfd (PROsfd) printed in hexadecimal with 0x prefix */ andre@0: #ifdef _WIN64 andre@0: #define OSFD_STRLEN 18 andre@0: #else andre@0: #define OSFD_STRLEN 10 andre@0: #endif andre@0: /* The length of fd type (PRDescType) printed in decimal */ andre@0: #define FD_TYPE_STRLEN 1 andre@0: PRSize newSize; andre@0: int remainder; andre@0: char *newBuffer; andre@0: int nwritten; andre@0: char *cur; andre@0: int freeSize; andre@0: andre@0: if (fd->identity != PR_NSPR_IO_LAYER) { andre@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: if (fd->secret->inheritable == _PR_TRI_UNKNOWN) { andre@0: _PR_MD_QUERY_FD_INHERITABLE(fd); andre@0: } andre@0: if (fd->secret->inheritable != _PR_TRI_TRUE) { andre@0: PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: /* andre@0: * We also need to account for the : separators and the andre@0: * terminating null byte. andre@0: */ andre@0: if (NULL == attr->fdInheritBuffer) { andre@0: /* The first time, we print "NSPR_INHERIT_FDS=::" */ andre@0: newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name) andre@0: + FD_TYPE_STRLEN + OSFD_STRLEN + 2 + 1; andre@0: } else { andre@0: /* At other times, we print ":::" */ andre@0: newSize = attr->fdInheritBufferUsed + strlen(name) andre@0: + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1; andre@0: } andre@0: if (newSize > attr->fdInheritBufferSize) { andre@0: /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */ andre@0: remainder = newSize % FD_INHERIT_BUFFER_INCR; andre@0: if (remainder != 0) { andre@0: newSize += (FD_INHERIT_BUFFER_INCR - remainder); andre@0: } andre@0: if (NULL == attr->fdInheritBuffer) { andre@0: newBuffer = (char *) PR_MALLOC(newSize); andre@0: } else { andre@0: newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize); andre@0: } andre@0: if (NULL == newBuffer) { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: attr->fdInheritBuffer = newBuffer; andre@0: attr->fdInheritBufferSize = newSize; andre@0: } andre@0: cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed; andre@0: freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed; andre@0: if (0 == attr->fdInheritBufferUsed) { andre@0: nwritten = PR_snprintf(cur, freeSize, andre@0: "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD, andre@0: name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); andre@0: } else { andre@0: nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD, andre@0: name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); andre@0: } andre@0: attr->fdInheritBufferUsed += nwritten; andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD( andre@0: const char *name) andre@0: { andre@0: PRFileDesc *fd; andre@0: const char *envVar; andre@0: const char *ptr; andre@0: int len = strlen(name); andre@0: PROsfd osfd; andre@0: int nColons; andre@0: PRIntn fileType; andre@0: andre@0: envVar = PR_GetEnv("NSPR_INHERIT_FDS"); andre@0: if (NULL == envVar || '\0' == envVar[0]) { andre@0: PR_SetError(PR_UNKNOWN_ERROR, 0); andre@0: return NULL; andre@0: } andre@0: andre@0: ptr = envVar; andre@0: while (1) { andre@0: if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) { andre@0: ptr += len + 1; andre@0: PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd); andre@0: switch ((PRDescType)fileType) { andre@0: case PR_DESC_FILE: andre@0: fd = PR_ImportFile(osfd); andre@0: break; andre@0: case PR_DESC_PIPE: andre@0: fd = PR_ImportPipe(osfd); andre@0: break; andre@0: case PR_DESC_SOCKET_TCP: andre@0: fd = PR_ImportTCPSocket(osfd); andre@0: break; andre@0: case PR_DESC_SOCKET_UDP: andre@0: fd = PR_ImportUDPSocket(osfd); andre@0: break; andre@0: default: andre@0: PR_ASSERT(0); andre@0: PR_SetError(PR_UNKNOWN_ERROR, 0); andre@0: fd = NULL; andre@0: break; andre@0: } andre@0: if (fd) { andre@0: /* andre@0: * An inherited FD is inheritable by default. andre@0: * The child process needs to call PR_SetFDInheritable andre@0: * to make it non-inheritable if so desired. andre@0: */ andre@0: fd->secret->inheritable = _PR_TRI_TRUE; andre@0: } andre@0: return fd; andre@0: } andre@0: /* Skip three colons */ andre@0: nColons = 0; andre@0: while (*ptr) { andre@0: if (*ptr == ':') { andre@0: if (++nColons == 3) { andre@0: break; andre@0: } andre@0: } andre@0: ptr++; andre@0: } andre@0: if (*ptr == '\0') { andre@0: PR_SetError(PR_UNKNOWN_ERROR, 0); andre@0: return NULL; andre@0: } andre@0: ptr++; andre@0: } andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRProcess*) PR_CreateProcess( andre@0: const char *path, andre@0: char *const *argv, andre@0: char *const *envp, andre@0: const PRProcessAttr *attr) andre@0: { andre@0: return _PR_MD_CREATE_PROCESS(path, argv, envp, attr); andre@0: } /* PR_CreateProcess */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_CreateProcessDetached( andre@0: const char *path, andre@0: char *const *argv, andre@0: char *const *envp, andre@0: const PRProcessAttr *attr) andre@0: { andre@0: PRProcess *process; andre@0: PRStatus rv; andre@0: andre@0: process = PR_CreateProcess(path, argv, envp, attr); andre@0: if (NULL == process) { andre@0: return PR_FAILURE; andre@0: } andre@0: rv = PR_DetachProcess(process); andre@0: PR_ASSERT(PR_SUCCESS == rv); andre@0: if (rv == PR_FAILURE) { andre@0: PR_DELETE(process); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process) andre@0: { andre@0: return _PR_MD_DETACH_PROCESS(process); andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode) andre@0: { andre@0: return _PR_MD_WAIT_PROCESS(process, exitCode); andre@0: } /* PR_WaitProcess */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process) andre@0: { andre@0: return _PR_MD_KILL_PROCESS(process); andre@0: } andre@0: andre@0: /* andre@0: ******************************************************************** andre@0: * andre@0: * Module initialization andre@0: * andre@0: ******************************************************************** andre@0: */ andre@0: andre@0: static struct { andre@0: PRLock *ml; andre@0: PRCondVar *cv; andre@0: } mod_init; andre@0: andre@0: static void _PR_InitCallOnce(void) { andre@0: mod_init.ml = PR_NewLock(); andre@0: PR_ASSERT(NULL != mod_init.ml); andre@0: mod_init.cv = PR_NewCondVar(mod_init.ml); andre@0: PR_ASSERT(NULL != mod_init.cv); andre@0: } andre@0: andre@0: void _PR_CleanupCallOnce() andre@0: { andre@0: PR_DestroyLock(mod_init.ml); andre@0: mod_init.ml = NULL; andre@0: PR_DestroyCondVar(mod_init.cv); andre@0: mod_init.cv = NULL; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_CallOnce( andre@0: PRCallOnceType *once, andre@0: PRCallOnceFN func) andre@0: { andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: if (!once->initialized) { andre@0: if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) { andre@0: once->status = (*func)(); andre@0: PR_Lock(mod_init.ml); andre@0: once->initialized = 1; andre@0: PR_NotifyAllCondVar(mod_init.cv); andre@0: PR_Unlock(mod_init.ml); andre@0: } else { andre@0: PR_Lock(mod_init.ml); andre@0: while (!once->initialized) { andre@0: PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); andre@0: } andre@0: PR_Unlock(mod_init.ml); andre@0: } andre@0: } else { andre@0: if (PR_SUCCESS != once->status) { andre@0: PR_SetError(PR_CALL_ONCE_ERROR, 0); andre@0: } andre@0: } andre@0: return once->status; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg( andre@0: PRCallOnceType *once, andre@0: PRCallOnceWithArgFN func, andre@0: void *arg) andre@0: { andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: if (!once->initialized) { andre@0: if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) { andre@0: once->status = (*func)(arg); andre@0: PR_Lock(mod_init.ml); andre@0: once->initialized = 1; andre@0: PR_NotifyAllCondVar(mod_init.cv); andre@0: PR_Unlock(mod_init.ml); andre@0: } else { andre@0: PR_Lock(mod_init.ml); andre@0: while (!once->initialized) { andre@0: PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); andre@0: } andre@0: PR_Unlock(mod_init.ml); andre@0: } andre@0: } else { andre@0: if (PR_SUCCESS != once->status) { andre@0: PR_SetError(PR_CALL_ONCE_ERROR, 0); andre@0: } andre@0: } andre@0: return once->status; andre@0: } andre@0: andre@0: PRBool _PR_Obsolete(const char *obsolete, const char *preferred) andre@0: { andre@0: #if defined(DEBUG) andre@0: PR_fprintf( andre@0: PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n", andre@0: obsolete, (NULL == preferred) ? "something else" : preferred); andre@0: #endif andre@0: return PR_FALSE; andre@0: } /* _PR_Obsolete */ andre@0: andre@0: /* prinit.c */ andre@0: andre@0: