/src/nspr/pr/src/misc/prinit.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
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 | 0 | } |
81 | 0 | if (*ptr == '.') { |
82 | 0 | ptr++; |
83 | 0 | while (isdigit(*ptr)) { |
84 | 0 | vminor = 10 * vminor + *ptr - '0'; |
85 | 0 | ptr++; |
86 | 0 | } |
87 | 0 | if (*ptr == '.') { |
88 | 0 | ptr++; |
89 | 0 | while (isdigit(*ptr)) { |
90 | 0 | vpatch = 10 * vpatch + *ptr - '0'; |
91 | 0 | ptr++; |
92 | 0 | } |
93 | 0 | } |
94 | 0 | } |
95 | |
|
96 | 0 | if (vmajor != PR_VMAJOR) { |
97 | 0 | return PR_FALSE; |
98 | 0 | } |
99 | 0 | if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) { |
100 | 0 | return PR_FALSE; |
101 | 0 | } |
102 | 0 | if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) { |
103 | 0 | return PR_FALSE; |
104 | 0 | } |
105 | 0 | return PR_TRUE; |
106 | 0 | } /* PR_VersionCheck */ |
107 | | |
108 | | PR_IMPLEMENT(const char*) PR_GetVersion(void) |
109 | 0 | { |
110 | 0 | return PR_VERSION; |
111 | 0 | } |
112 | | |
113 | | PR_IMPLEMENT(PRBool) PR_Initialized(void) |
114 | 0 | { |
115 | 0 | return _pr_initialized; |
116 | 0 | } |
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 | | static void _PR_InitStuff(void) |
139 | 10 | { |
140 | | |
141 | 10 | if (_pr_initialized) { |
142 | 0 | return; |
143 | 0 | } |
144 | 10 | _pr_initialized = PR_TRUE; |
145 | 10 | #ifdef _PR_ZONE_ALLOCATOR |
146 | 10 | _PR_InitZones(); |
147 | 10 | #endif |
148 | | #ifdef WINNT |
149 | | _pr_SetNativeThreadsOnlyMode(); |
150 | | #endif |
151 | | |
152 | | |
153 | 10 | (void) PR_GetPageSize(); |
154 | | |
155 | 10 | _pr_clock_lm = PR_NewLogModule("clock"); |
156 | 10 | _pr_cmon_lm = PR_NewLogModule("cmon"); |
157 | 10 | _pr_io_lm = PR_NewLogModule("io"); |
158 | 10 | _pr_mon_lm = PR_NewLogModule("mon"); |
159 | 10 | _pr_linker_lm = PR_NewLogModule("linker"); |
160 | 10 | _pr_cvar_lm = PR_NewLogModule("cvar"); |
161 | 10 | _pr_sched_lm = PR_NewLogModule("sched"); |
162 | 10 | _pr_thread_lm = PR_NewLogModule("thread"); |
163 | 10 | _pr_gc_lm = PR_NewLogModule("gc"); |
164 | 10 | _pr_shm_lm = PR_NewLogModule("shm"); |
165 | 10 | _pr_shma_lm = PR_NewLogModule("shma"); |
166 | | |
167 | | /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ |
168 | 10 | _PR_MD_EARLY_INIT(); |
169 | | |
170 | 10 | _PR_InitLocks(); |
171 | 10 | _PR_InitAtomic(); |
172 | 10 | _PR_InitSegs(); |
173 | 10 | _PR_InitStacks(); |
174 | 10 | _PR_InitTPD(); |
175 | 10 | _PR_InitEnv(); |
176 | 10 | _PR_InitLayerCache(); |
177 | 10 | _PR_InitClock(); |
178 | | |
179 | 10 | _pr_sleeplock = PR_NewLock(); |
180 | 10 | PR_ASSERT(NULL != _pr_sleeplock); |
181 | | |
182 | 10 | _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 | 10 | #ifndef _PR_GLOBAL_THREADS_ONLY |
192 | 10 | _PR_InitCPUs(); |
193 | 10 | #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 | 10 | _PR_InitCMon(); |
204 | 10 | _PR_InitIO(); |
205 | 10 | _PR_InitNet(); |
206 | 10 | _PR_InitTime(); |
207 | 10 | _PR_InitLog(); |
208 | 10 | _PR_InitLinker(); |
209 | 10 | _PR_InitCallOnce(); |
210 | 10 | _PR_InitDtoa(); |
211 | 10 | _PR_InitMW(); |
212 | 10 | _PR_InitRWLocks(); |
213 | | |
214 | 10 | nspr_InitializePRErrorTable(); |
215 | | |
216 | 10 | _PR_MD_FINAL_INIT(); |
217 | 10 | } |
218 | | |
219 | | void _PR_ImplicitInitialization(void) |
220 | 10 | { |
221 | 10 | _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 | 10 | } |
229 | | |
230 | | PR_IMPLEMENT(void) PR_DisableClockInterrupts(void) |
231 | 0 | { |
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 | 0 | } |
240 | | |
241 | | PR_IMPLEMENT(void) PR_EnableClockInterrupts(void) |
242 | 0 | { |
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 | 0 | } |
250 | | |
251 | | PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) |
252 | 0 | { |
253 | | #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) |
254 | | _PR_MD_BLOCK_CLOCK_INTERRUPTS(); |
255 | | #endif |
256 | 0 | } |
257 | | |
258 | | PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void) |
259 | 0 | { |
260 | | #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) |
261 | | _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(); |
262 | | #endif |
263 | 0 | } |
264 | | |
265 | | PR_IMPLEMENT(void) PR_Init( |
266 | | PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) |
267 | 0 | { |
268 | 0 | _PR_ImplicitInitialization(); |
269 | 0 | } |
270 | | |
271 | | PR_IMPLEMENT(PRIntn) PR_Initialize( |
272 | | PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs) |
273 | 0 | { |
274 | 0 | PRIntn rv; |
275 | 0 | _PR_ImplicitInitialization(); |
276 | 0 | rv = prmain(argc, argv); |
277 | 0 | PR_Cleanup(); |
278 | 0 | return rv; |
279 | 0 | } /* 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 |
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 | | |
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 |
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 *) |
456 | | PR_NewProcessAttr(void) |
457 | 0 | { |
458 | 0 | PRProcessAttr *attr; |
459 | |
|
460 | 0 | attr = PR_NEWZAP(PRProcessAttr); |
461 | 0 | if (!attr) { |
462 | 0 | PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
463 | 0 | } |
464 | 0 | return attr; |
465 | 0 | } |
466 | | |
467 | | PR_IMPLEMENT(void) |
468 | | PR_ResetProcessAttr(PRProcessAttr *attr) |
469 | 0 | { |
470 | 0 | PR_FREEIF(attr->currentDirectory); |
471 | 0 | PR_FREEIF(attr->fdInheritBuffer); |
472 | 0 | memset(attr, 0, sizeof(*attr)); |
473 | 0 | } |
474 | | |
475 | | PR_IMPLEMENT(void) |
476 | | PR_DestroyProcessAttr(PRProcessAttr *attr) |
477 | 0 | { |
478 | 0 | PR_FREEIF(attr->currentDirectory); |
479 | 0 | PR_FREEIF(attr->fdInheritBuffer); |
480 | 0 | PR_DELETE(attr); |
481 | 0 | } |
482 | | |
483 | | PR_IMPLEMENT(void) |
484 | | PR_ProcessAttrSetStdioRedirect( |
485 | | PRProcessAttr *attr, |
486 | | PRSpecialFD stdioFd, |
487 | | PRFileDesc *redirectFd) |
488 | 0 | { |
489 | 0 | switch (stdioFd) { |
490 | 0 | case PR_StandardInput: |
491 | 0 | attr->stdinFd = redirectFd; |
492 | 0 | break; |
493 | 0 | case PR_StandardOutput: |
494 | 0 | attr->stdoutFd = redirectFd; |
495 | 0 | break; |
496 | 0 | case PR_StandardError: |
497 | 0 | attr->stderrFd = redirectFd; |
498 | 0 | break; |
499 | 0 | default: |
500 | 0 | PR_ASSERT(0); |
501 | 0 | } |
502 | 0 | } |
503 | | |
504 | | /* |
505 | | * OBSOLETE |
506 | | */ |
507 | | PR_IMPLEMENT(void) |
508 | | PR_SetStdioRedirect( |
509 | | PRProcessAttr *attr, |
510 | | PRSpecialFD stdioFd, |
511 | | PRFileDesc *redirectFd) |
512 | 0 | { |
513 | 0 | #if defined(DEBUG) |
514 | 0 | static PRBool warn = PR_TRUE; |
515 | 0 | if (warn) { |
516 | 0 | warn = _PR_Obsolete("PR_SetStdioRedirect()", |
517 | 0 | "PR_ProcessAttrSetStdioRedirect()"); |
518 | 0 | } |
519 | 0 | #endif |
520 | 0 | PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd); |
521 | 0 | } |
522 | | |
523 | | PR_IMPLEMENT(PRStatus) |
524 | | PR_ProcessAttrSetCurrentDirectory( |
525 | | PRProcessAttr *attr, |
526 | | const char *dir) |
527 | 0 | { |
528 | 0 | PR_FREEIF(attr->currentDirectory); |
529 | 0 | attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1); |
530 | 0 | if (!attr->currentDirectory) { |
531 | 0 | PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
532 | 0 | return PR_FAILURE; |
533 | 0 | } |
534 | 0 | strcpy(attr->currentDirectory, dir); |
535 | 0 | return PR_SUCCESS; |
536 | 0 | } |
537 | | |
538 | | PR_IMPLEMENT(PRStatus) |
539 | | PR_ProcessAttrSetInheritableFD( |
540 | | PRProcessAttr *attr, |
541 | | PRFileDesc *fd, |
542 | | const char *name) |
543 | 0 | { |
544 | | /* We malloc the fd inherit buffer in multiples of this number. */ |
545 | 0 | #define FD_INHERIT_BUFFER_INCR 128 |
546 | | /* The length of "NSPR_INHERIT_FDS=" */ |
547 | 0 | #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 | 0 | #define OSFD_STRLEN 10 |
553 | 0 | #endif |
554 | | /* The length of fd type (PRDescType) printed in decimal */ |
555 | 0 | #define FD_TYPE_STRLEN 1 |
556 | 0 | PRSize newSize; |
557 | 0 | int remainder; |
558 | 0 | char *newBuffer; |
559 | 0 | int nwritten; |
560 | 0 | char *cur; |
561 | 0 | int freeSize; |
562 | |
|
563 | 0 | if (fd->identity != PR_NSPR_IO_LAYER) { |
564 | 0 | PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
565 | 0 | return PR_FAILURE; |
566 | 0 | } |
567 | 0 | if (fd->secret->inheritable == _PR_TRI_UNKNOWN) { |
568 | 0 | _PR_MD_QUERY_FD_INHERITABLE(fd); |
569 | 0 | } |
570 | 0 | if (fd->secret->inheritable != _PR_TRI_TRUE) { |
571 | 0 | PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); |
572 | 0 | return PR_FAILURE; |
573 | 0 | } |
574 | | |
575 | | /* |
576 | | * We also need to account for the : separators and the |
577 | | * terminating null byte. |
578 | | */ |
579 | 0 | if (NULL == attr->fdInheritBuffer) { |
580 | | /* The first time, we print "NSPR_INHERIT_FDS=<name>:<type>:<val>" */ |
581 | 0 | newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name) |
582 | 0 | + FD_TYPE_STRLEN + OSFD_STRLEN + 2 + 1; |
583 | 0 | } else { |
584 | | /* At other times, we print ":<name>:<type>:<val>" */ |
585 | 0 | newSize = attr->fdInheritBufferUsed + strlen(name) |
586 | 0 | + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1; |
587 | 0 | } |
588 | 0 | if (newSize > attr->fdInheritBufferSize) { |
589 | | /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */ |
590 | 0 | remainder = newSize % FD_INHERIT_BUFFER_INCR; |
591 | 0 | if (remainder != 0) { |
592 | 0 | newSize += (FD_INHERIT_BUFFER_INCR - remainder); |
593 | 0 | } |
594 | 0 | if (NULL == attr->fdInheritBuffer) { |
595 | 0 | newBuffer = (char *) PR_MALLOC(newSize); |
596 | 0 | } else { |
597 | 0 | newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize); |
598 | 0 | } |
599 | 0 | if (NULL == newBuffer) { |
600 | 0 | PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
601 | 0 | return PR_FAILURE; |
602 | 0 | } |
603 | 0 | attr->fdInheritBuffer = newBuffer; |
604 | 0 | attr->fdInheritBufferSize = newSize; |
605 | 0 | } |
606 | 0 | cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed; |
607 | 0 | freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed; |
608 | 0 | if (0 == attr->fdInheritBufferUsed) { |
609 | 0 | nwritten = PR_snprintf(cur, freeSize, |
610 | 0 | "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD, |
611 | 0 | name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); |
612 | 0 | } else { |
613 | 0 | nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD, |
614 | 0 | name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); |
615 | 0 | } |
616 | 0 | attr->fdInheritBufferUsed += nwritten; |
617 | 0 | return PR_SUCCESS; |
618 | 0 | } |
619 | | |
620 | | PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD( |
621 | | const char *name) |
622 | 0 | { |
623 | 0 | PRFileDesc *fd; |
624 | 0 | const char *envVar; |
625 | 0 | const char *ptr; |
626 | 0 | int len = strlen(name); |
627 | 0 | PROsfd osfd; |
628 | 0 | int nColons; |
629 | 0 | PRIntn fileType; |
630 | |
|
631 | 0 | envVar = PR_GetEnv("NSPR_INHERIT_FDS"); |
632 | 0 | if (NULL == envVar || '\0' == envVar[0]) { |
633 | 0 | PR_SetError(PR_UNKNOWN_ERROR, 0); |
634 | 0 | return NULL; |
635 | 0 | } |
636 | | |
637 | 0 | ptr = envVar; |
638 | 0 | while (1) { |
639 | 0 | if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) { |
640 | 0 | ptr += len + 1; |
641 | 0 | if (PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd) != 2) { |
642 | 0 | PR_SetError(PR_UNKNOWN_ERROR, 0); |
643 | 0 | return NULL; |
644 | 0 | } |
645 | 0 | switch ((PRDescType)fileType) { |
646 | 0 | case PR_DESC_FILE: |
647 | 0 | fd = PR_ImportFile(osfd); |
648 | 0 | break; |
649 | 0 | case PR_DESC_PIPE: |
650 | 0 | fd = PR_ImportPipe(osfd); |
651 | 0 | break; |
652 | 0 | case PR_DESC_SOCKET_TCP: |
653 | 0 | fd = PR_ImportTCPSocket(osfd); |
654 | 0 | break; |
655 | 0 | case PR_DESC_SOCKET_UDP: |
656 | 0 | fd = PR_ImportUDPSocket(osfd); |
657 | 0 | break; |
658 | 0 | default: |
659 | 0 | PR_ASSERT(0); |
660 | 0 | PR_SetError(PR_UNKNOWN_ERROR, 0); |
661 | 0 | fd = NULL; |
662 | 0 | break; |
663 | 0 | } |
664 | 0 | 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 | 0 | fd->secret->inheritable = _PR_TRI_TRUE; |
671 | 0 | } |
672 | 0 | return fd; |
673 | 0 | } |
674 | | /* Skip three colons */ |
675 | 0 | nColons = 0; |
676 | 0 | while (*ptr) { |
677 | 0 | if (*ptr == ':') { |
678 | 0 | if (++nColons == 3) { |
679 | 0 | break; |
680 | 0 | } |
681 | 0 | } |
682 | 0 | ptr++; |
683 | 0 | } |
684 | 0 | if (*ptr == '\0') { |
685 | 0 | PR_SetError(PR_UNKNOWN_ERROR, 0); |
686 | 0 | return NULL; |
687 | 0 | } |
688 | 0 | ptr++; |
689 | 0 | } |
690 | 0 | } |
691 | | |
692 | | PR_IMPLEMENT(PRProcess*) PR_CreateProcess( |
693 | | const char *path, |
694 | | char *const *argv, |
695 | | char *const *envp, |
696 | | const PRProcessAttr *attr) |
697 | 0 | { |
698 | 0 | return _PR_MD_CREATE_PROCESS(path, argv, envp, attr); |
699 | 0 | } /* PR_CreateProcess */ |
700 | | |
701 | | PR_IMPLEMENT(PRStatus) PR_CreateProcessDetached( |
702 | | const char *path, |
703 | | char *const *argv, |
704 | | char *const *envp, |
705 | | const PRProcessAttr *attr) |
706 | 0 | { |
707 | 0 | PRProcess *process; |
708 | 0 | PRStatus rv; |
709 | |
|
710 | 0 | process = PR_CreateProcess(path, argv, envp, attr); |
711 | 0 | if (NULL == process) { |
712 | 0 | return PR_FAILURE; |
713 | 0 | } |
714 | 0 | rv = PR_DetachProcess(process); |
715 | 0 | PR_ASSERT(PR_SUCCESS == rv); |
716 | 0 | if (rv == PR_FAILURE) { |
717 | 0 | PR_DELETE(process); |
718 | 0 | return PR_FAILURE; |
719 | 0 | } |
720 | 0 | return PR_SUCCESS; |
721 | 0 | } |
722 | | |
723 | | PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process) |
724 | 0 | { |
725 | 0 | return _PR_MD_DETACH_PROCESS(process); |
726 | 0 | } |
727 | | |
728 | | PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode) |
729 | 0 | { |
730 | 0 | return _PR_MD_WAIT_PROCESS(process, exitCode); |
731 | 0 | } /* PR_WaitProcess */ |
732 | | |
733 | | PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process) |
734 | 0 | { |
735 | 0 | return _PR_MD_KILL_PROCESS(process); |
736 | 0 | } |
737 | | |
738 | | /* |
739 | | ******************************************************************** |
740 | | * |
741 | | * Module initialization |
742 | | * |
743 | | ******************************************************************** |
744 | | */ |
745 | | |
746 | | static struct { |
747 | | PRLock *ml; |
748 | | PRCondVar *cv; |
749 | | } mod_init; |
750 | | |
751 | 10 | static void _PR_InitCallOnce(void) { |
752 | 10 | mod_init.ml = PR_NewLock(); |
753 | 10 | PR_ASSERT(NULL != mod_init.ml); |
754 | 10 | mod_init.cv = PR_NewCondVar(mod_init.ml); |
755 | 10 | PR_ASSERT(NULL != mod_init.cv); |
756 | 10 | } |
757 | | |
758 | | void _PR_CleanupCallOnce() |
759 | 0 | { |
760 | 0 | PR_DestroyLock(mod_init.ml); |
761 | 0 | mod_init.ml = NULL; |
762 | 0 | PR_DestroyCondVar(mod_init.cv); |
763 | 0 | mod_init.cv = NULL; |
764 | 0 | } |
765 | | |
766 | | PR_IMPLEMENT(PRStatus) PR_CallOnce( |
767 | | PRCallOnceType *once, |
768 | | PRCallOnceFN func) |
769 | 2.31M | { |
770 | 2.31M | if (!_pr_initialized) { |
771 | 8 | _PR_ImplicitInitialization(); |
772 | 8 | } |
773 | | |
774 | 2.31M | PR_Lock(mod_init.ml); |
775 | 2.31M | PRIntn initialized = once->initialized; |
776 | 2.31M | PRStatus status = once->status; |
777 | 2.31M | PR_Unlock(mod_init.ml); |
778 | 2.31M | if (!initialized) { |
779 | 108k | if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) { |
780 | 108k | status = (*func)(); |
781 | 108k | PR_Lock(mod_init.ml); |
782 | 108k | once->status = status; |
783 | 108k | once->initialized = 1; |
784 | 108k | PR_NotifyAllCondVar(mod_init.cv); |
785 | 108k | PR_Unlock(mod_init.ml); |
786 | 108k | } else { |
787 | 0 | PR_Lock(mod_init.ml); |
788 | 0 | while (!once->initialized) { |
789 | 0 | PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); |
790 | 0 | } |
791 | 0 | status = once->status; |
792 | 0 | PR_Unlock(mod_init.ml); |
793 | 0 | if (PR_SUCCESS != status) { |
794 | 0 | PR_SetError(PR_CALL_ONCE_ERROR, 0); |
795 | 0 | } |
796 | 0 | } |
797 | 108k | return status; |
798 | 108k | } |
799 | 2.20M | if (PR_SUCCESS != status) { |
800 | 438k | PR_SetError(PR_CALL_ONCE_ERROR, 0); |
801 | 438k | } |
802 | 2.20M | return status; |
803 | 2.31M | } |
804 | | |
805 | | PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg( |
806 | | PRCallOnceType *once, |
807 | | PRCallOnceWithArgFN func, |
808 | | void *arg) |
809 | 1.65M | { |
810 | 1.65M | if (!_pr_initialized) { |
811 | 0 | _PR_ImplicitInitialization(); |
812 | 0 | } |
813 | | |
814 | 1.65M | PR_Lock(mod_init.ml); |
815 | 1.65M | PRIntn initialized = once->initialized; |
816 | 1.65M | PRStatus status = once->status; |
817 | 1.65M | PR_Unlock(mod_init.ml); |
818 | 1.65M | if (!initialized) { |
819 | 36.3k | if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) { |
820 | 36.3k | status = (*func)(arg); |
821 | 36.3k | PR_Lock(mod_init.ml); |
822 | 36.3k | once->status = status; |
823 | 36.3k | once->initialized = 1; |
824 | 36.3k | PR_NotifyAllCondVar(mod_init.cv); |
825 | 36.3k | PR_Unlock(mod_init.ml); |
826 | 36.3k | } else { |
827 | 0 | PR_Lock(mod_init.ml); |
828 | 0 | while (!once->initialized) { |
829 | 0 | PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); |
830 | 0 | } |
831 | 0 | status = once->status; |
832 | 0 | PR_Unlock(mod_init.ml); |
833 | 0 | if (PR_SUCCESS != status) { |
834 | 0 | PR_SetError(PR_CALL_ONCE_ERROR, 0); |
835 | 0 | } |
836 | 0 | } |
837 | 36.3k | return status; |
838 | 36.3k | } |
839 | 1.61M | if (PR_SUCCESS != status) { |
840 | 0 | PR_SetError(PR_CALL_ONCE_ERROR, 0); |
841 | 0 | } |
842 | 1.61M | return status; |
843 | 1.65M | } |
844 | | |
845 | | PRBool _PR_Obsolete(const char *obsolete, const char *preferred) |
846 | 0 | { |
847 | 0 | #if defined(DEBUG) |
848 | 0 | PR_fprintf( |
849 | 0 | PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n", |
850 | 0 | obsolete, (NULL == preferred) ? "something else" : preferred); |
851 | 0 | #endif |
852 | 0 | return PR_FALSE; |
853 | 0 | } /* _PR_Obsolete */ |
854 | | |
855 | | /* prinit.c */ |
856 | | |
857 | | |