Wed, 31 Dec 2014 06:55:46 +0100
Added tag TORBROWSER_REPLICA for changeset 6474c204b198
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 *) ⊤ |
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 |