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/. */
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
);
38 PRInt32 _pr_userActive
;
39 PRInt32 _pr_systemActive
;
42 # ifdef _PR_LOCAL_THREADS_ONLY
44 struct _PRCPU
* _pr_currentCPU
;
45 PRThread
* _pr_currentThread
;
46 PRThread
* _pr_lastThread
;
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
72 int vmajor
= 0, vminor
= 0, vpatch
= 0;
73 const char* ptr
= importedVersion
;
75 while (isdigit(*ptr
)) {
76 vmajor
= 10 * vmajor
+ *ptr
- '0';
81 while (isdigit(*ptr
)) {
82 vminor
= 10 * vminor
+ *ptr
- '0';
87 while (isdigit(*ptr
)) {
88 vpatch
= 10 * vpatch
+ *ptr
- '0';
94 if (vmajor
!= PR_VMAJOR
) {
97 if (vmajor
== PR_VMAJOR
&& vminor
> PR_VMINOR
) {
100 if (vmajor
== PR_VMAJOR
&& vminor
== PR_VMINOR
&& vpatch
> PR_VPATCH
) {
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;
113 static void _pr_SetNativeThreadsOnlyMode(void) {
118 mainExe
= GetModuleHandle(NULL
);
119 PR_ASSERT(NULL
!= mainExe
);
120 globalp
= (PRBool
*)GetProcAddress(mainExe
, "nspr_native_threads_only");
122 _native_threads_only
= (*globalp
!= PR_FALSE
);
123 } else if (envp
= getenv("NSPR_NATIVE_THREADS_ONLY")) {
124 _native_threads_only
= (atoi(envp
) == 1);
129 static void _PR_InitStuff(void) {
130 if (_pr_initialized
) {
133 _pr_initialized
= PR_TRUE
;
134 #ifdef _PR_ZONE_ALLOCATOR
138 _pr_SetNativeThreadsOnlyMode();
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() */
164 _PR_InitLayerCache();
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
177 * XXX: call _PR_InitMem only on those platforms for which nspr implements
180 #ifdef _PR_OVERRIDE_MALLOC
195 nspr_InitializePRErrorTable();
200 void _PR_ImplicitInitialization(void) {
203 /* Enable interrupts */
204 #if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY)
205 _PR_MD_START_INTERRUPTS();
209 PR_IMPLEMENT(void) PR_DisableClockInterrupts(void) {
210 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
211 if (!_pr_initialized
) {
214 _PR_MD_DISABLE_CLOCK_INTERRUPTS();
219 PR_IMPLEMENT(void) PR_EnableClockInterrupts(void) {
220 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
221 if (!_pr_initialized
) {
224 _PR_MD_ENABLE_CLOCK_INTERRUPTS();
228 PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) {
229 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
230 _PR_MD_BLOCK_CLOCK_INTERRUPTS();
234 PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void) {
235 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
236 _PR_MD_UNBLOCK_CLOCK_INTERRUPTS();
241 PR_Init(PRThreadType type
, PRThreadPriority priority
, PRUintn maxPTDs
) {
242 _PR_ImplicitInitialization();
246 PR_Initialize(PRPrimordialFn prmain
, PRIntn argc
, char** argv
,
249 _PR_ImplicitInitialization();
250 rv
= prmain(argc
, argv
);
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)
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.
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 *----------------------------------------------------------------------
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)
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
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
) {
344 PR_Unlock(_pr_activeLock
);
346 _PR_MD_EARLY_CLEANUP();
351 _PR_CleanupCallOnce();
352 _PR_ShutdownLinker();
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"));
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
);
372 _PR_UserDestroyThread(me
);
373 PR_DELETE(me
->stack
);
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.
387 _PR_CleanupThreads();
389 PR_DestroyLock(_pr_sleeplock
);
390 _pr_sleeplock
= NULL
;
391 _PR_CleanupLayerCache();
394 _PR_CleanupBeforeExit();
395 _pr_initialized
= PR_FALSE
;
400 #endif /* defined(_PR_PTHREADS) */
403 *------------------------------------------------------------------------
406 * Cause an immediate, nongraceful, forced termination of the process.
407 * It takes a PRIntn argument, which is the exit status code of the
410 * See also: PR_Cleanup()
412 *------------------------------------------------------------------------
415 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
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) {
426 attr
= PR_NEWZAP(PRProcessAttr
);
428 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
434 PR_ResetProcessAttr(PRProcessAttr
* attr
) {
435 PR_FREEIF(attr
->currentDirectory
);
436 PR_FREEIF(attr
->fdInheritBuffer
);
437 memset(attr
, 0, sizeof(*attr
));
441 PR_DestroyProcessAttr(PRProcessAttr
* attr
) {
442 PR_FREEIF(attr
->currentDirectory
);
443 PR_FREEIF(attr
->fdInheritBuffer
);
448 PR_ProcessAttrSetStdioRedirect(PRProcessAttr
* attr
, PRSpecialFD stdioFd
,
449 PRFileDesc
* redirectFd
) {
451 case PR_StandardInput
:
452 attr
->stdinFd
= redirectFd
;
454 case PR_StandardOutput
:
455 attr
->stdoutFd
= redirectFd
;
457 case PR_StandardError
:
458 attr
->stderrFd
= redirectFd
;
469 PR_SetStdioRedirect(PRProcessAttr
* attr
, PRSpecialFD stdioFd
,
470 PRFileDesc
* redirectFd
) {
472 static PRBool warn
= PR_TRUE
;
474 warn
= _PR_Obsolete("PR_SetStdioRedirect()",
475 "PR_ProcessAttrSetStdioRedirect()");
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);
489 strcpy(attr
->currentDirectory
, dir
);
493 PR_IMPLEMENT(PRStatus
)
494 PR_ProcessAttrSetInheritableFD(PRProcessAttr
* attr
, PRFileDesc
* fd
,
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 */
502 # define OSFD_STRLEN 18
504 # define OSFD_STRLEN 10
506 /* The length of fd type (PRDescType) printed in decimal */
507 #define FD_TYPE_STRLEN 1
515 if (fd
->identity
!= PR_NSPR_IO_LAYER
) {
516 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
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);
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
+
536 /* At other times, we print ":<name>:<type>:<val>" */
537 newSize
= attr
->fdInheritBufferUsed
+ strlen(name
) + FD_TYPE_STRLEN
+
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
);
549 newBuffer
= (char*)PR_REALLOC(attr
->fdInheritBuffer
, newSize
);
551 if (NULL
== newBuffer
) {
552 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
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
) {
562 PR_snprintf(cur
, freeSize
, "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD
,
563 name
, (PRIntn
)fd
->methods
->file_type
, fd
->secret
->md
.osfd
);
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
;
572 PR_IMPLEMENT(PRFileDesc
*) PR_GetInheritedFD(const char* name
) {
576 int len
= strlen(name
);
581 envVar
= PR_GetEnv("NSPR_INHERIT_FDS");
582 if (NULL
== envVar
|| '\0' == envVar
[0]) {
583 PR_SetError(PR_UNKNOWN_ERROR
, 0);
589 if ((ptr
[len
] == ':') && (strncmp(ptr
, name
, len
) == 0)) {
591 if (PR_sscanf(ptr
, "%d:0x%" PR_SCNxOSFD
, &fileType
, &osfd
) != 2) {
592 PR_SetError(PR_UNKNOWN_ERROR
, 0);
595 switch ((PRDescType
)fileType
) {
597 fd
= PR_ImportFile(osfd
);
600 fd
= PR_ImportPipe(osfd
);
602 case PR_DESC_SOCKET_TCP
:
603 fd
= PR_ImportTCPSocket(osfd
);
605 case PR_DESC_SOCKET_UDP
:
606 fd
= PR_ImportUDPSocket(osfd
);
610 PR_SetError(PR_UNKNOWN_ERROR
, 0);
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
;
624 /* Skip three colons */
628 if (++nColons
== 3) {
635 PR_SetError(PR_UNKNOWN_ERROR
, 0);
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
) {
654 process
= PR_CreateProcess(path
, argv
, envp
, attr
);
655 if (NULL
== process
) {
658 rv
= PR_DetachProcess(process
);
659 PR_ASSERT(PR_SUCCESS
== rv
);
660 if (rv
== PR_FAILURE
) {
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 ********************************************************************
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
);
702 PR_DestroyCondVar(mod_init
.cv
);
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
);
716 if (PR_ATOMIC_SET(&once
->inProgress
, 1) == 0) {
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
);
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);
736 if (PR_SUCCESS
!= status
) {
737 PR_SetError(PR_CALL_ONCE_ERROR
, 0);
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
);
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
);
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);
773 if (PR_SUCCESS
!= status
) {
774 PR_SetError(PR_CALL_ONCE_ERROR
, 0);
779 PRBool
_PR_Obsolete(const char* obsolete
, const char* preferred
) {
781 PR_fprintf(PR_STDERR
, "'%s' is obsolete. Use '%s' instead.\n", obsolete
,
782 (NULL
== preferred
) ? "something else" : preferred
);