Coverage Report

Created: 2025-07-11 07:04

/src/nspr/pr/src/misc/prinit.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "primpl.h"
7
#include <ctype.h>
8
#include <string.h>
9
10
PRLogModuleInfo* _pr_clock_lm;
11
PRLogModuleInfo* _pr_cmon_lm;
12
PRLogModuleInfo* _pr_io_lm;
13
PRLogModuleInfo* _pr_cvar_lm;
14
PRLogModuleInfo* _pr_mon_lm;
15
PRLogModuleInfo* _pr_linker_lm;
16
PRLogModuleInfo* _pr_sched_lm;
17
PRLogModuleInfo* _pr_thread_lm;
18
PRLogModuleInfo* _pr_gc_lm;
19
PRLogModuleInfo* _pr_shm_lm;
20
PRLogModuleInfo* _pr_shma_lm;
21
22
PRFileDesc* _pr_stdin;
23
PRFileDesc* _pr_stdout;
24
PRFileDesc* _pr_stderr;
25
26
#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
27
28
PRCList _pr_active_local_threadQ =
29
    PR_INIT_STATIC_CLIST(&_pr_active_local_threadQ);
30
PRCList _pr_active_global_threadQ =
31
    PR_INIT_STATIC_CLIST(&_pr_active_global_threadQ);
32
33
_MDLock _pr_cpuLock; /* lock for the CPU Q */
34
PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ);
35
36
PRUint32 _pr_utid;
37
38
PRInt32 _pr_userActive;
39
PRInt32 _pr_systemActive;
40
PRUintn _pr_maxPTDs;
41
42
#  ifdef _PR_LOCAL_THREADS_ONLY
43
44
struct _PRCPU* _pr_currentCPU;
45
PRThread* _pr_currentThread;
46
PRThread* _pr_lastThread;
47
PRInt32 _pr_intsOff;
48
49
#  endif /* _PR_LOCAL_THREADS_ONLY */
50
51
/* Lock protecting all "termination" condition variables of all threads */
52
PRLock* _pr_terminationCVLock;
53
54
#endif /* !defined(_PR_PTHREADS) */
55
56
PRLock* _pr_sleeplock; /* used in PR_Sleep(), classic and pthreads */
57
58
static void _PR_InitCallOnce(void);
59
60
PRBool _pr_initialized = PR_FALSE;
61
62
0
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
0
  int vmajor = 0, vminor = 0, vpatch = 0;
73
0
  const char* ptr = importedVersion;
74
75
0
  while (isdigit(*ptr)) {
76
0
    vmajor = 10 * vmajor + *ptr - '0';
77
0
    ptr++;
78
0
  }
79
0
  if (*ptr == '.') {
80
0
    ptr++;
81
0
    while (isdigit(*ptr)) {
82
0
      vminor = 10 * vminor + *ptr - '0';
83
0
      ptr++;
84
0
    }
85
0
    if (*ptr == '.') {
86
0
      ptr++;
87
0
      while (isdigit(*ptr)) {
88
0
        vpatch = 10 * vpatch + *ptr - '0';
89
0
        ptr++;
90
0
      }
91
0
    }
92
0
  }
93
94
0
  if (vmajor != PR_VMAJOR) {
95
0
    return PR_FALSE;
96
0
  }
97
0
  if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
98
0
    return PR_FALSE;
99
0
  }
100
0
  if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) {
101
0
    return PR_FALSE;
102
0
  }
103
0
  return PR_TRUE;
