Coverage Report

Created: 2024-02-25 06:31

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