Back to index

lightning-sunbird  0.9+nobinonly
prinit.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 #include <ctype.h>
00040 #include <string.h>
00041 
00042 PRLogModuleInfo *_pr_clock_lm;
00043 PRLogModuleInfo *_pr_cmon_lm;
00044 PRLogModuleInfo *_pr_io_lm;
00045 PRLogModuleInfo *_pr_cvar_lm;
00046 PRLogModuleInfo *_pr_mon_lm;
00047 PRLogModuleInfo *_pr_linker_lm;
00048 PRLogModuleInfo *_pr_sched_lm;
00049 PRLogModuleInfo *_pr_thread_lm;
00050 PRLogModuleInfo *_pr_gc_lm;
00051 PRLogModuleInfo *_pr_shm_lm;
00052 PRLogModuleInfo *_pr_shma_lm;
00053 
00054 PRFileDesc *_pr_stdin;
00055 PRFileDesc *_pr_stdout;
00056 PRFileDesc *_pr_stderr;
00057 
00058 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
00059 
00060 PRCList _pr_active_local_threadQ =
00061                      PR_INIT_STATIC_CLIST(&_pr_active_local_threadQ);
00062 PRCList _pr_active_global_threadQ =
00063                      PR_INIT_STATIC_CLIST(&_pr_active_global_threadQ);
00064 
00065 _MDLock  _pr_cpuLock;           /* lock for the CPU Q */
00066 PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ);
00067 
00068 PRUint32 _pr_utid;
00069 
00070 PRInt32 _pr_userActive;
00071 PRInt32 _pr_systemActive;
00072 PRUintn _pr_maxPTDs;
00073 
00074 #ifdef _PR_LOCAL_THREADS_ONLY
00075 
00076 struct _PRCPU        *_pr_currentCPU;
00077 PRThread      *_pr_currentThread;
00078 PRThread      *_pr_lastThread;
00079 PRInt32       _pr_intsOff;
00080 
00081 #endif /* _PR_LOCAL_THREADS_ONLY */
00082 
00083 /* Lock protecting all "termination" condition variables of all threads */
00084 PRLock *_pr_terminationCVLock;
00085 
00086 #endif /* !defined(_PR_PTHREADS) */
00087 
00088 PRLock *_pr_sleeplock;  /* used in PR_Sleep(), classic and pthreads */
00089 
00090 static void _PR_InitCallOnce(void);
00091 
00092 PRBool _pr_initialized = PR_FALSE;
00093 
00094 
00095 PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion)
00096 {
00097     /*
00098     ** This is the secret handshake algorithm.
00099     **
00100     ** This release has a simple version compatibility
00101     ** check algorithm.  This release is not backward
00102     ** compatible with previous major releases.  It is
00103     ** not compatible with future major, minor, or
00104     ** patch releases.
00105     */
00106     int vmajor = 0, vminor = 0, vpatch = 0;
00107     const char *ptr = importedVersion;
00108 
00109     while (isdigit(*ptr)) {
00110         vmajor = 10 * vmajor + *ptr - '0';
00111         ptr++;
00112     }
00113     if (*ptr == '.') {
00114         ptr++;
00115         while (isdigit(*ptr)) {
00116             vminor = 10 * vminor + *ptr - '0';
00117             ptr++;
00118         }
00119         if (*ptr == '.') {
00120             ptr++;
00121             while (isdigit(*ptr)) {
00122                 vpatch = 10 * vpatch + *ptr - '0';
00123                 ptr++;
00124             }
00125         }
00126     }
00127 
00128     if (vmajor != PR_VMAJOR) {
00129         return PR_FALSE;
00130     }
00131     if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
00132         return PR_FALSE;
00133     }
00134     if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) {
00135         return PR_FALSE;
00136     }
00137     return PR_TRUE;
00138 }  /* PR_VersionCheck */
00139 
00140 
00141 PR_IMPLEMENT(PRBool) PR_Initialized(void)
00142 {
00143     return _pr_initialized;
00144 }
00145 
00146 PRInt32 _native_threads_only = 0;
00147 
00148 #ifdef WINNT
00149 static void _pr_SetNativeThreadsOnlyMode(void)
00150 {
00151     HMODULE mainExe;
00152     PRBool *globalp;
00153     char *envp;
00154 
00155     mainExe = GetModuleHandle(NULL);
00156     PR_ASSERT(NULL != mainExe);
00157     globalp = (PRBool *) GetProcAddress(mainExe, "nspr_native_threads_only");
00158     if (globalp) {
00159         _native_threads_only = (*globalp != PR_FALSE);
00160     } else if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) {
00161         _native_threads_only = (atoi(envp) == 1);
00162     }
00163 }
00164 #endif
00165 
00166 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
00167 extern PRStatus _pr_init_ipv6(void);
00168 #endif
00169 
00170 static void _PR_InitStuff(void)
00171 {
00172 
00173     if (_pr_initialized) return;
00174     _pr_initialized = PR_TRUE;
00175 #ifdef _PR_ZONE_ALLOCATOR
00176     _PR_InitZones();
00177 #endif
00178 #ifdef WINNT
00179     _pr_SetNativeThreadsOnlyMode();
00180 #endif
00181 
00182 
00183     (void) PR_GetPageSize();
00184 
00185        _pr_clock_lm = PR_NewLogModule("clock");
00186        _pr_cmon_lm = PR_NewLogModule("cmon");
00187        _pr_io_lm = PR_NewLogModule("io");
00188        _pr_mon_lm = PR_NewLogModule("mon");
00189        _pr_linker_lm = PR_NewLogModule("linker");
00190        _pr_cvar_lm = PR_NewLogModule("cvar");
00191        _pr_sched_lm = PR_NewLogModule("sched");
00192        _pr_thread_lm = PR_NewLogModule("thread");
00193        _pr_gc_lm = PR_NewLogModule("gc");
00194        _pr_shm_lm = PR_NewLogModule("shm");
00195        _pr_shma_lm = PR_NewLogModule("shma");
00196       
00197     /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ 
00198     _PR_MD_EARLY_INIT();
00199 
00200     _PR_InitLocks();
00201     _PR_InitAtomic();
00202     _PR_InitSegs();
00203     _PR_InitStacks();
00204        _PR_InitTPD();
00205     _PR_InitEnv();
00206     _PR_InitLayerCache();
00207     _PR_InitClock();
00208 
00209     _pr_sleeplock = PR_NewLock();
00210     PR_ASSERT(NULL != _pr_sleeplock);
00211 
00212 #ifdef GC_LEAK_DETECTOR
00213     _PR_InitGarbageCollector();
00214 #endif
00215 
00216     _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
00217     
00218 #ifdef WIN16
00219        {
00220        PRInt32 top;   /* artificial top of stack, win16 */
00221     _pr_top_of_task_stack = (char *) &top;
00222        }
00223 #endif    
00224 
00225 #ifndef _PR_GLOBAL_THREADS_ONLY
00226        _PR_InitCPUs();
00227 #endif
00228 
00229 /*
00230  * XXX: call _PR_InitMem only on those platforms for which nspr implements
00231  *     malloc, for now.
00232  */
00233 #ifdef _PR_OVERRIDE_MALLOC
00234     _PR_InitMem();
00235 #endif
00236 
00237     _PR_InitCMon();
00238     _PR_InitIO();
00239     _PR_InitNet();
00240     _PR_InitLog();
00241     _PR_InitLinker();
00242     _PR_InitCallOnce();
00243     _PR_InitDtoa();
00244     _PR_InitTime();
00245     _PR_InitMW();
00246     _PR_InitRWLocks();
00247 
00248     nspr_InitializePRErrorTable();
00249 
00250 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
00251        _pr_init_ipv6();
00252 #endif
00253        
00254     _PR_MD_FINAL_INIT();
00255 }
00256 
00257 void _PR_ImplicitInitialization(void)
00258 {
00259        _PR_InitStuff();
00260 
00261     /* Enable interrupts */
00262 #if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY)
00263     _PR_MD_START_INTERRUPTS();
00264 #endif
00265 
00266 }
00267 
00268 PR_IMPLEMENT(void) PR_DisableClockInterrupts(void)
00269 {
00270 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
00271        if (!_pr_initialized) {
00272               _PR_InitStuff();
00273        } else {
00274        _PR_MD_DISABLE_CLOCK_INTERRUPTS();
00275        }
00276 #endif
00277 }
00278 
00279 PR_IMPLEMENT(void) PR_EnableClockInterrupts(void)
00280 {
00281 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
00282        if (!_pr_initialized) {
00283               _PR_InitStuff();
00284        }
00285     _PR_MD_ENABLE_CLOCK_INTERRUPTS();
00286 #endif
00287 }
00288 
00289 PR_IMPLEMENT(void) PR_BlockClockInterrupts(void)
00290 {
00291 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
00292        _PR_MD_BLOCK_CLOCK_INTERRUPTS();
00293 #endif
00294 }
00295 
00296 PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void)
00297 {
00298 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
00299        _PR_MD_UNBLOCK_CLOCK_INTERRUPTS();
00300 #endif
00301 }
00302 
00303 PR_IMPLEMENT(void) PR_Init(
00304     PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
00305 {
00306 #if defined(XP_MAC)
00307 #pragma unused (type, priority, maxPTDs)
00308 #endif
00309 
00310     _PR_ImplicitInitialization();
00311 }
00312 
00313 PR_IMPLEMENT(PRIntn) PR_Initialize(
00314     PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs)
00315 {
00316 #if defined(XP_MAC)
00317 #pragma unused (maxPTDs)
00318 #endif
00319 
00320     PRIntn rv;
00321     _PR_ImplicitInitialization();
00322     rv = prmain(argc, argv);
00323        PR_Cleanup();
00324     return rv;
00325 }  /* PR_Initialize */
00326 
00327 /*
00328  *-----------------------------------------------------------------------
00329  *
00330  * _PR_CleanupBeforeExit --
00331  *
00332  *   Perform the cleanup work before exiting the process. 
00333  *   We first do the cleanup generic to all platforms.  Then
00334  *   we call _PR_MD_CLEANUP_BEFORE_EXIT(), where platform-dependent
00335  *   cleanup is done.  This function is used by PR_Cleanup().
00336  *
00337  * See also: PR_Cleanup().
00338  *
00339  *-----------------------------------------------------------------------
00340  */
00341 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
00342     /* see ptthread.c */
00343 #else
00344 static void
00345 _PR_CleanupBeforeExit(void)
00346 {
00347 /* 
00348 Do not make any calls here other than to destroy resources.  For example,
00349 do not make any calls that eventually may end up in PR_Lock.  Because the
00350 thread is destroyed, can not access current thread any more.
00351 */
00352     _PR_CleanupTPD();
00353     if (_pr_terminationCVLock)
00354     /*
00355      * In light of the comment above, this looks real suspicious.
00356      * I'd go so far as to say it's just a problem waiting to happen.
00357      */
00358         PR_DestroyLock(_pr_terminationCVLock);
00359 
00360     _PR_MD_CLEANUP_BEFORE_EXIT();
00361 }
00362 #endif /* defined(_PR_PTHREADS) */
00363 
00364 /*
00365  *----------------------------------------------------------------------
00366  *
00367  * PR_Cleanup --
00368  *
00369  *   Perform a graceful shutdown of the NSPR runtime.  PR_Cleanup() may
00370  *   only be called from the primordial thread, typically at the
00371  *   end of the main() function.  It returns when it has completed
00372  *   its platform-dependent duty and the process must not make any other
00373  *   NSPR library calls prior to exiting from main().
00374  *
00375  *   PR_Cleanup() first blocks the primordial thread until all the
00376  *   other user (non-system) threads, if any, have terminated.
00377  *   Then it performs cleanup in preparation for exiting the process.
00378  *   PR_Cleanup() does not exit the primordial thread (which would
00379  *   in turn exit the process).
00380  *   
00381  *   PR_Cleanup() only responds when it is called by the primordial
00382  *   thread. Calls by any other thread are silently ignored.
00383  *
00384  * See also: PR_ExitProcess()
00385  *
00386  *----------------------------------------------------------------------
00387  */
00388 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
00389     /* see ptthread.c */
00390 #else
00391 
00392 PR_IMPLEMENT(PRStatus) PR_Cleanup()
00393 {
00394     PRThread *me = PR_GetCurrentThread();
00395     PR_ASSERT((NULL != me) && (me->flags & _PR_PRIMORDIAL));
00396     if ((NULL != me) && (me->flags & _PR_PRIMORDIAL))
00397     {
00398         PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
00399 
00400         /*
00401          * No more recycling of threads
00402          */
00403         _pr_recycleThreads = 0;
00404 
00405         /*
00406          * Wait for all other user (non-system/daemon) threads
00407          * to terminate.
00408          */
00409         PR_Lock(_pr_activeLock);
00410         while (_pr_userActive > _pr_primordialExitCount) {
00411             PR_WaitCondVar(_pr_primordialExitCVar, PR_INTERVAL_NO_TIMEOUT);
00412         }
00413         PR_Unlock(_pr_activeLock);
00414 
00415 #ifdef IRIX
00416               _PR_MD_PRE_CLEANUP(me);
00417               /*
00418                * The primordial thread must now be running on the primordial cpu
00419                */
00420        PR_ASSERT((_PR_IS_NATIVE_THREAD(me)) || (me->cpu->id == 0));
00421 #endif
00422 
00423         _PR_CleanupMW();
00424         _PR_CleanupTime();
00425         _PR_CleanupDtoa();
00426         _PR_CleanupCallOnce();
00427               _PR_ShutdownLinker();
00428         /* Release the primordial thread's private data, etc. */
00429         _PR_CleanupThread(me);
00430 
00431         _PR_MD_STOP_INTERRUPTS();
00432 
00433            PR_LOG(_pr_thread_lm, PR_LOG_MIN,
00434                    ("PR_Cleanup: clean up before destroying thread"));
00435            _PR_LogCleanup();
00436 
00437         /*
00438          * This part should look like the end of _PR_NativeRunThread
00439          * and _PR_UserRunThread.
00440          */
00441         if (_PR_IS_NATIVE_THREAD(me)) {
00442             _PR_MD_EXIT_THREAD(me);
00443             _PR_NativeDestroyThread(me);
00444         } else {
00445             _PR_UserDestroyThread(me);
00446             PR_DELETE(me->stack);
00447             PR_DELETE(me);
00448         }
00449 
00450         /*
00451          * XXX: We are freeing the heap memory here so that Purify won't
00452          * complain, but we should also free other kinds of resources
00453          * that are allocated by the _PR_InitXXX() functions.
00454          * Ideally, for each _PR_InitXXX(), there should be a corresponding
00455          * _PR_XXXCleanup() that we can call here.
00456          */
00457         _PR_CleanupNet();
00458         _PR_CleanupIO();
00459 #ifdef WINNT
00460         _PR_CleanupCPUs();
00461 #endif
00462         _PR_CleanupThreads();
00463         PR_DestroyLock(_pr_sleeplock);
00464         _pr_sleeplock = NULL;
00465         _PR_CleanupLayerCache();
00466         _PR_CleanupEnv();
00467         _PR_CleanupStacks();
00468         _PR_CleanupBeforeExit();
00469         _pr_initialized = PR_FALSE;
00470         return PR_SUCCESS;
00471     }
00472     return PR_FAILURE;
00473 }
00474 #endif /* defined(_PR_PTHREADS) */
00475 
00476 /*
00477  *------------------------------------------------------------------------
00478  * PR_ProcessExit --
00479  * 
00480  *   Cause an immediate, nongraceful, forced termination of the process.
00481  *   It takes a PRIntn argument, which is the exit status code of the
00482  *   process.
00483  *   
00484  * See also: PR_Cleanup()
00485  *
00486  *------------------------------------------------------------------------
00487  */
00488 
00489 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
00490     /* see ptthread.c */
00491 #else
00492 PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
00493 {
00494     _PR_MD_EXIT(status);
00495 }
00496 
00497 #endif /* defined(_PR_PTHREADS) */
00498 
00499 PR_IMPLEMENT(PRProcessAttr *)
00500 PR_NewProcessAttr(void)
00501 {
00502     PRProcessAttr *attr;
00503 
00504     attr = PR_NEWZAP(PRProcessAttr);
00505     if (!attr) {
00506         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00507     }
00508     return attr;
00509 }
00510 
00511 PR_IMPLEMENT(void)
00512 PR_ResetProcessAttr(PRProcessAttr *attr)
00513 {
00514     PR_FREEIF(attr->currentDirectory);
00515     PR_FREEIF(attr->fdInheritBuffer);
00516     memset(attr, 0, sizeof(*attr));
00517 }
00518 
00519 PR_IMPLEMENT(void)
00520 PR_DestroyProcessAttr(PRProcessAttr *attr)
00521 {
00522     PR_FREEIF(attr->currentDirectory);
00523     PR_FREEIF(attr->fdInheritBuffer);
00524     PR_DELETE(attr);
00525 }
00526 
00527 PR_IMPLEMENT(void)
00528 PR_ProcessAttrSetStdioRedirect(
00529     PRProcessAttr *attr,
00530     PRSpecialFD stdioFd,
00531     PRFileDesc *redirectFd)
00532 {
00533     switch (stdioFd) {
00534         case PR_StandardInput:
00535             attr->stdinFd = redirectFd;
00536             break;
00537         case PR_StandardOutput:
00538             attr->stdoutFd = redirectFd;
00539             break;
00540         case PR_StandardError:
00541             attr->stderrFd = redirectFd;
00542             break;
00543         default:
00544             PR_ASSERT(0);
00545     }
00546 }
00547 
00548 /*
00549  * OBSOLETE
00550  */
00551 PR_IMPLEMENT(void)
00552 PR_SetStdioRedirect(
00553     PRProcessAttr *attr,
00554     PRSpecialFD stdioFd,
00555     PRFileDesc *redirectFd)
00556 {
00557 #if defined(DEBUG)
00558     static PRBool warn = PR_TRUE;
00559     if (warn) {
00560         warn = _PR_Obsolete("PR_SetStdioRedirect()",
00561                 "PR_ProcessAttrSetStdioRedirect()");
00562     }
00563 #endif
00564     PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd);
00565 }
00566 
00567 PR_IMPLEMENT(PRStatus)
00568 PR_ProcessAttrSetCurrentDirectory(
00569     PRProcessAttr *attr,
00570     const char *dir)
00571 {
00572     PR_FREEIF(attr->currentDirectory);
00573     attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1);
00574     if (!attr->currentDirectory) {
00575         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00576         return PR_FAILURE;
00577     }
00578     strcpy(attr->currentDirectory, dir);
00579     return PR_SUCCESS;
00580 }
00581 
00582 PR_IMPLEMENT(PRStatus)
00583 PR_ProcessAttrSetInheritableFD(
00584     PRProcessAttr *attr,
00585     PRFileDesc *fd,
00586     const char *name)
00587 {
00588     /* We malloc the fd inherit buffer in multiples of this number. */
00589 #define FD_INHERIT_BUFFER_INCR 128
00590     /* The length of "NSPR_INHERIT_FDS=" */
00591 #define NSPR_INHERIT_FDS_STRLEN 17
00592     /* The length of osfd (PRInt32) printed in hexadecimal with 0x prefix */
00593 #define OSFD_STRLEN 10
00594     /* The length of fd type (PRDescType) printed in decimal */
00595 #define FD_TYPE_STRLEN 1
00596     PRSize newSize;
00597     int remainder;
00598     char *newBuffer;
00599     int nwritten;
00600     char *cur;
00601     int freeSize;
00602 
00603     if (fd->identity != PR_NSPR_IO_LAYER) {
00604         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00605         return PR_FAILURE;
00606     }
00607     if (fd->secret->inheritable == _PR_TRI_UNKNOWN) {
00608         _PR_MD_QUERY_FD_INHERITABLE(fd);
00609     }
00610     if (fd->secret->inheritable != _PR_TRI_TRUE) {
00611         PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0);
00612         return PR_FAILURE;
00613     }
00614 
00615     /*
00616      * We also need to account for the : separators and the
00617      * terminating null byte.
00618      */
00619     if (NULL == attr->fdInheritBuffer) {
00620         /* The first time, we print "NSPR_INHERIT_FDS=<name>:<type>:<val>" */
00621         newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name)
00622                 + FD_TYPE_STRLEN + OSFD_STRLEN + 2 + 1;
00623     } else {
00624         /* At other times, we print ":<name>:<type>:<val>" */
00625         newSize = attr->fdInheritBufferUsed + strlen(name)
00626                 + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1;
00627     }
00628     if (newSize > attr->fdInheritBufferSize) {
00629         /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */
00630         remainder = newSize % FD_INHERIT_BUFFER_INCR;
00631         if (remainder != 0) {
00632             newSize += (FD_INHERIT_BUFFER_INCR - remainder);
00633         }
00634         if (NULL == attr->fdInheritBuffer) {
00635             newBuffer = (char *) PR_MALLOC(newSize);
00636         } else {
00637             newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize);
00638         }
00639         if (NULL == newBuffer) {
00640             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00641             return PR_FAILURE;
00642         }
00643         attr->fdInheritBuffer = newBuffer;
00644         attr->fdInheritBufferSize = newSize;
00645     }
00646     cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed;
00647     freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed;
00648     if (0 == attr->fdInheritBufferUsed) {
00649         nwritten = PR_snprintf(cur, freeSize,
00650                 "NSPR_INHERIT_FDS=%s:%d:0x%lx",
00651                 name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
00652     } else {
00653         nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%lx",
00654                 name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
00655     }
00656     attr->fdInheritBufferUsed += nwritten; 
00657     return PR_SUCCESS;
00658 }
00659 
00660 PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD(
00661     const char *name)
00662 {
00663     PRFileDesc *fd;
00664     const char *envVar;
00665     const char *ptr;
00666     int len = strlen(name);
00667     PRInt32 osfd;
00668     int nColons;
00669     PRIntn fileType;
00670 
00671     envVar = PR_GetEnv("NSPR_INHERIT_FDS");
00672     if (NULL == envVar || '\0' == envVar[0]) {
00673         PR_SetError(PR_UNKNOWN_ERROR, 0);
00674         return NULL;
00675     }
00676 
00677     ptr = envVar;
00678     while (1) {
00679         if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) {
00680             ptr += len + 1;
00681             PR_sscanf(ptr, "%d:0x%lx", &fileType, &osfd);
00682             switch ((PRDescType)fileType) {
00683                 case PR_DESC_FILE:
00684                     fd = PR_ImportFile(osfd);
00685                     break;
00686                 case PR_DESC_PIPE:
00687                     fd = PR_ImportPipe(osfd);
00688                     break;
00689                 case PR_DESC_SOCKET_TCP:
00690                     fd = PR_ImportTCPSocket(osfd);
00691                     break;
00692                 case PR_DESC_SOCKET_UDP:
00693                     fd = PR_ImportUDPSocket(osfd);
00694                     break;
00695                 default:
00696                     PR_ASSERT(0);
00697                     PR_SetError(PR_UNKNOWN_ERROR, 0);
00698                     fd = NULL;
00699                     break;
00700             }
00701             if (fd) {
00702                 /*
00703                  * An inherited FD is inheritable by default.
00704                  * The child process needs to call PR_SetFDInheritable
00705                  * to make it non-inheritable if so desired.
00706                  */
00707                 fd->secret->inheritable = _PR_TRI_TRUE;
00708             }
00709             return fd;
00710         }
00711         /* Skip three colons */
00712         nColons = 0;
00713         while (*ptr) {
00714             if (*ptr == ':') {
00715                 if (++nColons == 3) {
00716                     break;
00717                 }
00718             }
00719             ptr++;
00720         }
00721         if (*ptr == '\0') {
00722             PR_SetError(PR_UNKNOWN_ERROR, 0);
00723             return NULL;
00724         }
00725         ptr++;
00726     }
00727 }
00728 
00729 PR_IMPLEMENT(PRProcess*) PR_CreateProcess(
00730     const char *path,
00731     char *const *argv,
00732     char *const *envp,
00733     const PRProcessAttr *attr)
00734 {
00735     return _PR_MD_CREATE_PROCESS(path, argv, envp, attr);
00736 }  /* PR_CreateProcess */
00737 
00738 PR_IMPLEMENT(PRStatus) PR_CreateProcessDetached(
00739     const char *path,
00740     char *const *argv,
00741     char *const *envp,
00742     const PRProcessAttr *attr)
00743 {
00744     PRProcess *process;
00745     PRStatus rv;
00746 
00747     process = PR_CreateProcess(path, argv, envp, attr);
00748     if (NULL == process) {
00749        return PR_FAILURE;
00750     }
00751     rv = PR_DetachProcess(process);
00752     PR_ASSERT(PR_SUCCESS == rv);
00753     if (rv == PR_FAILURE) {
00754        PR_DELETE(process);
00755        return PR_FAILURE;
00756     }
00757     return PR_SUCCESS;
00758 }
00759 
00760 PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process)
00761 {
00762     return _PR_MD_DETACH_PROCESS(process);
00763 }
00764 
00765 PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode)
00766 {
00767     return _PR_MD_WAIT_PROCESS(process, exitCode);
00768 }  /* PR_WaitProcess */
00769 
00770 PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process)
00771 {
00772     return _PR_MD_KILL_PROCESS(process);
00773 }
00774 
00775 /*
00776  ********************************************************************
00777  *
00778  * Module initialization
00779  *
00780  ********************************************************************
00781  */
00782 
00783 static struct {
00784     PRLock *ml;
00785     PRCondVar *cv;
00786 } mod_init;
00787 
00788 static void _PR_InitCallOnce(void) {
00789     mod_init.ml = PR_NewLock();
00790     PR_ASSERT(NULL != mod_init.ml);
00791     mod_init.cv = PR_NewCondVar(mod_init.ml);
00792     PR_ASSERT(NULL != mod_init.cv);
00793 }
00794 
00795 void _PR_CleanupCallOnce()
00796 {
00797     PR_DestroyLock(mod_init.ml);
00798     mod_init.ml = NULL;
00799     PR_DestroyCondVar(mod_init.cv);
00800     mod_init.cv = NULL;
00801 }
00802 
00803 PR_IMPLEMENT(PRStatus) PR_CallOnce(
00804     PRCallOnceType *once,
00805     PRCallOnceFN    func)
00806 {
00807     if (!_pr_initialized) _PR_ImplicitInitialization();
00808 
00809     if (!once->initialized) {
00810        if (PR_AtomicSet(&once->inProgress, 1) == 0) {
00811            once->status = (*func)();
00812            PR_Lock(mod_init.ml);
00813            once->initialized = 1;
00814            PR_NotifyAllCondVar(mod_init.cv);
00815            PR_Unlock(mod_init.ml);
00816        } else {
00817            PR_Lock(mod_init.ml);
00818            while (!once->initialized) {
00819               PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
00820             }
00821            PR_Unlock(mod_init.ml);
00822        }
00823     }
00824     return once->status;
00825 }
00826 
00827 PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg(
00828     PRCallOnceType      *once,
00829     PRCallOnceWithArgFN  func,
00830     void                *arg)
00831 {
00832     if (!_pr_initialized) _PR_ImplicitInitialization();
00833 
00834     if (!once->initialized) {
00835        if (PR_AtomicSet(&once->inProgress, 1) == 0) {
00836            once->status = (*func)(arg);
00837            PR_Lock(mod_init.ml);
00838            once->initialized = 1;
00839            PR_NotifyAllCondVar(mod_init.cv);
00840            PR_Unlock(mod_init.ml);
00841        } else {
00842            PR_Lock(mod_init.ml);
00843            while (!once->initialized) {
00844               PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
00845             }
00846            PR_Unlock(mod_init.ml);
00847        }
00848     }
00849     return once->status;
00850 }
00851 
00852 PRBool _PR_Obsolete(const char *obsolete, const char *preferred)
00853 {
00854 #if defined(DEBUG)
00855 #ifndef XP_MAC
00856     PR_fprintf(
00857         PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n",
00858         obsolete, (NULL == preferred) ? "something else" : preferred);
00859 #else
00860 #pragma unused (obsolete, preferred)
00861 #endif
00862 #endif
00863     return PR_FALSE;
00864 }  /* _PR_Obsolete */
00865 
00866 /* prinit.c */
00867 
00868