104
0
} /* PR_VersionCheck */
105
106
0
PR_IMPLEMENT(const char*) PR_GetVersion(void) { return PR_VERSION; }
107
108
0
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
1
static void _PR_InitStuff(void) {
130
1
  if (_pr_initialized) {
131
0
    return;
132
0
  }
133
1
  _pr_initialized = PR_TRUE;
134
1
#ifdef _PR_ZONE_ALLOCATOR
135
1
  _PR_InitZones();
136
1
#endif
137
#ifdef WINNT
138
  _pr_SetNativeThreadsOnlyMode();
139
#endif
140
141
1
  (void)PR_GetPageSize();
142
143
1
  _pr_clock_lm = PR_NewLogModule("clock");
144
1
  _pr_cmon_lm = PR_NewLogModule("cmon");
145
1
  _pr_io_lm = PR_NewLogModule("io");
146
1
  _pr_mon_lm = PR_NewLogModule("mon");
147
1
  _pr_linker_lm = PR_NewLogModule("linker");
148
1
  _pr_cvar_lm = PR_NewLogModule("cvar");
149
1
  _pr_sched_lm = PR_NewLogModule("sched");
150
1
  _pr_thread_lm = PR_NewLogModule("thread");
151
1
  _pr_gc_lm = PR_NewLogModule("gc");
152
1
  _pr_shm_lm = PR_NewLogModule("shm");
153
1
  _pr_shma_lm = PR_NewLogModule("shma");
154
155
  /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */
156
1
  _PR_MD_EARLY_INIT();
157
158
1
  _PR_InitLocks();
159
1
  _PR_InitAtomic();
160
1
  _PR_InitSegs();
161
1
  _PR_InitStacks();
162
1
  _PR_InitTPD();
163
1
  _PR_InitEnv();
164
1
  _PR_InitLayerCache();
165
1
  _PR_InitClock();
166
167
1
  _pr_sleeplock = PR_NewLock();
168
1
  PR_ASSERT(NULL != _pr_sleeplock);
169
170
1
  _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
171
172
1
#ifndef _PR_GLOBAL_THREADS_ONLY
173
1
  _PR_InitCPUs();
174
1
#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
1
  _PR_InitCMon();
185
1
  _PR_InitIO();
186
1
  _PR_InitNet();
187
1
  _PR_InitTime();
188
1
  _PR_InitLog();
189
1
  _PR_InitLinker();
190
1
  _PR_InitCallOnce();
191
1
  _PR_InitDtoa();
192
1
  _PR_InitMW();
193
1
  _PR_InitRWLocks();
194
195
1
  nspr_InitializePRErrorTable();
196
197
1
  _PR_MD_FINAL_INIT();
198
1
}
199
200
1
void _PR_ImplicitInitialization(void) {
201
1
  _PR_InitStuff();
202
203
  /* Enable interrupts */
204
#if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY)
205
  _PR_MD_START_INTERRUPTS();
206
#endif
207
1
}
208
209
0
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
0
}
218
219
0
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
0
}
227
228
0
PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) {
229
#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
230
  _PR_MD_BLOCK_CLOCK_INTERRUPTS();
231
#endif
232
0
}
233
234
0
PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void) {
235
#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
236
  _PR_MD_UNBLOCK_CLOCK_INTERRUPTS();
237
#endif
238
0
}
239
240
PR_IMPLEMENT(void)
241
0
PR_Init(PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) {
242
0
  _PR_ImplicitInitialization();
243
0
}
244
245
PR_IMPLEMENT(PRIntn)
246
PR_Initialize(PRPrimordialFn prmain, PRIntn argc, char** argv,
247
0
              PRUintn maxPTDs) {
248
0
  PRIntn rv;
249
0
  _PR_ImplicitInitialization();
250
0
  rv = prmain(argc, argv);
251
0
  PR_Cleanup();
252
0
  return rv;
253
0
} /* 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
0
PR_NewProcessAttr(void) {
424
0
  PRProcessAttr* attr;
425
426
0
  attr = PR_NEWZAP(PRProcessAttr);
427
0
  if (!attr) {
428
0
    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
429
0
  }
430
0
  return attr;
431
0
}
432
433
PR_IMPLEMENT(void)
434
0
PR_ResetProcessAttr(PRProcessAttr* attr) {
435
0
  PR_FREEIF(attr->currentDirectory);
436
0
  PR_FREEIF(attr->fdInheritBuffer);
437
0
  memset(attr, 0, sizeof(*attr));
438
0
}
439
440
PR_IMPLEMENT(void)
441
0
PR_DestroyProcessAttr(PRProcessAttr* attr) {
442
0
  PR_FREEIF(attr->currentDirectory);
443
0
  PR_FREEIF(attr->fdInheritBuffer);
444
0
  PR_DELETE(attr);
445
0
}
446
447
PR_IMPLEMENT(void)
448
PR_ProcessAttrSetStdioRedirect(PRProcessAttr* attr, PRSpecialFD stdioFd,
449
0
                               PRFileDesc* redirectFd) {
450
0
  switch (stdioFd) {
451
0
    case PR_StandardInput:
452
0
      attr->stdinFd = redirectFd;
453
0
      break;
454
0
    case PR_StandardOutput:
455
0
      attr->stdoutFd = redirectFd;
456
0
      break;
457
0
    case PR_StandardError:
458
0
      attr->stderrFd = redirectFd;
459
0
      break;
460
0
    default:
461
0
      PR_ASSERT(0);
462
0
  }
463
0
}
464
465
/*
466
 * OBSOLETE
467
 */
