Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / nsprpub / pr / src / misc / prinit.c
blobd36a7dee26d3889b59a083b72b0b3787d9734a53
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/. */
6 #include "primpl.h"
7 #include <ctype.h>
8 #include <string.h>
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;
22 PRFileDesc* _pr_stdin;
23 PRFileDesc* _pr_stdout;
24 PRFileDesc* _pr_stderr;
26 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
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);
33 _MDLock _pr_cpuLock; /* lock for the CPU Q */
34 PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ);
36 PRUint32 _pr_utid;
38 PRInt32 _pr_userActive;
39 PRInt32 _pr_systemActive;
40 PRUintn _pr_maxPTDs;
42 # ifdef _PR_LOCAL_THREADS_ONLY
44 struct _PRCPU* _pr_currentCPU;
45 PRThread* _pr_currentThread;
46 PRThread* _pr_lastThread;
47 PRInt32 _pr_intsOff;
49 # endif /* _PR_LOCAL_THREADS_ONLY */
51 /* Lock protecting all "termination" condition variables of all threads */
52 PRLock* _pr_terminationCVLock;
54 #endif /* !defined(_PR_PTHREADS) */
56 PRLock* _pr_sleeplock; /* used in PR_Sleep(), classic and pthreads */
58 static void _PR_InitCallOnce(void);
60 PRBool _pr_initialized = PR_FALSE;
62 PR_IMPLEMENT(PRBool) PR_VersionCheck(const char* importedVersion) {
64 ** This is the secret handshake algorithm.
66 ** This release has a simple version compatibility
67 ** check algorithm. This release is not backward
68 ** compatible with previous major releases. It is
69 ** not compatible with future major, minor, or
70 ** patch releases.
72 int vmajor = 0, vminor = 0, vpatch = 0;
73 const char* ptr = importedVersion;
75 while (isdigit(*ptr)) {
76 vmajor = 10 * vmajor + *ptr - '0';
77 ptr++;
79 if (*ptr == '.') {
80 ptr++;
81 while (isdigit(*ptr)) {
82 vminor = 10 * vminor + *ptr - '0';
83 ptr++;
85 if (*ptr == '.') {
86 ptr++;
87 while (isdigit(*ptr)) {
88 vpatch = 10 * vpatch + *ptr - '0';
89 ptr++;
94 if (vmajor != PR_VMAJOR) {
95 return PR_FALSE;
97 if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
98 return PR_FALSE;
100 if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) {
101 return PR_FALSE;
103 return PR_TRUE;
104 } /* PR_VersionCheck */
106 PR_IMPLEMENT(const char*) PR_GetVersion(void) { return PR_VERSION; }
108 PR_IMPLEMENT(PRBool) PR_Initialized(void) { return _pr_initialized; }
110 PRInt32 _native_threads_only = 0;
112 #ifdef WINNT
113 static void _pr_SetNativeThreadsOnlyMode(void) {
114 HMODULE mainExe;
115 PRBool* globalp;
116 char* envp;
118 mainExe = GetModuleHandle(NULL);
119 PR_ASSERT(NULL != mainExe);
120 globalp = (PRBool*)GetProcAddress(mainExe, "nspr_native_threads_only");
121 if (globalp) {
122 _native_threads_only = (*globalp != PR_FALSE);
123 } else if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) {
124 _native_threads_only = (atoi(envp) == 1);
127 #endif
129 static void _PR_InitStuff(void) {
130 if (_pr_initialized) {
131 return;
133 _pr_initialized = PR_TRUE;
134 #ifdef _PR_ZONE_ALLOCATOR
135 _PR_InitZones();
136 #endif
137 #ifdef WINNT
138 _pr_SetNativeThreadsOnlyMode();
139 #endif
141 (void)PR_GetPageSize();
143 _pr_clock_lm = PR_NewLogModule("clock");
144 _pr_cmon_lm = PR_NewLogModule("cmon");
145 _pr_io_lm = PR_NewLogModule("io");
146 _pr_mon_lm = PR_NewLogModule("mon");
147 _pr_linker_lm = PR_NewLogModule("linker");
148 _pr_cvar_lm = PR_NewLogModule("cvar");
149 _pr_sched_lm = PR_NewLogModule("sched");
150 _pr_thread_lm = PR_NewLogModule("thread");
151 _pr_gc_lm = PR_NewLogModule("gc");
152 _pr_shm_lm = PR_NewLogModule("shm");
153 _pr_shma_lm = PR_NewLogModule("shma");
155 /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */
156 _PR_MD_EARLY_INIT();
158 _PR_InitLocks();
159 _PR_InitAtomic();
160 _PR_InitSegs();
161 _PR_InitStacks();
162 _PR_InitTPD();
163 _PR_InitEnv();
164 _PR_InitLayerCache();
165 _PR_InitClock();
167 _pr_sleeplock = PR_NewLock();
168 PR_ASSERT(NULL != _pr_sleeplock);
170 _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
172 #ifndef _PR_GLOBAL_THREADS_ONLY
173 _PR_InitCPUs();
174 #endif
177 * XXX: call _PR_InitMem only on those platforms for which nspr implements
178 * malloc, for now.
180 #ifdef _PR_OVERRIDE_MALLOC
181 _PR_InitMem();
182 #endif
184 _PR_InitCMon();
185 _PR_InitIO();
186 _PR_InitNet();
187 _PR_InitTime();
188 _PR_InitLog();
189 _PR_InitLinker();
190 _PR_InitCallOnce();
191 _PR_InitDtoa();
192 _PR_InitMW();
193 _PR_InitRWLocks();
195 nspr_InitializePRErrorTable();
197 _PR_MD_FINAL_INIT();
200 void _PR_ImplicitInitialization(void) {
201 _PR_InitStuff();
203 /* Enable interrupts */
204 #if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY)
205 _PR_MD_START_INTERRUPTS();
206 #endif
209 PR_IMPLEMENT(void) PR_DisableClockInterrupts(void) {
210 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
211 if (!_pr_initialized) {
212 _PR_InitStuff();
213 } else {
214 _PR_MD_DISABLE_CLOCK_INTERRUPTS();
216 #endif
219 PR_IMPLEMENT(void) PR_EnableClockInterrupts(void) {
220 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
221 if (!_pr_initialized) {
222 _PR_InitStuff();
224 _PR_MD_ENABLE_CLOCK_INTERRUPTS();
225 #endif
228 PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) {
229 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
230 _PR_MD_BLOCK_CLOCK_INTERRUPTS();
231 #endif
234 PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void) {
235 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
236 _PR_MD_UNBLOCK_CLOCK_INTERRUPTS();
237 #endif
240 PR_IMPLEMENT(void)
241 PR_Init(PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) {
242 _PR_ImplicitInitialization();
245 PR_IMPLEMENT(PRIntn)
246 PR_Initialize(PRPrimordialFn prmain, PRIntn argc, char** argv,
247 PRUintn maxPTDs) {
248 PRIntn rv;
249 _PR_ImplicitInitialization();
250 rv = prmain(argc, argv);
251 PR_Cleanup();
252 return rv;
253 } /* PR_Initialize */
256 *-----------------------------------------------------------------------
258 * _PR_CleanupBeforeExit --
260 * Perform the cleanup work before exiting the process.
261 * We first do the cleanup generic to all platforms. Then
262 * we call _PR_MD_CLEANUP_BEFORE_EXIT(), where platform-dependent
263 * cleanup is done. This function is used by PR_Cleanup().
265 * See also: PR_Cleanup().
267 *-----------------------------------------------------------------------
269 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
270 /* see ptthread.c */
271 #else
272 static void _PR_CleanupBeforeExit(void) {
274 Do not make any calls here other than to destroy resources. For example,
275 do not make any calls that eventually may end up in PR_Lock. Because the
276 thread is destroyed, can not access current thread any more.
278 _PR_CleanupTPD();
279 if (_pr_terminationCVLock)
281 * In light of the comment above, this looks real suspicious.
282 * I'd go so far as to say it's just a problem waiting to happen.
285 PR_DestroyLock(_pr_terminationCVLock);
288 _PR_MD_CLEANUP_BEFORE_EXIT();
290 #endif /* defined(_PR_PTHREADS) */
293 *----------------------------------------------------------------------
295 * PR_Cleanup --
297 * Perform a graceful shutdown of the NSPR runtime. PR_Cleanup() may
298 * only be called from the primordial thread, typically at the
299 * end of the main() function. It returns when it has completed
300 * its platform-dependent duty and the process must not make any other
301 * NSPR library calls prior to exiting from main().
303 * PR_Cleanup() first blocks the primordial thread until all the
304 * other user (non-system) threads, if any, have terminated.
305 * Then it performs cleanup in preparation for exiting the process.
306 * PR_Cleanup() does not exit the primordial thread (which would
307 * in turn exit the process).
309 * PR_Cleanup() only responds when it is called by the primordial
310 * thread. Calls by any other thread are silently ignored.
312 * See also: PR_ExitProcess()
314 *----------------------------------------------------------------------
316 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
317 /* see ptthread.c */
318 #else
320 PR_IMPLEMENT(PRStatus) PR_Cleanup() {
321 PRThread* me = PR_GetCurrentThread();
322 PR_ASSERT((NULL != me) && (me->flags & _PR_PRIMORDIAL));
323 if ((NULL != me) && (me->flags & _PR_PRIMORDIAL)) {
324 PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
327 * No more recycling of threads
329 _pr_recycleThreads = 0;
332 * Wait for all other user (non-system/daemon) threads
333 * to terminate.
335 PR_Lock(_pr_activeLock);
336 while (_pr_userActive > _pr_primordialExitCount) {
337 PR_WaitCondVar(_pr_primordialExitCVar, PR_INTERVAL_NO_TIMEOUT);
339 if (me->flags & _PR_SYSTEM) {
340 _pr_systemActive--;
341 } else {
342 _pr_userActive--;
344 PR_Unlock(_pr_activeLock);
346 _PR_MD_EARLY_CLEANUP();
348 _PR_CleanupMW();
349 _PR_CleanupTime();
350 _PR_CleanupDtoa();
351 _PR_CleanupCallOnce();
352 _PR_ShutdownLinker();
353 _PR_CleanupNet();
354 _PR_CleanupIO();
355 /* Release the primordial thread's private data, etc. */
356 _PR_CleanupThread(me);
358 _PR_MD_STOP_INTERRUPTS();
360 PR_LOG(_pr_thread_lm, PR_LOG_MIN,
361 ("PR_Cleanup: clean up before destroying thread"));
362 _PR_LogCleanup();
365 * This part should look like the end of _PR_NativeRunThread
366 * and _PR_UserRunThread.
368 if (_PR_IS_NATIVE_THREAD(me)) {
369 _PR_MD_EXIT_THREAD(me);
370 _PR_NativeDestroyThread(me);
371 } else {
372 _PR_UserDestroyThread(me);
373 PR_DELETE(me->stack);
374 PR_DELETE(me);
378 * XXX: We are freeing the heap memory here so that Purify won't
379 * complain, but we should also free other kinds of resources
380 * that are allocated by the _PR_InitXXX() functions.
381 * Ideally, for each _PR_InitXXX(), there should be a corresponding
382 * _PR_XXXCleanup() that we can call here.
384 # ifdef WINNT
385 _PR_CleanupCPUs();
386 # endif
387 _PR_CleanupThreads();
388 _PR_CleanupCMon();
389 PR_DestroyLock(_pr_sleeplock);
390 _pr_sleeplock = NULL;
391 _PR_CleanupLayerCache();
392 _PR_CleanupEnv();
393 _PR_CleanupStacks();
394 _PR_CleanupBeforeExit();
395 _pr_initialized = PR_FALSE;
396 return PR_SUCCESS;
398 return PR_FAILURE;
400 #endif /* defined(_PR_PTHREADS) */
403 *------------------------------------------------------------------------
404 * PR_ProcessExit --
406 * Cause an immediate, nongraceful, forced termination of the process.
407 * It takes a PRIntn argument, which is the exit status code of the
408 * process.
410 * See also: PR_Cleanup()
412 *------------------------------------------------------------------------
415 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
416 /* see ptthread.c */
417 #else
418 PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) { _PR_MD_EXIT(status); }
420 #endif /* defined(_PR_PTHREADS) */
422 PR_IMPLEMENT(PRProcessAttr*)
423 PR_NewProcessAttr(void) {
424 PRProcessAttr* attr;
426 attr = PR_NEWZAP(PRProcessAttr);
427 if (!attr) {
428 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
430 return attr;
433 PR_IMPLEMENT(void)
434 PR_ResetProcessAttr(PRProcessAttr* attr) {
435 PR_FREEIF(attr->currentDirectory);
436 PR_FREEIF(attr->fdInheritBuffer);
437 memset(attr, 0, sizeof(*attr));
440 PR_IMPLEMENT(void)
441 PR_DestroyProcessAttr(PRProcessAttr* attr) {
442 PR_FREEIF(attr->currentDirectory);
443 PR_FREEIF(attr->fdInheritBuffer);
444 PR_DELETE(attr);
447 PR_IMPLEMENT(void)
448 PR_ProcessAttrSetStdioRedirect(PRProcessAttr* attr, PRSpecialFD stdioFd,
449 PRFileDesc* redirectFd) {
450 switch (stdioFd) {
451 case PR_StandardInput:
452 attr->stdinFd = redirectFd;
453 break;
454 case PR_StandardOutput:
455 attr->stdoutFd = redirectFd;
456 break;
457 case PR_StandardError:
458 attr->stderrFd = redirectFd;
459 break;
460 default:
461 PR_ASSERT(0);
466 * OBSOLETE
468 PR_IMPLEMENT(void)
469 PR_SetStdioRedirect(PRProcessAttr* attr, PRSpecialFD stdioFd,
470 PRFileDesc* redirectFd) {
471 #if defined(DEBUG)
472 static PRBool warn = PR_TRUE;
473 if (warn) {
474 warn = _PR_Obsolete("PR_SetStdioRedirect()",
475 "PR_ProcessAttrSetStdioRedirect()");
477 #endif
478 PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd);
481 PR_IMPLEMENT(PRStatus)
482 PR_ProcessAttrSetCurrentDirectory(PRProcessAttr* attr, const char* dir) {
483 PR_FREEIF(attr->currentDirectory);
484 attr->currentDirectory = (char*)PR_MALLOC(strlen(dir) + 1);
485 if (!attr->currentDirectory) {
486 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
487 return PR_FAILURE;
489 strcpy(attr->currentDirectory, dir);
490 return PR_SUCCESS;
493 PR_IMPLEMENT(PRStatus)
494 PR_ProcessAttrSetInheritableFD(PRProcessAttr* attr, PRFileDesc* fd,
495 const char* name) {
496 /* We malloc the fd inherit buffer in multiples of this number. */
497 #define FD_INHERIT_BUFFER_INCR 128
498 /* The length of "NSPR_INHERIT_FDS=" */
499 #define NSPR_INHERIT_FDS_STRLEN 17
500 /* The length of osfd (PROsfd) printed in hexadecimal with 0x prefix */
501 #ifdef _WIN64
502 # define OSFD_STRLEN 18
503 #else
504 # define OSFD_STRLEN 10
505 #endif
506 /* The length of fd type (PRDescType) printed in decimal */
507 #define FD_TYPE_STRLEN 1
508 PRSize newSize;
509 int remainder;
510 char* newBuffer;
511 int nwritten;
512 char* cur;
513 int freeSize;
515 if (fd->identity != PR_NSPR_IO_LAYER) {
516 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
517 return PR_FAILURE;
519 if (fd->secret->inheritable == _PR_TRI_UNKNOWN) {
520 _PR_MD_QUERY_FD_INHERITABLE(fd);
522 if (fd->secret->inheritable != _PR_TRI_TRUE) {
523 PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0);
524 return PR_FAILURE;
528 * We also need to account for the : separators and the
529 * terminating null byte.
531 if (NULL == attr->fdInheritBuffer) {
532 /* The first time, we print "NSPR_INHERIT_FDS=<name>:<type>:<val>" */
533 newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name) + FD_TYPE_STRLEN +
534 OSFD_STRLEN + 2 + 1;
535 } else {
536 /* At other times, we print ":<name>:<type>:<val>" */
537 newSize = attr->fdInheritBufferUsed + strlen(name) + FD_TYPE_STRLEN +
538 OSFD_STRLEN + 3 + 1;
540 if (newSize > attr->fdInheritBufferSize) {
541 /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */
542 remainder = newSize % FD_INHERIT_BUFFER_INCR;
543 if (remainder != 0) {
544 newSize += (FD_INHERIT_BUFFER_INCR - remainder);
546 if (NULL == attr->fdInheritBuffer) {
547 newBuffer = (char*)PR_MALLOC(newSize);
548 } else {
549 newBuffer = (char*)PR_REALLOC(attr->fdInheritBuffer, newSize);
551 if (NULL == newBuffer) {
552 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
553 return PR_FAILURE;
555 attr->fdInheritBuffer = newBuffer;
556 attr->fdInheritBufferSize = newSize;
558 cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed;
559 freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed;
560 if (0 == attr->fdInheritBufferUsed) {
561 nwritten =
562 PR_snprintf(cur, freeSize, "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD,
563 name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
564 } else {
565 nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD, name,
566 (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
568 attr->fdInheritBufferUsed += nwritten;
569 return PR_SUCCESS;
572 PR_IMPLEMENT(PRFileDesc*) PR_GetInheritedFD(const char* name) {
573 PRFileDesc* fd;
574 const char* envVar;
575 const char* ptr;
576 int len = strlen(name);
577 PROsfd osfd;
578 int nColons;
579 PRIntn fileType;
581 envVar = PR_GetEnv("NSPR_INHERIT_FDS");
582 if (NULL == envVar || '\0' == envVar[0]) {
583 PR_SetError(PR_UNKNOWN_ERROR, 0);
584 return NULL;
587 ptr = envVar;
588 while (1) {
589 if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) {
590 ptr += len + 1;
591 if (PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd) != 2) {
592 PR_SetError(PR_UNKNOWN_ERROR, 0);
593 return NULL;
595 switch ((PRDescType)fileType) {
596 case PR_DESC_FILE:
597 fd = PR_ImportFile(osfd);
598 break;
599 case PR_DESC_PIPE:
600 fd = PR_ImportPipe(osfd);
601 break;
602 case PR_DESC_SOCKET_TCP:
603 fd = PR_ImportTCPSocket(osfd);
604 break;
605 case PR_DESC_SOCKET_UDP:
606 fd = PR_ImportUDPSocket(osfd);
607 break;
608 default:
609 PR_ASSERT(0);
610 PR_SetError(PR_UNKNOWN_ERROR, 0);
611 fd = NULL;
612 break;
614 if (fd) {
616 * An inherited FD is inheritable by default.
617 * The child process needs to call PR_SetFDInheritable
618 * to make it non-inheritable if so desired.
620 fd->secret->inheritable = _PR_TRI_TRUE;
622 return fd;
624 /* Skip three colons */
625 nColons = 0;
626 while (*ptr) {
627 if (*ptr == ':') {
628 if (++nColons == 3) {
629 break;
632 ptr++;
634 if (*ptr == '\0') {
635 PR_SetError(PR_UNKNOWN_ERROR, 0);
636 return NULL;
638 ptr++;
642 PR_IMPLEMENT(PRProcess*)
643 PR_CreateProcess(const char* path, char* const* argv, char* const* envp,
644 const PRProcessAttr* attr) {
645 return _PR_MD_CREATE_PROCESS(path, argv, envp, attr);
646 } /* PR_CreateProcess */
648 PR_IMPLEMENT(PRStatus)
649 PR_CreateProcessDetached(const char* path, char* const* argv, char* const* envp,
650 const PRProcessAttr* attr) {
651 PRProcess* process;
652 PRStatus rv;
654 process = PR_CreateProcess(path, argv, envp, attr);
655 if (NULL == process) {
656 return PR_FAILURE;
658 rv = PR_DetachProcess(process);
659 PR_ASSERT(PR_SUCCESS == rv);
660 if (rv == PR_FAILURE) {
661 PR_DELETE(process);
662 return PR_FAILURE;
664 return PR_SUCCESS;
667 PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess* process) {
668 return _PR_MD_DETACH_PROCESS(process);
671 PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess* process, PRInt32* exitCode) {
672 return _PR_MD_WAIT_PROCESS(process, exitCode);
673 } /* PR_WaitProcess */
675 PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess* process) {
676 return _PR_MD_KILL_PROCESS(process);
680 ********************************************************************
682 * Module initialization
684 ********************************************************************
687 static struct {
688 PRLock* ml;
689 PRCondVar* cv;
690 } mod_init;
692 static void _PR_InitCallOnce(void) {
693 mod_init.ml = PR_NewLock();
694 PR_ASSERT(NULL != mod_init.ml);
695 mod_init.cv = PR_NewCondVar(mod_init.ml);
696 PR_ASSERT(NULL != mod_init.cv);
699 void _PR_CleanupCallOnce() {
700 PR_DestroyLock(mod_init.ml);
701 mod_init.ml = NULL;
702 PR_DestroyCondVar(mod_init.cv);
703 mod_init.cv = NULL;
706 PR_IMPLEMENT(PRStatus) PR_CallOnce(PRCallOnceType* once, PRCallOnceFN func) {
707 if (!_pr_initialized) {
708 _PR_ImplicitInitialization();
711 PR_Lock(mod_init.ml);
712 PRIntn initialized = once->initialized;
713 PRStatus status = once->status;
714 PR_Unlock(mod_init.ml);
715 if (!initialized) {
716 if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) {
717 status = (*func)();
718 PR_Lock(mod_init.ml);
719 once->status = status;
720 once->initialized = 1;
721 PR_NotifyAllCondVar(mod_init.cv);
722 PR_Unlock(mod_init.ml);
723 } else {
724 PR_Lock(mod_init.ml);
725 while (!once->initialized) {
726 PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
728 status = once->status;
729 PR_Unlock(mod_init.ml);
730 if (PR_SUCCESS != status) {
731 PR_SetError(PR_CALL_ONCE_ERROR, 0);
734 return status;
736 if (PR_SUCCESS != status) {
737 PR_SetError(PR_CALL_ONCE_ERROR, 0);
739 return status;
742 PR_IMPLEMENT(PRStatus)
743 PR_CallOnceWithArg(PRCallOnceType* once, PRCallOnceWithArgFN func, void* arg) {
744 if (!_pr_initialized) {
745 _PR_ImplicitInitialization();
748 PR_Lock(mod_init.ml);
749 PRIntn initialized = once->initialized;
750 PRStatus status = once->status;
751 PR_Unlock(mod_init.ml);
752 if (!initialized) {
753 if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) {
754 status = (*func)(arg);
755 PR_Lock(mod_init.ml);
756 once->status = status;
757 once->initialized = 1;
758 PR_NotifyAllCondVar(mod_init.cv);
759 PR_Unlock(mod_init.ml);
760 } else {
761 PR_Lock(mod_init.ml);
762 while (!once->initialized) {
763 PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
765 status = once->status;
766 PR_Unlock(mod_init.ml);
767 if (PR_SUCCESS != status) {
768 PR_SetError(PR_CALL_ONCE_ERROR, 0);
771 return status;
773 if (PR_SUCCESS != status) {
774 PR_SetError(PR_CALL_ONCE_ERROR, 0);
776 return status;
779 PRBool _PR_Obsolete(const char* obsolete, const char* preferred) {
780 #if defined(DEBUG)
781 PR_fprintf(PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n", obsolete,
782 (NULL == preferred) ? "something else" : preferred);
783 #endif
784 return PR_FALSE;
785 } /* _PR_Obsolete */
787 /* prinit.c */