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