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 *) ⊤
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