468
PR_IMPLEMENT(void)
469
PR_SetStdioRedirect(PRProcessAttr* attr, PRSpecialFD stdioFd,
470
0
                    PRFileDesc* redirectFd) {
471
0
#if defined(DEBUG)
472
0
  static PRBool warn = PR_TRUE;
473
0
  if (warn) {
474
0
    warn = _PR_Obsolete("PR_SetStdioRedirect()",
475
0
                        "PR_ProcessAttrSetStdioRedirect()");
476
0
  }
477
0
#endif
478
0
  PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd);
479
0
}
480
481
PR_IMPLEMENT(PRStatus)
482
0
PR_ProcessAttrSetCurrentDirectory(PRProcessAttr* attr, const char* dir) {
483
0
  PR_FREEIF(attr->currentDirectory);
484
0
  attr->currentDirectory = (char*)PR_MALLOC(strlen(dir) + 1);
485
0
  if (!attr->currentDirectory) {
486
0
    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
487
0
    return PR_FAILURE;
488
0
  }
489
0
  strcpy(attr->currentDirectory, dir);
490
0
  return PR_SUCCESS;
491
0
}
492
493
PR_IMPLEMENT(PRStatus)
494
PR_ProcessAttrSetInheritableFD(PRProcessAttr* attr, PRFileDesc* fd,
495
0
                               const char* name) {
496
  /* We malloc the fd inherit buffer in multiples of this number. */
497
0
#define FD_INHERIT_BUFFER_INCR 128
498
  /* The length of "NSPR_INHERIT_FDS=" */
499
0
#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
0
#  define OSFD_STRLEN 10
505
0
#endif
506
  /* The length of fd type (PRDescType) printed in decimal */
507
0
#define FD_TYPE_STRLEN 1
508
0
  PRSize newSize;
509
0
  int remainder;
510
0
  char* newBuffer;
511
0
  int nwritten;
512
0
  char* cur;
513
0
  int freeSize;
514
515
0
  if (fd->identity != PR_NSPR_IO_LAYER) {
516
0
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
517
0
    return PR_FAILURE;
518
0
  }
519
0
  if (fd->secret->inheritable == _PR_TRI_UNKNOWN) {
520
0
    _PR_MD_QUERY_FD_INHERITABLE(fd);
521
0
  }
522
0
  if (fd->secret->inheritable != _PR_TRI_TRUE) {
523
0
    PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0);
524
0
    return PR_FAILURE;
525
0
  }
526
527
  /*
528
   * We also need to account for the : separators and the
529
   * terminating null byte.
530
   */
531
0
  if (NULL == attr->fdInheritBuffer) {
532
    /* The first time, we print "NSPR_INHERIT_FDS=<name>:<type>:<val>" */
533
0
    newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name) + FD_TYPE_STRLEN +
534
0
              OSFD_STRLEN + 2 + 1;
535
0
  } else {
536
    /* At other times, we print ":<name>:<type>:<val>" */
537
0
    newSize = attr->fdInheritBufferUsed + strlen(name) + FD_TYPE_STRLEN +
538
0
              OSFD_STRLEN + 3 + 1;
539
0
  }
540
0
  if (newSize > attr->fdInheritBufferSize) {
541
    /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */
542
0
    remainder = newSize % FD_INHERIT_BUFFER_INCR;
543
0
    if (remainder != 0) {
544
0
      newSize += (FD_INHERIT_BUFFER_INCR - remainder);
545
0
    }
546
0
    if (NULL == attr->fdInheritBuffer) {
547
0
      newBuffer = (char*)PR_MALLOC(newSize);
548
0
    } else {
549
0
      newBuffer = (char*)PR_REALLOC(attr->fdInheritBuffer, newSize);
550
0
    }
551
0
    if (NULL == newBuffer) {
552
0
      PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
553
0
      return PR_FAILURE;
554
0
    }
555
0
    attr->fdInheritBuffer = newBuffer;
556
0
    attr->fdInheritBufferSize = newSize;
557
0
  }
558
0
  cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed;
559
0
  freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed;
