tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */