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