560
0
  if (0 == attr->fdInheritBufferUsed) {
561
0
    nwritten =
562
0
        PR_snprintf(cur, freeSize, "NSPR_INHERIT_FDS=%s:%d:0x%" PR_PRIxOSFD,
563
0
                    name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
564
0
  } else {
565
0
    nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%" PR_PRIxOSFD, name,
566
0
                           (PRIntn)fd->methods->file_type, fd->secret->md.osfd);
567
0
  }
568
0
  attr->fdInheritBufferUsed += nwritten;
569
0
  return PR_SUCCESS;
570
0
}
571
572
0
PR_IMPLEMENT(PRFileDesc*) PR_GetInheritedFD(const char* name) {
573
0
  PRFileDesc* fd;
574
0
  const char* envVar;
575
0
  const char* ptr;
576
0
  int len = strlen(name);
577
0
  PROsfd osfd;
578
0
  int nColons;
579
0
  PRIntn fileType;
580
581
0
  envVar = PR_GetEnv("NSPR_INHERIT_FDS");
582
0
  if (NULL == envVar || '\0' == envVar[0]) {
583
0
    PR_SetError(PR_UNKNOWN_ERROR, 0);
584
0
    return NULL;
585
0
  }
586
587
0
  ptr = envVar;
588
0
  while (1) {
589
0
    if ((ptr[len] == ':') && (strncmp(ptr, name, len) == 0)) {
590
0
      ptr += len + 1;
591
0
      if (PR_sscanf(ptr, "%d:0x%" PR_SCNxOSFD, &fileType, &osfd) != 2) {
592
0
        PR_SetError(PR_UNKNOWN_ERROR, 0);
593
0
        return NULL;
594
0
      }
595
0
      switch ((PRDescType)fileType) {
596
0
        case PR_DESC_FILE:
597
0
          fd = PR_ImportFile(osfd);
598
0
          break;
599
0
        case PR_DESC_PIPE:
600
0
          fd = PR_ImportPipe(osfd);
601
0
          break;
602
0
        case PR_DESC_SOCKET_TCP:
603
0
          fd = PR_ImportTCPSocket(osfd);
604
0
          break;
605
0
        case PR_DESC_SOCKET_UDP:
606
0
          fd = PR_ImportUDPSocket(osfd);
607
0
          break;
608
0
        default:
609
0
          PR_ASSERT(0);
610
0
          PR_SetError(PR_UNKNOWN_ERROR, 0);
611
0
          fd = NULL;
612
0
          break;
613
0
      }
614
0
      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
0
        fd->secret->inheritable = _PR_TRI_TRUE;
621
0
      }
622
0
      return fd;
623
0
    }
624
    /* Skip three colons */
625
0
    nColons = 0;
626
0
    while (*ptr) {
627
0
      if (*ptr == ':') {
628
0
        if (++nColons == 3) {
629
0
          break;
630
0
        }
631
0
      }
632
0
      ptr++;
633
0
    }
634
0
    if (*ptr == '\0') {
635
0
      PR_SetError(PR_UNKNOWN_ERROR, 0);
636
0
      return NULL;
637
0
    }
638
0
    ptr++;
639
0
  }
640
0
}
641
642
PR_IMPLEMENT(PRProcess*)
643
PR_CreateProcess(const char* path, char* const* argv, char* const* envp,
644
0
                 const PRProcessAttr* attr) {
645
0
  return _PR_MD_CREATE_PROCESS(path, argv, envp, attr);
646
0
} /* PR_CreateProcess */
647
648
PR_IMPLEMENT(PRStatus)
649
PR_CreateProcessDetached(const char* path, char* const* argv, char* const* envp,
650
0
                         const PRProcessAttr* attr) {
651
0
  PRProcess* process;
652
0
  PRStatus rv;
653
654
0
  process = PR_CreateProcess(path, argv, envp, attr);
655
0
  if (NULL == process) {
656
0
    return PR_FAILURE;
657
0
  }
658
0
  rv = PR_DetachProcess(process);
659
0
  PR_ASSERT(PR_SUCCESS == rv);
660
0
  if (rv == PR_FAILURE) {
661
0
    PR_DELETE(process);
662
0
    return PR_FAILURE;
663
0
  }
664
0
  return PR_SUCCESS;
665
0
}
666
667
0
PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess* process) {
668
0
  return _PR_MD_DETACH_PROCESS(process);
669
0
}
670
671
0
PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess* process, PRInt32* exitCode) {
672
0
  return _PR_MD_WAIT_PROCESS(process, exitCode);
673
0
} /* PR_WaitProcess */
674
675
0
PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess* process) {
676
0
  return _PR_MD_KILL_PROCESS(process);
677
0
}
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
1
static void _PR_InitCallOnce(void) {
693
1
  mod_init.ml = PR_NewLock();
694
1
  PR_ASSERT(NULL != mod_init.ml);
695
1
  mod_init.cv = PR_NewCondVar(mod_init.ml);
696
1
  PR_ASSERT(NULL != mod_init.cv);
697
1
}
698
699
0
void _PR_CleanupCallOnce() {
700
0
  PR_DestroyLock(mod_init.ml);
701
0
  mod_init.ml = NULL;
702
0
  PR_DestroyCondVar(mod_init.cv);
703
0
  mod_init.cv = NULL;
704
0
}
705
706
17.4k
PR_IMPLEMENT(PRStatus) PR_CallOnce(PRCallOnceType* once, PRCallOnceFN func) {
707
17.4k
  if (!_pr_initialized) {
708
1
    _PR_ImplicitInitialization();
709
1
  }
710
711
17.4k
  PR_Lock(mod_init.ml);
712
17.4k
  PRIntn initialized = once->initialized;
713
17.4k
  PRStatus status = once->status;
714
17.4k
  PR_Unlock(mod_init.ml);
715
17.4k
  if (!initialized) {
716
7
    if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) {
717
7
      status = (*func)();
718
7
      PR_Lock(mod_init.ml);
719
7
      once->status = status;
720
7
      once->initialized = 1;
721
7
      PR_NotifyAllCondVar(mod_init.cv);
722
7
      PR_Unlock(mod_init.ml);
723
7
    } else {
724
0
      PR_Lock(mod_init.ml);
725
0
      while (!once->initialized) {
726
0
        PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
727
0
      }
728
0
      status = once->status;
729
0
      PR_Unlock(mod_init.ml);
730
0
      if (PR_SUCCESS != status) {
731
0
        PR_SetError(PR_CALL_ONCE_ERROR, 0);
732
0
      }
733
0
    }
734
7
    return status;
735
7
  }
736
17.4k
  if (PR_SUCCESS != status) {
737
0
    PR_SetError(PR_CALL_ONCE_ERROR, 0);
738
0
  }
739
17.4k
  return status;
740
17.4k
}
741
742
PR_IMPLEMENT(PRStatus)
743
118
PR_CallOnceWithArg(PRCallOnceType* once, PRCallOnceWithArgFN func, void* arg) {
744
118
  if (!_pr_initialized) {
745
0
    _PR_ImplicitInitialization();
746
0
  }
747
748
118
  PR_Lock(mod_init.ml);
749
118
  PRIntn initialized = once->initialized;
750
118
  PRStatus status = once->status;
751
118
  PR_Unlock(mod_init.ml);
752
118
  if (!initialized) {
753
2
    if (PR_ATOMIC_SET(&once->inProgress, 1) == 0) {
754
2
      status = (*func)(arg);
755
2
      PR_Lock(mod_init.ml);
756
2
      once->status = status;
757
2
      once->initialized = 1;
758
2
      PR_NotifyAllCondVar(mod_init.cv);
759
2
      PR_Unlock(mod_init.ml);
760
2
    } else {
761
0
      PR_Lock(mod_init.ml);
762
0
      while (!once->initialized) {
763
0
        PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
764
0
      }
765
0
      status = once->status;
766
0
      PR_Unlock(mod_init.ml);
767
0
      if (PR_SUCCESS != status) {
768
0
        PR_SetError(PR_CALL_ONCE_ERROR, 0);
769
0
      }
770
0
    }
771
2
    return status;
772
2
  }
773
116
  if (PR_SUCCESS != status) {
774
0
    PR_SetError(PR_CALL_ONCE_ERROR, 0);
775
0
  }
776
116
  return status;
777
118
}
778
779
0
PRBool _PR_Obsolete(const char* obsolete, const char* preferred) {
780
0
#if defined(DEBUG)
781
0
  PR_fprintf(PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n", obsolete,
782
0
             (NULL == preferred) ? "something else" : preferred);
783
0
#endif
784
0
  return PR_FALSE;
785
0
} /* _PR_Obsolete */
786
787
/* prinit.c */