1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "primpl.h"
7 #include <ctype.h>
8 #include <string.h>
9 
10 PRLogModuleInfo *_pr_clock_lm;
11 PRLogModuleInfo *_pr_cmon_lm;
12 PRLogModuleInfo *_pr_io_lm;
13 PRLogModuleInfo *_pr_cvar_lm;
14 PRLogModuleInfo *_pr_mon_lm;
15 PRLogModuleInfo *_pr_linker_lm;
16 PRLogModuleInfo *_pr_sched_lm;
17 PRLogModuleInfo *_pr_thread_lm;
18 PRLogModuleInfo *_pr_gc_lm;
19 PRLogModuleInfo *_pr_shm_lm;
20 PRLogModuleInfo *_pr_shma_lm;
21 
22 PRFileDesc *_pr_stdin;
23 PRFileDesc *_pr_stdout;
24 PRFileDesc *_pr_stderr;
25 
26 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
27 
28 PRCList _pr_active_local_threadQ =
29     PR_INIT_STATIC_CLIST(&_pr_active_local_threadQ);
30 PRCList _pr_active_global_threadQ =
31     PR_INIT_STATIC_CLIST(&_pr_active_global_threadQ);
32 
33 _MDLock  _pr_cpuLock;           /* lock for the CPU Q */
34 PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ);
35 
36 PRUint32 _pr_utid;
37 
38 PRInt32 _pr_userActive;
39 PRInt32 _pr_systemActive;
40 PRUintn _pr_maxPTDs;
41 
42 #ifdef _PR_LOCAL_THREADS_ONLY
43 
44 struct _PRCPU   *_pr_currentCPU;
45 PRThread    *_pr_currentThread;
46 PRThread    *_pr_lastThread;
47 PRInt32     _pr_intsOff;
48 
49 #endif /* _PR_LOCAL_THREADS_ONLY */
50 
51 /* Lock protecting all "termination" condition variables of all threads */
52 PRLock *_pr_terminationCVLock;
53 
54 #endif /* !defined(_PR_PTHREADS) */
55 
56 PRLock *_pr_sleeplock;  /* used in PR_Sleep(), classic and pthreads */
57 
58 static void _PR_InitCallOnce(void);
59 
60 PRBool _pr_initialized = PR_FALSE;
61 
62 
PR_VersionCheck(const char * importedVersion)63 PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion)
64 {
65     /*
66     ** This is the secret handshake algorithm.
67     **
68     ** This release has a simple version compatibility
69     ** check algorithm.  This release is not backward
70     ** compatible with previous major releases.  It is
71     ** not compatible with future major, minor, or
72     ** patch releases.
73     */
74     int vmajor = 0, vminor = 0, vpatch = 0;
75     const char *ptr = importedVersion;
76 
77     while (isdigit(*ptr)) {
78         vmajor = 10 * vmajor + *ptr - '0';
79         ptr++;
80     }
81     if (*ptr == '.') {
82         ptr++;
83         while (isdigit(*ptr)) {
84             vminor = 10 * vminor + *ptr - '0';
85             ptr++;
86         }
87         if (*ptr == '.') {
88             ptr++;
89             while (isdigit(*ptr)) {
90                 vpatch = 10 * vpatch + *ptr - '0';
91                 ptr++;
92             }
93         }
94     }
95 
96     if (vmajor != PR_VMAJOR) {
97         return PR_FALSE;
98     }
99     if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
100         return PR_FALSE;
101     }
102     if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) {
103         return PR_FALSE;
104     }
105     return PR_TRUE;
106 }  /* PR_VersionCheck */
107 
PR_GetVersion(void)108 PR_IMPLEMENT(const char*) PR_GetVersion(void)
109 {
110     return PR_VERSION;
111 }
112 
PR_Initialized(void)113 PR_IMPLEMENT(PRBool) PR_Initialized(void)
114 {
115     return _pr_initialized;
116 }
117 
118 PRInt32 _native_threads_only = 0;
119 
120 #ifdef WINNT
_pr_SetNativeThreadsOnlyMode(void)121 static void _pr_SetNativeThreadsOnlyMode(void)
122 {
123     HMODULE mainExe;
124     PRBool *globalp;
125     char *envp;
126 
127     mainExe = GetModuleHandle(NULL);
128     PR_ASSERT(NULL != mainExe);
129     globalp = (PRBool *) GetProcAddress(mainExe, "nspr_native_threads_only");
130     if (globalp) {
131         _native_threads_only = (*globalp != PR_FALSE);
132     } else if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) {
133         _native_threads_only = (atoi(envp) == 1);
134     }
135 }
136 #endif
137 
_PR_InitStuff(void)138 static void _PR_InitStuff(void)
139 {
140 
141     if (_pr_initialized) {
142         return;
143     }
144     _pr_initialized = PR_TRUE;
145 #ifdef _PR_ZONE_ALLOCATOR
146     _PR_InitZones();
147 #endif
148 #ifdef WINNT
149     _pr_SetNativeThreadsOnlyMode();
150 #endif
151 
152 
153     (void) PR_GetPageSize();
154 
155     _pr_clock_lm = PR_NewLogModule("clock");
156     _pr_cmon_lm = PR_NewLogModule("cmon");
157     _pr_io_lm = PR_NewLogModule("io");
158     _pr_mon_lm = PR_NewLogModule("mon");
159     _pr_linker_lm = PR_NewLogModule("linker");
160     _pr_cvar_lm = PR_NewLogModule("cvar");
161     _pr_sched_lm = PR_NewLogModule("sched");
162     _pr_thread_lm = PR_NewLogModule("thread");
163     _pr_gc_lm = PR_NewLogModule("gc");
164     _pr_shm_lm = PR_NewLogModule("shm");
165     _pr_shma_lm = PR_NewLogModule("shma");
166 
167     /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */
168     _PR_MD_EARLY_INIT();
169 
170     _PR_InitLocks();
171     _PR_InitAtomic();
172     _PR_InitSegs();
173     _PR_InitStacks();
174     _PR_InitTPD();
175     _PR_InitEnv();
176     _PR_InitLayerCache();
177     _PR_InitClock();
178 
179     _pr_sleeplock = PR_NewLock();
180     PR_ASSERT(NULL != _pr_sleeplock);
181 
182     _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
183 
184 #ifdef WIN16
185     {
186         PRInt32 top;   /* artificial top of stack, win16 */
187         _pr_top_of_task_stack = (char *) &top;
188     }
189 #endif
190 
191 #ifndef _PR_GLOBAL_THREADS_ONLY
192     _PR_InitCPUs();
193 #endif
194 
195     /*
196      * XXX: call _PR_InitMem only on those platforms for which nspr implements
197      *  malloc, for now.
198      */
199 #ifdef _PR_OVERRIDE_MALLOC
200     _PR_InitMem();
201 #endif
202 
203     _PR_InitCMon();
204     _PR_InitIO();
205     _PR_InitNet();
206     _PR_InitTime();
207     _PR_InitLog();
208     _PR_InitLinker();
209     _PR_InitCallOnce();
210     _PR_InitDtoa();
211     _PR_InitMW();
212     _PR_InitRWLocks();
213 
214     nspr_InitializePRErrorTable();
215 
216     _PR_MD_FINAL_INIT();
217 }
218 
_PR_ImplicitInitialization(void)219 void _PR_ImplicitInitialization(void)
220 {
221     _PR_InitStuff();
222 
223     /* Enable interrupts */
224 #if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY)
225     _PR_MD_START_INTERRUPTS();
226 #endif
227 
228 }
229 
PR_DisableClockInterrupts(void)230 PR_IMPLEMENT(void) PR_DisableClockInterrupts(void)
231 {
232 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
233     if (!_pr_initialized) {
234         _PR_InitStuff();
235     } else {
236         _PR_MD_DISABLE_CLOCK_INTERRUPTS();
237     }
238 #endif
239 }
240 
PR_EnableClockInterrupts(void)241 PR_IMPLEMENT(void) PR_EnableClockInterrupts(void)
242 {
243 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
244     if (!_pr_initialized) {
245         _PR_InitStuff();
246     }
247     _PR_MD_ENABLE_CLOCK_INTERRUPTS();
248 #endif
249 }
250 
PR_BlockClockInterrupts(void)251 PR_IMPLEMENT(void) PR_BlockClockInterrupts(void)
252 {
253 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
254     _PR_MD_BLOCK_CLOCK_INTERRUPTS();
255 #endif
256 }
257 
PR_UnblockClockInterrupts(void)258 PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void)
259 {
260 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
261     _PR_MD_UNBLOCK_CLOCK_INTERRUPTS();
262 #endif
263 }
264 
PR_Init(PRThreadType type,PRThreadPriority priority,PRUintn maxPTDs)265 PR_IMPLEMENT(void) PR_Init(
266     PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
267 {
268     _PR_ImplicitInitialization();
269 }
270 
PR_Initialize(PRPrimordialFn prmain,PRIntn argc,char ** argv,PRUintn maxPTDs)271 PR_IMPLEMENT(PRIntn) PR_Initialize(
272     PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs)
273 {
274     PRIntn rv;
275     _PR_ImplicitInitialization();
276     rv = prmain(argc, argv);
277     PR_Cleanup();
278     return rv;
279 }  /* PR_Initialize */
280 
281 /*
282  *-----------------------------------------------------------------------
283  *
284  * _PR_CleanupBeforeExit --
285  *
286  *   Perform the cleanup work before exiting the process.
287  *   We first do the cleanup generic to all platforms.  Then
288  *   we call _PR_MD_CLEANUP_BEFORE_EXIT(), where platform-dependent
289  *   cleanup is done.  This function is used by PR_Cleanup().
290  *
291  * See also: PR_Cleanup().
292  *
293  *-----------------------------------------------------------------------
294  */
295 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
296 /* see ptthread.c */
297 #else
298 static void
_PR_CleanupBeforeExit(void)299 _PR_CleanupBeforeExit(void)
300 {
301     /*
302     Do not make any calls here other than to destroy resources.  For example,
303     do not make any calls that eventually may end up in PR_Lock.  Because the
304     thread is destroyed, can not access current thread any more.
305     */
306     _PR_CleanupTPD();
307     if (_pr_terminationCVLock)
308         /*
309          * In light of the comment above, this looks real suspicious.
310          * I'd go so far as to say it's just a problem waiting to happen.
311          */
312     {
313         PR_DestroyLock(_pr_terminationCVLock);
314     }
315 
316     _PR_MD_CLEANUP_BEFORE_EXIT();
317 }
318 #endif /* defined(_PR_PTHREADS) */
319 
320 /*
321  *----------------------------------------------------------------------
322  *
323  * PR_Cleanup --
324  *
325  *   Perform a graceful shutdown of the NSPR runtime.  PR_Cleanup() may
326  *   only be called from the primordial thread, typically at the
327  *   end of the main() function.  It returns when it has completed
328  *   its platform-dependent duty and the process must not make any other
329  *   NSPR library calls prior to exiting from main().
330  *
331  *   PR_Cleanup() first blocks the primordial thread until all the
332  *   other user (non-system) threads, if any, have terminated.
333  *   Then it performs cleanup in preparation for exiting the process.
334  *   PR_Cleanup() does not exit the primordial thread (which would
335  *   in turn exit the process).
336  *
337  *   PR_Cleanup() only responds when it is called by the primordial
338  *   thread. Calls by any other thread are silently ignored.
339  *
340  * See also: PR_ExitProcess()
341  *
342  *----------------------------------------------------------------------
343  */
344 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
345 /* see ptthread.c */
346 #else
347 
PR_Cleanup()348 PR_IMPLEMENT(PRStatus) PR_Cleanup()
349 {
350     PRThread *me = PR_GetCurrentThread();
351     PR_ASSERT((NULL != me) && (me->flags & _PR_PRIMORDIAL));
352     if ((NULL != me) && (me->flags & _PR_PRIMORDIAL))
353     {
354         PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
355 
356         /*
357          * No more recycling of threads
358          */
359         _pr_recycleThreads = 0;
360 
361         /*
362          * Wait for all other user (non-system/daemon) threads
363          * to terminate.
364          */
365         PR_Lock(_pr_activeLock);
366         while (_pr_userActive > _pr_primordialExitCount) {
367             PR_WaitCondVar(_pr_primordialExitCVar, PR_INTERVAL_NO_TIMEOUT);
368         }
369         if (me->flags & _PR_SYSTEM) {
370             _pr_systemActive--;
371         } else {
372             _pr_userActive--;
373         }
374         PR_Unlock(_pr_activeLock);
375 
376         _PR_MD_EARLY_CLEANUP();
377 
378         _PR_CleanupMW();
379         _PR_CleanupTime();
380         _PR_CleanupDtoa();
381         _PR_CleanupCallOnce();
382         _PR_ShutdownLinker();
383         _PR_CleanupNet();
384         _PR_CleanupIO();
385         /* Release the primordial thread's private data, etc. */
386         _PR_CleanupThread(me);
387 
388         _PR_MD_STOP_INTERRUPTS();
389 
390         PR_LOG(_pr_thread_lm, PR_LOG_MIN,
391                ("PR_Cleanup: clean up before destroying thread"));
392         _PR_LogCleanup();
393 
394         /*
395          * This part should look like the end of _PR_NativeRunThread
396          * and _PR_UserRunThread.
397          */
398         if (_PR_IS_NATIVE_THREAD(me)) {
399             _PR_MD_EXIT_THREAD(me);
400             _PR_NativeDestroyThread(me);
401         } else {
402             _PR_UserDestroyThread(me);
403             PR_DELETE(me->stack);
404             PR_DELETE(me);
405         }
406 
407         /*
408          * XXX: We are freeing the heap memory here so that Purify won't
409          * complain, but we should also free other kinds of resources
410          * that are allocated by the _PR_InitXXX() functions.
411          * Ideally, for each _PR_InitXXX(), there should be a corresponding
412          * _PR_XXXCleanup() that we can call here.
413          */
414 #ifdef WINNT
415         _PR_CleanupCPUs();
416 #endif
417         _PR_CleanupThreads();
418         _PR_CleanupCMon();
419         PR_DestroyLock(_pr_sleeplock);
420         _pr_sleeplock = NULL;
421         _PR_CleanupLayerCache();
422         _PR_CleanupEnv();
423         _PR_CleanupStacks();
424         _PR_CleanupBeforeExit();
425         _pr_initialized = PR_FALSE;
426         return PR_SUCCESS;
427     }
428     return PR_FAILURE;
429 }
430 #endif /* defined(_PR_PTHREADS) */
431 
432 /*
433  *------------------------------------------------------------------------
434  * PR_ProcessExit --
435  *
436  *   Cause an immediate, nongraceful, forced termination of the process.
437  *   It takes a PRIntn argument, which is the exit status code of the
438  *   process.
439  *
440  * See also: PR_Cleanup()
441  *
442  *------------------------------------------------------------------------
443  */
444 
445 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
446 /* see ptthread.c */
447 #else
PR_ProcessExit(PRIntn status)448 PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
449 {
450     _PR_MD_EXIT(status);
451 }
452 
453 #endif /* defined(_PR_PTHREADS) */
454 
455 PR_IMPLEMENT(PRProcessAttr *)
PR_NewProcessAttr(void)456 PR_NewProcessAttr(void)
457 {
458     PRProcessAttr *attr;
459 
460     attr = PR_NEWZAP(PRProcessAttr);
461     if (!attr) {
462         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
463     }
464     return attr;
465 }
466 
467 PR_IMPLEMENT(void)
PR_ResetProcessAttr(PRProcessAttr * attr)468 PR_ResetProcessAttr(PRProcessAttr *attr)
469 {
470     PR_FREEIF(attr->currentDirectory);
471     PR_FREEIF(attr->fdInheritBuffer);
472     memset(attr, 0, sizeof(*attr));
473 }
474 
475 PR_IMPLEMENT(void)
PR_DestroyProcessAttr(PRProcessAttr * attr)476 PR_DestroyProcessAttr(PRProcessAttr *attr)
477 {
478     PR_FREEIF(attr->currentDirectory);
479     PR_FREEIF(attr->fdInheritBuffer);
480     PR_DELETE(attr);
481 }
482 
483 PR_IMPLEMENT(void)
PR_ProcessAttrSetStdioRedirect(PRProcessAttr * attr,PRSpecialFD stdioFd,PRFileDesc * redirectFd)484 PR_ProcessAttrSetStdioRedirect(
485     PRProcessAttr *attr,
486     PRSpecialFD stdioFd,
487     PRFileDesc *redirectFd)
488 {
489     switch (stdioFd) {
490         case PR_StandardInput:
491             attr->stdinFd = redirectFd;
492             break;
493         case PR_StandardOutput:
494             attr->stdoutFd = redirectFd;
495             break;
496         case PR_StandardError:
497             attr->stderrFd = redirectFd;
498             break;
499         default:
500             PR_ASSERT(0);
501     }
502 }
503 
504 /*
505  * OBSOLETE
506  */
507 PR_IMPLEMENT(void)
PR_SetStdioRedirect(PRProcessAttr * attr,PRSpecialFD stdioFd,PRFileDesc * redirectFd)508 PR_SetStdioRedirect(
509     PRProcessAttr *attr,
510     PRSpecialFD stdioFd,
511     PRFileDesc *redirectFd)
512 {
513 #if defined(DEBUG)
514     static PRBool warn = PR_TRUE;
515     if (warn) {
516         warn = _PR_Obsolete("PR_SetStdioRedirect()",
517                             "PR_ProcessAttrSetStdioRedirect()");
518     }
519 #endif
520     PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd);
521 }
522 
523 PR_IMPLEMENT(PRStatus)
PR_ProcessAttrSetCurrentDirectory(PRProcessAttr * attr,const char * dir)524 PR_ProcessAttrSetCurrentDirectory(
525     PRProcessAttr *attr,
526     const char *dir)
527 {
528     PR_FREEIF(attr->currentDirectory);
529     attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1);
530     if (!attr->currentDirectory) {
531         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
532         return PR_FAILURE;
533     }
534     strcpy(attr->currentDirectory, dir);
535     return PR_SUCCESS;
536 }
537 
538 PR_IMPLEMENT(PRStatus)
PR_ProcessAttrSetInheritableFD(PRProcessAttr * attr,PRFileDesc * fd,const char * name)539 PR_ProcessAttrSetInheritableFD(
540     PRProcessAttr *attr,
541     PRFileDesc *fd,
542     const char *name)
543 {
544     /* We malloc the fd inherit buffer in multiples of this number. */
545 #define FD_INHERIT_BUFFER_INCR 128
546     /* The length of "NSPR_INHERIT_FDS=" */
547 #define NSPR_INHERIT_FDS_STRLEN 17
548     /* The length of osfd (PROsfd) printed in hexadecimal with 0x prefix */
549 #ifdef _WIN64
550 #define OSFD_STRLEN 18
551 #else
552 #define OSFD_STRLEN 10
553 #endif
554     /* The length of fd type (PRDescType) printed in decimal */
555 #define FD_TYPE_STRLEN 1
556     PRSize newSize;
557     int remainder;
558     char *newBuffer;
559     int nwritten;
560     char *cur;
561     int freeSize;
562 
563     if (fd->identity != PR_NSPR_IO_LAYER) {
564         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
565         return PR_FAILURE;
566     }
567     if (fd->secret->inheritable == _PR_TRI_UNKNOWN) {
568         _PR_MD_QUERY_FD_INHERITABLE(fd);
569     }
570     if (fd->secret->inheritable != _PR_TRI_TRUE) {
571         PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0);
572         return PR_FAILURE;
573     }
574 
575     /*
576      * We also need to account for the : separators and the
577      * terminating null byte.
578      */
579     if (NULL == attr->fdInheritBuffer) {
580         /* The first time, we print "NSPR_INHERIT_FDS=<name>:<type>:<val>" */
581         newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name)
582                   + FD_TYPE_STRLEN + OSFD_STRLEN + 2 + 1;
583     } else {
584         /* At other times, we print ":<name>:<type>:<val>" */
585         newSize = attr->fdInheritBufferUsed + strlen(name)
586                   + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1;
587     }
588     if (newSize > attr->fdInheritBufferSize) {
589         /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */
590         remainder = newSize % FD_INHERIT_BUFFER_INCR;
591         if (remainder != 0) {
592             newSize += (FD_INHERIT_BUFFER_INCR - remainder);
593         }
594         if (NULL == attr->fdInheritBuffer) {
595             newBuffer = (char *) PR_MALLOC(newSize);
596         } else {
597             newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize);
598         }
599         if (NULL == newBuffer) {
600             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
601             return PR_FAILURE;
602         }
603         attr->fdInheritBuffer = newBuffer;
604         attr->fdInheritBufferSize = newSize;
605     }
606     cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed;
607     freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed;
608     if (0 == attr->fdInheritBufferUsed) {
609         nwritten = PR_snprintf(cur, freeSize,
610                                "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD,
611                                name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
612     } else {
613         nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD,
614                                name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
615     }
616     attr->fdInheritBufferUsed += nwritten;
617     return PR_SUCCESS;
618 }
619 
PR_GetInheritedFD(const char * name)620 PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD(
621     const char *name)
622 {
623     PRFileDesc *fd;
624     const char *envVar;
625     const char *ptr;
626     int len = strlen(name);
627     PROsfd osfd;
628     int nColons;
629     PRIntn fileType;
630 
631     envVar = PR_GetEnv("NSPR_INHERIT_FDS");
632     if (NULL == envVar || '\0' == envVar[0]) {
633         PR_SetError(PR_UNKNOWN_ERROR, 0);
634         return NULL;
635     }
636 
637     ptr = envVar;
638     while (1) {
639         if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) {
640             ptr += len + 1;
641             if (PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd) != 2) {
642                 PR_SetError(PR_UNKNOWN_ERROR, 0);
643                 return NULL;
644             }
645             switch ((PRDescType)fileType) {
646                 case PR_DESC_FILE:
647                     fd = PR_ImportFile(osfd);
648                     break;
649                 case PR_DESC_PIPE:
650                     fd = PR_ImportPipe(osfd);
651                     break;
652                 case PR_DESC_SOCKET_TCP:
653                     fd = PR_ImportTCPSocket(osfd);
654                     break;
655                 case PR_DESC_SOCKET_UDP:
656                     fd = PR_ImportUDPSocket(osfd);
657                     break;
658                 default:
659                     PR_ASSERT(0);
660                     PR_SetError(PR_UNKNOWN_ERROR, 0);
661                     fd = NULL;
662                     break;
663             }
664             if (fd) {
665                 /*
666                  * An inherited FD is inheritable by default.
667                  * The child process needs to call PR_SetFDInheritable
668                  * to make it non-inheritable if so desired.
669                  */
670                 fd->secret->inheritable = _PR_TRI_TRUE;
671             }
672             return fd;
673         }
674         /* Skip three colons */
675         nColons = 0;
676         while (*ptr) {
677             if (*ptr == ':') {
678                 if (++nColons == 3) {
679                     break;
680                 }
681             }
682             ptr++;
683         }
684         if (*ptr == '\0') {
685             PR_SetError(PR_UNKNOWN_ERROR, 0);
686             return NULL;
687         }
688         ptr++;
689     }
690 }
691 
PR_CreateProcess(const char * path,char * const * argv,char * const * envp,const PRProcessAttr * attr)692 PR_IMPLEMENT(PRProcess*) PR_CreateProcess(
693     const char *path,
694     char *const *argv,
695     char *const *envp,
696     const PRProcessAttr *attr)
697 {
698     return _PR_MD_CREATE_PROCESS(path, argv, envp, attr);
699 }  /* PR_CreateProcess */
700 
PR_CreateProcessDetached(const char * path,char * const * argv,char * const * envp,const PRProcessAttr * attr)701 PR_IMPLEMENT(PRStatus) PR_CreateProcessDetached(
702     const char *path,
703     char *const *argv,
704     char *const *envp,
705     const PRProcessAttr *attr)
706 {
707     PRProcess *process;
708     PRStatus rv;
709 
710     process = PR_CreateProcess(path, argv, envp, attr);
711     if (NULL == process) {
712         return PR_FAILURE;
713     }
714     rv = PR_DetachProcess(process);
715     PR_ASSERT(PR_SUCCESS == rv);
716     if (rv == PR_FAILURE) {
717         PR_DELETE(process);
718         return PR_FAILURE;
719     }
720     return PR_SUCCESS;
721 }
722 
PR_DetachProcess(PRProcess * process)723 PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process)
724 {
725     return _PR_MD_DETACH_PROCESS(process);
726 }
727 
PR_WaitProcess(PRProcess * process,PRInt32 * exitCode)728 PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode)
729 {
730     return _PR_MD_WAIT_PROCESS(process, exitCode);
731 }  /* PR_WaitProcess */
732 
PR_KillProcess(PRProcess * process)733 PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process)
734 {
735     return _PR_MD_KILL_PROCESS(process);
736 }
737 
738 /*
739  ********************************************************************
740  *
741  * Module initialization
742  *
743  ********************************************************************
744  */
745 
746 static struct {
747     PRLock *ml;
748     PRCondVar *cv;
749 } mod_init;
750 
_PR_InitCallOnce(void)751 static void _PR_InitCallOnce(void) {
752     mod_init.ml = PR_NewLock();
753     PR_ASSERT(NULL != mod_init.ml);
754     mod_init.cv = PR_NewCondVar(mod_init.ml);
755     PR_ASSERT(NULL != mod_init.cv);
756 }
757 
_PR_CleanupCallOnce()758 void _PR_CleanupCallOnce()
759 {
760     PR_DestroyLock(mod_init.ml);
761     mod_init.ml = NULL;
762     PR_DestroyCondVar(mod_init.cv);
763     mod_init.cv = NULL;
764 }
765 
PR_CallOnce(PRCallOnceType * once,PRCallOnceFN func)766 PR_IMPLEMENT(PRStatus) PR_CallOnce(
767     PRCallOnceType *once,
768     PRCallOnceFN    func)
769 {
770     if (!_pr_initialized) {
771         _PR_ImplicitInitialization();
772     }
773 
774     PR_Lock(mod_init.ml);
775     PRIntn initialized = once->initialized;
776     PRStatus status = once->status;
777     PR_Unlock(mod_init.ml);
778     if (!initialized) {
779         if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) {
780             status = (*func)();
781             PR_Lock(mod_init.ml);
782             once->status = status;
783             once->initialized = 1;
784             PR_NotifyAllCondVar(mod_init.cv);
785             PR_Unlock(mod_init.ml);
786         } else {
787             PR_Lock(mod_init.ml);
788             while (!once->initialized) {
789                 PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
790             }
791             status = once->status;
792             PR_Unlock(mod_init.ml);
793             if (PR_SUCCESS != status) {
794                 PR_SetError(PR_CALL_ONCE_ERROR, 0);
795             }
796         }
797         return status;
798     }
799     if (PR_SUCCESS != status) {
800         PR_SetError(PR_CALL_ONCE_ERROR, 0);
801     }
802     return status;
803 }
804 
PR_CallOnceWithArg(PRCallOnceType * once,PRCallOnceWithArgFN func,void * arg)805 PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg(
806     PRCallOnceType      *once,
807     PRCallOnceWithArgFN  func,
808     void                *arg)
809 {
810     if (!_pr_initialized) {
811         _PR_ImplicitInitialization();
812     }
813 
814     PR_Lock(mod_init.ml);
815     PRIntn initialized = once->initialized;
816     PRStatus status = once->status;
817     PR_Unlock(mod_init.ml);
818     if (!initialized) {
819         if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) {
820             status = (*func)(arg);
821             PR_Lock(mod_init.ml);
822             once->status = status;
823             once->initialized = 1;
824             PR_NotifyAllCondVar(mod_init.cv);
825             PR_Unlock(mod_init.ml);
826         } else {
827             PR_Lock(mod_init.ml);
828             while (!once->initialized) {
829                 PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
830             }
831             status = once->status;
832             PR_Unlock(mod_init.ml);
833             if (PR_SUCCESS != status) {
834                 PR_SetError(PR_CALL_ONCE_ERROR, 0);
835             }
836         }
837         return status;
838     }
839     if (PR_SUCCESS != status) {
840         PR_SetError(PR_CALL_ONCE_ERROR, 0);
841     }
842     return status;
843 }
844 
_PR_Obsolete(const char * obsolete,const char * preferred)845 PRBool _PR_Obsolete(const char *obsolete, const char *preferred)
846 {
847 #if defined(DEBUG)
848     PR_fprintf(
849         PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n",
850         obsolete, (NULL == preferred) ? "something else" : preferred);
851 #endif
852     return PR_FALSE;
853 }  /* _PR_Obsolete */
854 
855 /* prinit.c */
856 
857 
858