| OLD | NEW |
| (Empty) |
| 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 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 | |
| 108 PR_IMPLEMENT(const char*) PR_GetVersion(void) | |
| 109 { | |
| 110 return PR_VERSION; | |
| 111 } | |
| 112 | |
| 113 PR_IMPLEMENT(PRBool) PR_Initialized(void) | |
| 114 { | |
| 115 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 static void _PR_InitStuff(void) | |
| 139 { | |
| 140 | |
| 141 if (_pr_initialized) return; | |
| 142 _pr_initialized = PR_TRUE; | |
| 143 #ifdef _PR_ZONE_ALLOCATOR | |
| 144 _PR_InitZones(); | |
| 145 #endif | |
| 146 #ifdef WINNT | |
| 147 _pr_SetNativeThreadsOnlyMode(); | |
| 148 #endif | |
| 149 | |
| 150 | |
| 151 (void) PR_GetPageSize(); | |
| 152 | |
| 153 _pr_clock_lm = PR_NewLogModule("clock"); | |
| 154 _pr_cmon_lm = PR_NewLogModule("cmon"); | |
| 155 _pr_io_lm = PR_NewLogModule("io"); | |
| 156 _pr_mon_lm = PR_NewLogModule("mon"); | |
| 157 _pr_linker_lm = PR_NewLogModule("linker"); | |
| 158 _pr_cvar_lm = PR_NewLogModule("cvar"); | |
| 159 _pr_sched_lm = PR_NewLogModule("sched"); | |
| 160 _pr_thread_lm = PR_NewLogModule("thread"); | |
| 161 _pr_gc_lm = PR_NewLogModule("gc"); | |
| 162 _pr_shm_lm = PR_NewLogModule("shm"); | |
| 163 _pr_shma_lm = PR_NewLogModule("shma"); | |
| 164 | |
| 165 /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ | |
| 166 _PR_MD_EARLY_INIT(); | |
| 167 | |
| 168 _PR_InitLocks(); | |
| 169 _PR_InitAtomic(); | |
| 170 _PR_InitSegs(); | |
| 171 _PR_InitStacks(); | |
| 172 _PR_InitTPD(); | |
| 173 _PR_InitEnv(); | |
| 174 _PR_InitLayerCache(); | |
| 175 _PR_InitClock(); | |
| 176 | |
| 177 _pr_sleeplock = PR_NewLock(); | |
| 178 PR_ASSERT(NULL != _pr_sleeplock); | |
| 179 | |
| 180 _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 _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 _PR_InitCMon(); | |
| 202 _PR_InitIO(); | |
| 203 _PR_InitNet(); | |
| 204 _PR_InitTime(); | |
| 205 _PR_InitLog(); | |
| 206 _PR_InitLinker(); | |
| 207 _PR_InitCallOnce(); | |
| 208 _PR_InitDtoa(); | |
| 209 _PR_InitMW(); | |
| 210 _PR_InitRWLocks(); | |
| 211 | |
| 212 nspr_InitializePRErrorTable(); | |
| 213 | |
| 214 _PR_MD_FINAL_INIT(); | |
| 215 } | |
| 216 | |
| 217 void _PR_ImplicitInitialization(void) | |
| 218 { | |
| 219 _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 } | |
| 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 } | |
| 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 } | |
| 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 } | |
| 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 } | |
| 262 | |
| 263 PR_IMPLEMENT(void) PR_Init( | |
| 264 PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) | |
| 265 { | |
| 266 _PR_ImplicitInitialization(); | |
| 267 } | |
| 268 | |
| 269 PR_IMPLEMENT(PRIntn) PR_Initialize( | |
| 270 PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs) | |
| 271 { | |
| 272 PRIntn rv; | |
| 273 _PR_ImplicitInitialization(); | |
| 274 rv = prmain(argc, argv); | |
| 275 PR_Cleanup(); | |
| 276 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 c
pu | |
| 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 attr = PR_NEWZAP(PRProcessAttr); | |
| 465 if (!attr) { | |
| 466 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
| 467 } | |
| 468 return attr; | |
| 469 } | |
| 470 | |
| 471 PR_IMPLEMENT(void) | |
| 472 PR_ResetProcessAttr(PRProcessAttr *attr) | |
| 473 { | |
| 474 PR_FREEIF(attr->currentDirectory); | |
| 475 PR_FREEIF(attr->fdInheritBuffer); | |
| 476 memset(attr, 0, sizeof(*attr)); | |
| 477 } | |
| 478 | |
| 479 PR_IMPLEMENT(void) | |
| 480 PR_DestroyProcessAttr(PRProcessAttr *attr) | |
| 481 { | |
| 482 PR_FREEIF(attr->currentDirectory); | |
| 483 PR_FREEIF(attr->fdInheritBuffer); | |
| 484 PR_DELETE(attr); | |
| 485 } | |
| 486 | |
| 487 PR_IMPLEMENT(void) | |
| 488 PR_ProcessAttrSetStdioRedirect( | |
| 489 PRProcessAttr *attr, | |
| 490 PRSpecialFD stdioFd, | |
| 491 PRFileDesc *redirectFd) | |
| 492 { | |
| 493 switch (stdioFd) { | |
| 494 case PR_StandardInput: | |
| 495 attr->stdinFd = redirectFd; | |
| 496 break; | |
| 497 case PR_StandardOutput: | |
| 498 attr->stdoutFd = redirectFd; | |
| 499 break; | |
| 500 case PR_StandardError: | |
| 501 attr->stderrFd = redirectFd; | |
| 502 break; | |
| 503 default: | |
| 504 PR_ASSERT(0); | |
| 505 } | |
| 506 } | |
| 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 if (warn) { | |
| 520 warn = _PR_Obsolete("PR_SetStdioRedirect()", | |
| 521 "PR_ProcessAttrSetStdioRedirect()"); | |
| 522 } | |
| 523 #endif | |
| 524 PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd); | |
| 525 } | |
| 526 | |
| 527 PR_IMPLEMENT(PRStatus) | |
| 528 PR_ProcessAttrSetCurrentDirectory( | |
| 529 PRProcessAttr *attr, | |
| 530 const char *dir) | |
| 531 { | |
| 532 PR_FREEIF(attr->currentDirectory); | |
| 533 attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1); | |
| 534 if (!attr->currentDirectory) { | |
| 535 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
| 536 return PR_FAILURE; | |
| 537 } | |
| 538 strcpy(attr->currentDirectory, dir); | |
| 539 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 if (fd->identity != PR_NSPR_IO_LAYER) { | |
| 568 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 569 return PR_FAILURE; | |
| 570 } | |
| 571 if (fd->secret->inheritable == _PR_TRI_UNKNOWN) { | |
| 572 _PR_MD_QUERY_FD_INHERITABLE(fd); | |
| 573 } | |
| 574 if (fd->secret->inheritable != _PR_TRI_TRUE) { | |
| 575 PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); | |
| 576 return PR_FAILURE; | |
| 577 } | |
| 578 | |
| 579 /* | |
| 580 * We also need to account for the : separators and the | |
| 581 * terminating null byte. | |
| 582 */ | |
| 583 if (NULL == attr->fdInheritBuffer) { | |
| 584 /* The first time, we print "NSPR_INHERIT_FDS=<name>:<type>:<val>" */ | |
| 585 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 newSize = attr->fdInheritBufferUsed + strlen(name) | |
| 590 + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1; | |
| 591 } | |
| 592 if (newSize > attr->fdInheritBufferSize) { | |
| 593 /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */ | |
| 594 remainder = newSize % FD_INHERIT_BUFFER_INCR; | |
| 595 if (remainder != 0) { | |
| 596 newSize += (FD_INHERIT_BUFFER_INCR - remainder); | |
| 597 } | |
| 598 if (NULL == attr->fdInheritBuffer) { | |
| 599 newBuffer = (char *) PR_MALLOC(newSize); | |
| 600 } else { | |
| 601 newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize); | |
| 602 } | |
| 603 if (NULL == newBuffer) { | |
| 604 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
| 605 return PR_FAILURE; | |
| 606 } | |
| 607 attr->fdInheritBuffer = newBuffer; | |
| 608 attr->fdInheritBufferSize = newSize; | |
| 609 } | |
| 610 cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed; | |
| 611 freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed; | |
| 612 if (0 == attr->fdInheritBufferUsed) { | |
| 613 nwritten = PR_snprintf(cur, freeSize, | |
| 614 "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD, | |
| 615 name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); | |
| 616 } else { | |
| 617 nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD, | |
| 618 name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); | |
| 619 } | |
| 620 attr->fdInheritBufferUsed += nwritten; | |
| 621 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 int len = strlen(name); | |
| 631 PROsfd osfd; | |
| 632 int nColons; | |
| 633 PRIntn fileType; | |
| 634 | |
| 635 envVar = PR_GetEnv("NSPR_INHERIT_FDS"); | |
| 636 if (NULL == envVar || '\0' == envVar[0]) { | |
| 637 PR_SetError(PR_UNKNOWN_ERROR, 0); | |
| 638 return NULL; | |
| 639 } | |
| 640 | |
| 641 ptr = envVar; | |
| 642 while (1) { | |
| 643 if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) { | |
| 644 ptr += len + 1; | |
| 645 if (PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd) != 2) { | |
| 646 PR_SetError(PR_UNKNOWN_ERROR, 0); | |
| 647 return NULL; | |
| 648 } | |
| 649 switch ((PRDescType)fileType) { | |
| 650 case PR_DESC_FILE: | |
| 651 fd = PR_ImportFile(osfd); | |
| 652 break; | |
| 653 case PR_DESC_PIPE: | |
| 654 fd = PR_ImportPipe(osfd); | |
| 655 break; | |
| 656 case PR_DESC_SOCKET_TCP: | |
| 657 fd = PR_ImportTCPSocket(osfd); | |
| 658 break; | |
| 659 case PR_DESC_SOCKET_UDP: | |
| 660 fd = PR_ImportUDPSocket(osfd); | |
| 661 break; | |
| 662 default: | |
| 663 PR_ASSERT(0); | |
| 664 PR_SetError(PR_UNKNOWN_ERROR, 0); | |
| 665 fd = NULL; | |
| 666 break; | |
| 667 } | |
| 668 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 fd->secret->inheritable = _PR_TRI_TRUE; | |
| 675 } | |
| 676 return fd; | |
| 677 } | |
| 678 /* Skip three colons */ | |
| 679 nColons = 0; | |
| 680 while (*ptr) { | |
| 681 if (*ptr == ':') { | |
| 682 if (++nColons == 3) { | |
| 683 break; | |
| 684 } | |
| 685 } | |
| 686 ptr++; | |
| 687 } | |
| 688 if (*ptr == '\0') { | |
| 689 PR_SetError(PR_UNKNOWN_ERROR, 0); | |
| 690 return NULL; | |
| 691 } | |
| 692 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 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 process = PR_CreateProcess(path, argv, envp, attr); | |
| 715 if (NULL == process) { | |
| 716 return PR_FAILURE; | |
| 717 } | |
| 718 rv = PR_DetachProcess(process); | |
| 719 PR_ASSERT(PR_SUCCESS == rv); | |
| 720 if (rv == PR_FAILURE) { | |
| 721 PR_DELETE(process); | |
| 722 return PR_FAILURE; | |
| 723 } | |
| 724 return PR_SUCCESS; | |
| 725 } | |
| 726 | |
| 727 PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process) | |
| 728 { | |
| 729 return _PR_MD_DETACH_PROCESS(process); | |
| 730 } | |
| 731 | |
| 732 PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode) | |
| 733 { | |
| 734 return _PR_MD_WAIT_PROCESS(process, exitCode); | |
| 735 } /* PR_WaitProcess */ | |
| 736 | |
| 737 PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process) | |
| 738 { | |
| 739 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 static void _PR_InitCallOnce(void) { | |
| 756 mod_init.ml = PR_NewLock(); | |
| 757 PR_ASSERT(NULL != mod_init.ml); | |
| 758 mod_init.cv = PR_NewCondVar(mod_init.ml); | |
| 759 PR_ASSERT(NULL != mod_init.cv); | |
| 760 } | |
| 761 | |
| 762 void _PR_CleanupCallOnce() | |
| 763 { | |
| 764 PR_DestroyLock(mod_init.ml); | |
| 765 mod_init.ml = NULL; | |
| 766 PR_DestroyCondVar(mod_init.cv); | |
| 767 mod_init.cv = NULL; | |
| 768 } | |
| 769 | |
| 770 PR_IMPLEMENT(PRStatus) PR_CallOnce( | |
| 771 PRCallOnceType *once, | |
| 772 PRCallOnceFN func) | |
| 773 { | |
| 774 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
| 775 | |
| 776 if (!once->initialized) { | |
| 777 if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) { | |
| 778 once->status = (*func)(); | |
| 779 PR_Lock(mod_init.ml); | |
| 780 once->initialized = 1; | |
| 781 PR_NotifyAllCondVar(mod_init.cv); | |
| 782 PR_Unlock(mod_init.ml); | |
| 783 } else { | |
| 784 PR_Lock(mod_init.ml); | |
| 785 while (!once->initialized) { | |
| 786 PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); | |
| 787 } | |
| 788 PR_Unlock(mod_init.ml); | |
| 789 } | |
| 790 } else { | |
| 791 if (PR_SUCCESS != once->status) { | |
| 792 PR_SetError(PR_CALL_ONCE_ERROR, 0); | |
| 793 } | |
| 794 } | |
| 795 return once->status; | |
| 796 } | |
| 797 | |
| 798 PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg( | |
| 799 PRCallOnceType *once, | |
| 800 PRCallOnceWithArgFN func, | |
| 801 void *arg) | |
| 802 { | |
| 803 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
| 804 | |
| 805 if (!once->initialized) { | |
| 806 if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) { | |
| 807 once->status = (*func)(arg); | |
| 808 PR_Lock(mod_init.ml); | |
| 809 once->initialized = 1; | |
| 810 PR_NotifyAllCondVar(mod_init.cv); | |
| 811 PR_Unlock(mod_init.ml); | |
| 812 } else { | |
| 813 PR_Lock(mod_init.ml); | |
| 814 while (!once->initialized) { | |
| 815 PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); | |
| 816 } | |
| 817 PR_Unlock(mod_init.ml); | |
| 818 } | |
| 819 } else { | |
| 820 if (PR_SUCCESS != once->status) { | |
| 821 PR_SetError(PR_CALL_ONCE_ERROR, 0); | |
| 822 } | |
| 823 } | |
| 824 return once->status; | |
| 825 } | |
| 826 | |
| 827 PRBool _PR_Obsolete(const char *obsolete, const char *preferred) | |
| 828 { | |
| 829 #if defined(DEBUG) | |
| 830 PR_fprintf( | |
| 831 PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n", | |
| 832 obsolete, (NULL == preferred) ? "something else" : preferred); | |
| 833 #endif | |
| 834 return PR_FALSE; | |
| 835 } /* _PR_Obsolete */ | |
| 836 | |
| 837 /* prinit.c */ | |
| 838 | |
| 839 | |
| OLD | NEW |