tor-browser

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

nssilock.c (11335B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6 * nssilock.c - NSS lock instrumentation wrapper functions
      7 *
      8 * NOTE - These are not public interfaces
      9 *
     10 * Implementation Notes:
     11 * I've tried to make the instrumentation relatively non-intrusive.
     12 * To do this, I have used a single PR_LOG() call in each
     13 * instrumented function. There's room for improvement.
     14 *
     15 *
     16 */
     17 
     18 #include "prinit.h"
     19 #include "prerror.h"
     20 #include "prlock.h"
     21 #include "prmem.h"
     22 #include "prenv.h"
     23 #include "prcvar.h"
     24 #include "prio.h"
     25 
     26 #if defined(NEED_NSS_ILOCK)
     27 #include "prlog.h"
     28 #include "nssilock.h"
     29 
     30 /*
     31 ** Declare the instrumented PZLock
     32 */
     33 struct pzlock_s {
     34    PRLock *lock;        /* the PZLock to be instrumented */
     35    PRIntervalTime time; /* timestamp when the lock was aquired */
     36    nssILockType ltype;
     37 };
     38 
     39 /*
     40 ** Declare the instrumented PZMonitor
     41 */
     42 struct pzmonitor_s {
     43    PRMonitor *mon;      /* the PZMonitor to be instrumented */
     44    PRIntervalTime time; /* timestamp when the monitor was aquired */
     45    nssILockType ltype;
     46 };
     47 
     48 /*
     49 ** Declare the instrumented PZCondVar
     50 */
     51 struct pzcondvar_s {
     52    PRCondVar *cvar; /* the PZCondVar to be instrumented */
     53    nssILockType ltype;
     54 };
     55 
     56 /*
     57 ** Define a CallOnce type to ensure serialized self-initialization
     58 */
     59 static PRCallOnceType coNssILock;  /* CallOnce type */
     60 static PRIntn nssILockInitialized; /* initialization done when 1 */
     61 static PRLogModuleInfo *nssILog;   /* Log instrumentation to this handle */
     62 
     63 #define NUM_TT_ENTRIES 6000000
     64 static PRInt32 traceIndex = -1; /* index into trace table */
     65 static struct pzTrace_s *tt;    /* pointer to trace table */
     66 static PRInt32 ttBufSize = (NUM_TT_ENTRIES * sizeof(struct pzTrace_s));
     67 static PRCondVar *ttCVar;
     68 static PRLock *ttLock;
     69 static PRFileDesc *ttfd; /* trace table file */
     70 
     71 /*
     72 ** Vtrace() -- Trace events, write events to external media
     73 **
     74 ** Vtrace() records traced events in an in-memory trace table
     75 ** when the trace table fills, Vtrace writes the entire table
     76 ** to a file.
     77 **
     78 ** data can be lost!
     79 **
     80 */
     81 static void
     82 Vtrace(
     83    nssILockOp op,
     84    nssILockType ltype,
     85    PRIntervalTime callTime,
     86    PRIntervalTime heldTime,
     87    void *lock,
     88    PRIntn line,
     89    char *file)
     90 {
     91    PRInt32 idx;
     92    struct pzTrace_s *tp;
     93 
     94 RetryTrace:
     95    idx = PR_ATOMIC_INCREMENT(&traceIndex);
     96    while (NUM_TT_ENTRIES <= idx || op == FlushTT) {
     97        if (NUM_TT_ENTRIES == idx || op == FlushTT) {
     98            int writeSize = idx * sizeof(struct pzTrace_s);
     99            PR_Lock(ttLock);
    100            PR_Write(ttfd, tt, writeSize);
    101            traceIndex = -1;
    102            PR_NotifyAllCondVar(ttCVar);
    103            PR_Unlock(ttLock);
    104            goto RetryTrace;
    105        } else {
    106            PR_Lock(ttLock);
    107            while (NUM_TT_ENTRIES < idx)
    108                PR_WaitCondVar(ttCVar, PR_INTERVAL_NO_WAIT);
    109            PR_Unlock(ttLock);
    110            goto RetryTrace;
    111        }
    112    } /* end while() */
    113 
    114    /* create the trace entry */
    115    tp = tt + idx;
    116    tp->threadID = PR_GetThreadID(PR_GetCurrentThread());
    117    tp->op = op;
    118    tp->ltype = ltype;
    119    tp->callTime = callTime;
    120    tp->heldTime = heldTime;
    121    tp->lock = lock;
    122    tp->line = line;
    123    strcpy(tp->file, file);
    124    return;
    125 } /* --- end Vtrace() --- */
    126 
    127 /*
    128 ** pz_TraceFlush() -- Force trace table write to file
    129 **
    130 */
    131 extern void
    132 pz_TraceFlush(void)
    133 {
    134    Vtrace(FlushTT, nssILockSelfServ, 0, 0, NULL, 0, "");
    135    return;
    136 } /* --- end pz_TraceFlush() --- */
    137 
    138 /*
    139 ** nssILockInit() -- Initialization for nssilock
    140 **
    141 ** This function is called from the CallOnce mechanism.
    142 */
    143 static PRStatus
    144 nssILockInit(void)
    145 {
    146    int i;
    147    nssILockInitialized = 1;
    148 
    149    /* new log module */
    150    nssILog = PR_NewLogModule("nssilock");
    151    if (NULL == nssILog) {
    152        return (PR_FAILURE);
    153    }
    154 
    155    tt = PR_Calloc(NUM_TT_ENTRIES, sizeof(struct pzTrace_s));
    156    if (NULL == tt) {
    157        fprintf(stderr, "nssilock: can't allocate trace table\n");
    158        exit(1);
    159    }
    160 
    161    ttfd = PR_Open("xxxTTLog", PR_CREATE_FILE | PR_WRONLY, 0666);
    162    if (NULL == ttfd) {
    163        fprintf(stderr, "Oh Drat! Can't open 'xxxTTLog'\n");
    164        exit(1);
    165    }
    166 
    167    ttLock = PR_NewLock();
    168    ttCVar = PR_NewCondVar(ttLock);
    169 
    170    return (PR_SUCCESS);
    171 } /* --- end nssILockInit() --- */
    172 
    173 extern PZLock *
    174 pz_NewLock(
    175    nssILockType ltype,
    176    char *file,
    177    PRIntn line)
    178 {
    179    PRStatus rc;
    180    PZLock *lock;
    181 
    182    /* Self Initialize the nssILock feature */
    183    if (!nssILockInitialized) {
    184        rc = PR_CallOnce(&coNssILock, nssILockInit);
    185        if (PR_FAILURE == rc) {
    186            PR_SetError(PR_UNKNOWN_ERROR, 0);
    187            return (NULL);
    188        }
    189    }
    190 
    191    lock = PR_NEWZAP(PZLock);
    192    if (NULL != lock) {
    193        lock->ltype = ltype;
    194        lock->lock = PR_NewLock();
    195        if (NULL == lock->lock) {
    196            PR_DELETE(lock);
    197            PORT_SetError(SEC_ERROR_NO_MEMORY);
    198        }
    199    } else {
    200        PORT_SetError(SEC_ERROR_NO_MEMORY);
    201    }
    202 
    203    Vtrace(NewLock, ltype, 0, 0, lock, line, file);
    204    return (lock);
    205 } /* --- end pz_NewLock() --- */
    206 
    207 extern void
    208 pz_Lock(
    209    PZLock *lock,
    210    char *file,
    211    PRIntn line)
    212 {
    213    PRIntervalTime callTime;
    214 
    215    callTime = PR_IntervalNow();
    216    PR_Lock(lock->lock);
    217    lock->time = PR_IntervalNow();
    218    callTime = lock->time - callTime;
    219 
    220    Vtrace(Lock, lock->ltype, callTime, 0, lock, line, file);
    221    return;
    222 } /* --- end  pz_Lock() --- */
    223 
    224 extern PRStatus
    225 pz_Unlock(
    226    PZLock *lock,
    227    char *file,
    228    PRIntn line)
    229 {
    230    PRStatus rc;
    231    PRIntervalTime callTime, now, heldTime;
    232 
    233    callTime = PR_IntervalNow();
    234    rc = PR_Unlock(lock->lock);
    235    now = PR_IntervalNow();
    236    callTime = now - callTime;
    237    heldTime = now - lock->time;
    238    Vtrace(Unlock, lock->ltype, callTime, heldTime, lock, line, file);
    239    return (rc);
    240 } /* --- end  pz_Unlock() --- */
    241 
    242 extern void
    243 pz_DestroyLock(
    244    PZLock *lock,
    245    char *file,
    246    PRIntn line)
    247 {
    248    Vtrace(DestroyLock, lock->ltype, 0, 0, lock, line, file);
    249    PR_DestroyLock(lock->lock);
    250    PR_DELETE(lock);
    251    return;
    252 } /* --- end  pz_DestroyLock() --- */
    253 
    254 extern PZCondVar *
    255 pz_NewCondVar(
    256    PZLock *lock,
    257    char *file,
    258    PRIntn line)
    259 {
    260    PZCondVar *cvar;
    261 
    262    cvar = PR_NEWZAP(PZCondVar);
    263    if (NULL == cvar) {
    264        PORT_SetError(SEC_ERROR_NO_MEMORY);
    265    } else {
    266        cvar->ltype = lock->ltype;
    267        cvar->cvar = PR_NewCondVar(lock->lock);
    268        if (NULL == cvar->cvar) {
    269            PR_DELETE(cvar);
    270            PORT_SetError(SEC_ERROR_NO_MEMORY);
    271        }
    272    }
    273    Vtrace(NewCondVar, lock->ltype, 0, 0, cvar, line, file);
    274    return (cvar);
    275 } /* --- end  pz_NewCondVar() --- */
    276 
    277 extern void
    278 pz_DestroyCondVar(
    279    PZCondVar *cvar,
    280    char *file,
    281    PRIntn line)
    282 {
    283    Vtrace(DestroyCondVar, cvar->ltype, 0, 0, cvar, line, file);
    284    PR_DestroyCondVar(cvar->cvar);
    285    PR_DELETE(cvar);
    286 } /* --- end  pz_DestroyCondVar() --- */
    287 
    288 extern PRStatus
    289 pz_WaitCondVar(
    290    PZCondVar *cvar,
    291    PRIntervalTime timeout,
    292    char *file,
    293    PRIntn line)
    294 {
    295    PRStatus rc;
    296    PRIntervalTime callTime;
    297 
    298    callTime = PR_IntervalNow();
    299    rc = PR_WaitCondVar(cvar->cvar, timeout);
    300    callTime = PR_IntervalNow() - callTime;
    301 
    302    Vtrace(WaitCondVar, cvar->ltype, callTime, 0, cvar, line, file);
    303    return (rc);
    304 } /* --- end  pz_WaitCondVar() --- */
    305 
    306 extern PRStatus
    307 pz_NotifyCondVar(
    308    PZCondVar *cvar,
    309    char *file,
    310    PRIntn line)
    311 {
    312    PRStatus rc;
    313 
    314    rc = PR_NotifyCondVar(cvar->cvar);
    315 
    316    Vtrace(NotifyCondVar, cvar->ltype, 0, 0, cvar, line, file);
    317    return (rc);
    318 } /* --- end  pz_NotifyCondVar() --- */
    319 
    320 extern PRStatus
    321 pz_NotifyAllCondVar(
    322    PZCondVar *cvar,
    323    char *file,
    324    PRIntn line)
    325 {
    326    PRStatus rc;
    327 
    328    rc = PR_NotifyAllCondVar(cvar->cvar);
    329 
    330    Vtrace(NotifyAllCondVar, cvar->ltype, 0, 0, cvar, line, file);
    331    return (rc);
    332 } /* --- end  pz_NotifyAllCondVar() --- */
    333 
    334 extern PZMonitor *
    335 pz_NewMonitor(
    336    nssILockType ltype,
    337    char *file,
    338    PRIntn line)
    339 {
    340    PRStatus rc;
    341    PZMonitor *mon;
    342 
    343    /* Self Initialize the nssILock feature */
    344    if (!nssILockInitialized) {
    345        rc = PR_CallOnce(&coNssILock, nssILockInit);
    346        if (PR_FAILURE == rc) {
    347            PR_SetError(PR_UNKNOWN_ERROR, 0);
    348            return (NULL);
    349        }
    350    }
    351 
    352    mon = PR_NEWZAP(PZMonitor);
    353    if (NULL != mon) {
    354        mon->ltype = ltype;
    355        mon->mon = PR_NewMonitor();
    356        if (NULL == mon->mon) {
    357            PR_DELETE(mon);
    358            PORT_SetError(SEC_ERROR_NO_MEMORY);
    359        }
    360    } else {
    361        PORT_SetError(SEC_ERROR_NO_MEMORY);
    362    }
    363 
    364    Vtrace(NewMonitor, ltype, 0, 0, mon, line, file);
    365    return (mon);
    366 } /* --- end  pz_NewMonitor() --- */
    367 
    368 extern void
    369 pz_DestroyMonitor(
    370    PZMonitor *mon,
    371    char *file,
    372    PRIntn line)
    373 {
    374    Vtrace(DestroyMonitor, mon->ltype, 0, 0, mon, line, file);
    375    PR_DestroyMonitor(mon->mon);
    376    PR_DELETE(mon);
    377    return;
    378 } /* --- end  pz_DestroyMonitor() --- */
    379 
    380 extern void
    381 pz_EnterMonitor(
    382    PZMonitor *mon,
    383    char *file,
    384    PRIntn line)
    385 {
    386    PRIntervalTime callTime, now;
    387 
    388    callTime = PR_IntervalNow();
    389    PR_EnterMonitor(mon->mon);
    390    now = PR_IntervalNow();
    391    callTime = now - callTime;
    392    if (PR_GetMonitorEntryCount(mon->mon) == 1) {
    393        mon->time = now;
    394    }
    395    Vtrace(EnterMonitor, mon->ltype, callTime, 0, mon, line, file);
    396    return;
    397 } /* --- end  pz_EnterMonitor() --- */
    398 
    399 extern PRStatus
    400 pz_ExitMonitor(
    401    PZMonitor *mon,
    402    char *file,
    403    PRIntn line)
    404 {
    405    PRStatus rc;
    406    PRIntervalTime callTime, now, heldTime;
    407    PRIntn mec = PR_GetMonitorEntryCount(mon->mon);
    408 
    409    heldTime = (PRIntervalTime)-1;
    410    callTime = PR_IntervalNow();
    411    rc = PR_ExitMonitor(mon->mon);
    412    now = PR_IntervalNow();
    413    callTime = now - callTime;
    414    if (mec == 1)
    415        heldTime = now - mon->time;
    416    Vtrace(ExitMonitor, mon->ltype, callTime, heldTime, mon, line, file);
    417    return (rc);
    418 } /* --- end  pz_ExitMonitor() --- */
    419 
    420 extern PRIntn
    421 pz_GetMonitorEntryCount(
    422    PZMonitor *mon,
    423    char *file,
    424    PRIntn line)
    425 {
    426    return (PR_GetMonitorEntryCount(mon->mon));
    427 } /* --- end pz_GetMonitorEntryCount() --- */
    428 
    429 extern PRStatus
    430 pz_Wait(
    431    PZMonitor *mon,
    432    PRIntervalTime ticks,
    433    char *file,
    434    PRIntn line)
    435 {
    436    PRStatus rc;
    437    PRIntervalTime callTime;
    438 
    439    callTime = PR_IntervalNow();
    440    rc = PR_Wait(mon->mon, ticks);
    441    callTime = PR_IntervalNow() - callTime;
    442    Vtrace(Wait, mon->ltype, callTime, 0, mon, line, file);
    443    return (rc);
    444 } /* --- end  pz_Wait() --- */
    445 
    446 extern PRStatus
    447 pz_Notify(
    448    PZMonitor *mon,
    449    char *file,
    450    PRIntn line)
    451 {
    452    PRStatus rc;
    453    PRIntervalTime callTime;
    454 
    455    callTime = PR_IntervalNow();
    456    rc = PR_Notify(mon->mon);
    457    callTime = PR_IntervalNow() - callTime;
    458    Vtrace(Notify, mon->ltype, callTime, 0, mon, line, file);
    459    return (rc);
    460 } /* --- end  pz_Notify() --- */
    461 
    462 extern PRStatus
    463 pz_NotifyAll(
    464    PZMonitor *mon,
    465    char *file,
    466    PRIntn line)
    467 {
    468    PRStatus rc;
    469    PRIntervalTime callTime;
    470 
    471    callTime = PR_IntervalNow();
    472    rc = PR_NotifyAll(mon->mon);
    473    callTime = PR_IntervalNow() - callTime;
    474    Vtrace(NotifyAll, mon->ltype, callTime, 0, mon, line, file);
    475    return (rc);
    476 } /* --- end  pz_NotifyAll() --- */
    477 
    478 #endif /* NEED_NSS_ILOCK */
    479 /* --- end nssilock.c --------------------------------- */