nsprpub/pr/src/misc/prinit.c

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

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

mercurial