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