security/nss/lib/util/nssilock.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/util/nssilock.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,498 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * nssilock.c - NSS lock instrumentation wrapper functions
    1.10 + *
    1.11 + * NOTE - These are not public interfaces
    1.12 + *
    1.13 + * Implementation Notes:
    1.14 + * I've tried to make the instrumentation relatively non-intrusive.
    1.15 + * To do this, I have used a single PR_LOG() call in each
    1.16 + * instrumented function. There's room for improvement.
    1.17 + *
    1.18 + *
    1.19 + */
    1.20 +
    1.21 +#include "prinit.h"
    1.22 +#include "prerror.h"
    1.23 +#include "prlock.h"
    1.24 +#include "prmem.h"
    1.25 +#include "prenv.h"
    1.26 +#include "prcvar.h"
    1.27 +#include "prio.h"
    1.28 +
    1.29 +#if defined(NEED_NSS_ILOCK)
    1.30 +#include "prlog.h"
    1.31 +#include "nssilock.h"
    1.32 +
    1.33 +/*
    1.34 +** Declare the instrumented PZLock 
    1.35 +*/
    1.36 +struct pzlock_s {
    1.37 +    PRLock *lock;  /* the PZLock to be instrumented */
    1.38 +    PRIntervalTime time; /* timestamp when the lock was aquired */
    1.39 +    nssILockType ltype;
    1.40 +};
    1.41 +
    1.42 +/*
    1.43 +** Declare the instrumented PZMonitor 
    1.44 +*/
    1.45 +struct pzmonitor_s {
    1.46 +    PRMonitor *mon;   /* the PZMonitor to be instrumented */
    1.47 +    PRIntervalTime time; /* timestamp when the monitor was aquired */
    1.48 +    nssILockType ltype;
    1.49 +};
    1.50 +
    1.51 +/*
    1.52 +** Declare the instrumented PZCondVar
    1.53 +*/
    1.54 +struct pzcondvar_s  {
    1.55 +    PRCondVar   *cvar;  /* the PZCondVar to be instrumented */
    1.56 +    nssILockType ltype;
    1.57 +};
    1.58 +
    1.59 +
    1.60 +/*
    1.61 +** Define a CallOnce type to ensure serialized self-initialization
    1.62 +*/
    1.63 +static PRCallOnceType coNssILock;     /* CallOnce type */
    1.64 +static PRIntn  nssILockInitialized;   /* initialization done when 1 */
    1.65 +static PRLogModuleInfo *nssILog;      /* Log instrumentation to this handle */
    1.66 +
    1.67 +
    1.68 +#define NUM_TT_ENTRIES 6000000
    1.69 +static PRInt32  traceIndex = -1;      /* index into trace table */
    1.70 +static struct pzTrace_s *tt;          /* pointer to trace table */
    1.71 +static PRInt32  ttBufSize = (NUM_TT_ENTRIES * sizeof(struct pzTrace_s ));
    1.72 +static PRCondVar *ttCVar;
    1.73 +static PRLock    *ttLock;
    1.74 +static PRFileDesc *ttfd;              /* trace table file */
    1.75 +
    1.76 +/*
    1.77 +** Vtrace() -- Trace events, write events to external media
    1.78 +**
    1.79 +** Vtrace() records traced events in an in-memory trace table
    1.80 +** when the trace table fills, Vtrace writes the entire table
    1.81 +** to a file.
    1.82 +**
    1.83 +** data can be lost!
    1.84 +**
    1.85 +*/
    1.86 +static void Vtrace(
    1.87 +    nssILockOp      op,
    1.88 +    nssILockType    ltype,
    1.89 +    PRIntervalTime  callTime,
    1.90 +    PRIntervalTime  heldTime,
    1.91 +    void            *lock,
    1.92 +    PRIntn          line,
    1.93 +    char            *file
    1.94 +)  {
    1.95 +    PRInt32 idx;
    1.96 +    struct pzTrace_s *tp;
    1.97 +
    1.98 +RetryTrace:
    1.99 +    idx = PR_ATOMIC_INCREMENT( &traceIndex );
   1.100 +    while( NUM_TT_ENTRIES <= idx || op == FlushTT ) {
   1.101 +        if( NUM_TT_ENTRIES == idx  || op == FlushTT )  {
   1.102 +            int writeSize = idx * sizeof(struct pzTrace_s);
   1.103 +            PR_Lock(ttLock);
   1.104 +            PR_Write( ttfd, tt, writeSize );
   1.105 +            traceIndex = -1;
   1.106 +            PR_NotifyAllCondVar( ttCVar );
   1.107 +            PR_Unlock(ttLock);
   1.108 +            goto RetryTrace;
   1.109 +        } else {
   1.110 +            PR_Lock(ttLock);
   1.111 +            while( NUM_TT_ENTRIES < idx )
   1.112 +                PR_WaitCondVar(ttCVar, PR_INTERVAL_NO_WAIT);
   1.113 +            PR_Unlock(ttLock);
   1.114 +            goto RetryTrace;
   1.115 +        }
   1.116 +    } /* end while() */
   1.117 +
   1.118 +    /* create the trace entry */
   1.119 +    tp = tt + idx;
   1.120 +    tp->threadID = PR_GetThreadID(PR_GetCurrentThread());
   1.121 +    tp->op = op;
   1.122 +    tp->ltype = ltype;
   1.123 +    tp->callTime = callTime;
   1.124 +    tp->heldTime = heldTime;
   1.125 +    tp->lock = lock;
   1.126 +    tp ->line = line;
   1.127 +    strcpy(tp->file, file );
   1.128 +    return;
   1.129 +} /* --- end Vtrace() --- */
   1.130 +
   1.131 +/*
   1.132 +** pz_TraceFlush() -- Force trace table write to file
   1.133 +**
   1.134 +*/
   1.135 +extern void pz_TraceFlush( void )
   1.136 +{
   1.137 +    Vtrace( FlushTT, nssILockSelfServ, 0, 0, NULL, 0, "" );
   1.138 +    return;
   1.139 +} /* --- end pz_TraceFlush() --- */
   1.140 +
   1.141 +/*
   1.142 +** nssILockInit() -- Initialization for nssilock
   1.143 +**
   1.144 +** This function is called from the CallOnce mechanism.
   1.145 +*/
   1.146 +static PRStatus
   1.147 +    nssILockInit( void ) 
   1.148 +{   
   1.149 +    int i;
   1.150 +    nssILockInitialized = 1;
   1.151 +
   1.152 +    /* new log module */
   1.153 +    nssILog = PR_NewLogModule("nssilock");
   1.154 +    if ( NULL == nssILog )  {
   1.155 +        return(PR_FAILURE);
   1.156 +    }
   1.157 +
   1.158 +    tt = PR_Calloc( NUM_TT_ENTRIES, sizeof(struct pzTrace_s));
   1.159 +    if (NULL == tt ) {
   1.160 +        fprintf(stderr, "nssilock: can't allocate trace table\n");
   1.161 +        exit(1);
   1.162 +    }
   1.163 +
   1.164 +    ttfd = PR_Open( "xxxTTLog", PR_CREATE_FILE | PR_WRONLY, 0666 );
   1.165 +    if ( NULL == ttfd )  {
   1.166 +        fprintf( stderr, "Oh Drat! Can't open 'xxxTTLog'\n");
   1.167 +        exit(1);
   1.168 +    }
   1.169 +
   1.170 +    ttLock = PR_NewLock();
   1.171 +    ttCVar = PR_NewCondVar(ttLock);
   1.172 +
   1.173 +    return(PR_SUCCESS);
   1.174 +} /* --- end nssILockInit() --- */
   1.175 +
   1.176 +extern PZLock * pz_NewLock( 
   1.177 +    nssILockType ltype,
   1.178 +    char *file,  
   1.179 +    PRIntn line )
   1.180 +{
   1.181 +    PRStatus rc;
   1.182 +    PZLock  *lock;
   1.183 +    
   1.184 +    /* Self Initialize the nssILock feature */
   1.185 +    if (!nssILockInitialized)  {
   1.186 +        rc = PR_CallOnce( &coNssILock, nssILockInit );
   1.187 +        if ( PR_FAILURE == rc ) {
   1.188 +            PR_SetError( PR_UNKNOWN_ERROR, 0 );
   1.189 +            return( NULL );
   1.190 +        }
   1.191 +    }
   1.192 +
   1.193 +    lock = PR_NEWZAP( PZLock );
   1.194 +    if ( NULL != lock )  {
   1.195 +        lock->ltype = ltype;
   1.196 +        lock->lock = PR_NewLock();
   1.197 +        if ( NULL == lock->lock )  {
   1.198 +            PR_DELETE( lock );
   1.199 +            PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.200 +        }
   1.201 +    } else {
   1.202 +            PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.203 +    }
   1.204 +
   1.205 +    Vtrace( NewLock, ltype, 0, 0, lock, line, file );
   1.206 +    return(lock);
   1.207 +} /* --- end pz_NewLock() --- */
   1.208 +
   1.209 +extern void
   1.210 +    pz_Lock(
   1.211 +        PZLock *lock,
   1.212 +        char *file,
   1.213 +        PRIntn line
   1.214 +    )
   1.215 +{            
   1.216 +    PRIntervalTime callTime;
   1.217 +
   1.218 +    callTime = PR_IntervalNow();
   1.219 +    PR_Lock( lock->lock );
   1.220 +    lock->time = PR_IntervalNow();
   1.221 +    callTime = lock->time - callTime;
   1.222 +
   1.223 +    Vtrace( Lock, lock->ltype, callTime, 0, lock, line, file );
   1.224 +    return;
   1.225 +} /* --- end  pz_Lock() --- */
   1.226 +
   1.227 +extern PRStatus
   1.228 +    pz_Unlock(
   1.229 +        PZLock *lock,
   1.230 +        char *file,
   1.231 +        PRIntn line
   1.232 +    ) 
   1.233 +{
   1.234 +    PRStatus rc;
   1.235 +    PRIntervalTime callTime, now, heldTime;
   1.236 +
   1.237 +    callTime = PR_IntervalNow();
   1.238 +    rc = PR_Unlock( lock->lock );
   1.239 +    now = PR_IntervalNow(); 
   1.240 +    callTime = now - callTime;
   1.241 +    heldTime = now - lock->time;
   1.242 +    Vtrace( Unlock, lock->ltype, callTime, heldTime, lock, line, file );
   1.243 +    return( rc );
   1.244 +} /* --- end  pz_Unlock() --- */
   1.245 +
   1.246 +extern void
   1.247 +    pz_DestroyLock(
   1.248 +        PZLock *lock,
   1.249 +        char *file,
   1.250 +        PRIntn line
   1.251 +    )
   1.252 +{
   1.253 +    Vtrace( DestroyLock, lock->ltype, 0, 0, lock, line, file );
   1.254 +    PR_DestroyLock( lock->lock );
   1.255 +    PR_DELETE( lock );
   1.256 +    return;
   1.257 +} /* --- end  pz_DestroyLock() --- */
   1.258 +
   1.259 +
   1.260 +
   1.261 +extern PZCondVar *
   1.262 +    pz_NewCondVar(
   1.263 +        PZLock *lock,
   1.264 +        char *file,
   1.265 +        PRIntn line
   1.266 +    )
   1.267 +{
   1.268 +    PZCondVar *cvar;
   1.269 +
   1.270 +    cvar = PR_NEWZAP( PZCondVar );
   1.271 +    if ( NULL == cvar ) {
   1.272 +        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.273 +    } else {
   1.274 +        cvar->ltype = lock->ltype; 
   1.275 +        cvar->cvar = PR_NewCondVar( lock->lock );
   1.276 +        if ( NULL == cvar->cvar )  {
   1.277 +            PR_DELETE( cvar );
   1.278 +            PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.279 +        }
   1.280 +
   1.281 +    }
   1.282 +    Vtrace( NewCondVar, lock->ltype, 0, 0, cvar, line, file );
   1.283 +    return( cvar );
   1.284 +} /* --- end  pz_NewCondVar() --- */
   1.285 +
   1.286 +extern void
   1.287 +    pz_DestroyCondVar(
   1.288 +        PZCondVar *cvar,
   1.289 +        char *file,
   1.290 +        PRIntn line
   1.291 +    )
   1.292 +{
   1.293 +    Vtrace( DestroyCondVar, cvar->ltype, 0, 0, cvar, line, file );
   1.294 +    PR_DestroyCondVar( cvar->cvar );
   1.295 +    PR_DELETE( cvar );
   1.296 +} /* --- end  pz_DestroyCondVar() --- */
   1.297 +
   1.298 +extern PRStatus
   1.299 +    pz_WaitCondVar(
   1.300 +        PZCondVar *cvar,
   1.301 +        PRIntervalTime timeout,
   1.302 +        char *file,
   1.303 +        PRIntn line
   1.304 +    )
   1.305 +{
   1.306 +    PRStatus    rc;
   1.307 +    PRIntervalTime callTime;
   1.308 +
   1.309 +    callTime = PR_IntervalNow();
   1.310 +    rc = PR_WaitCondVar( cvar->cvar, timeout );
   1.311 +    callTime = PR_IntervalNow() - callTime;
   1.312 +    
   1.313 +    Vtrace( WaitCondVar, cvar->ltype, callTime, 0, cvar, line, file );
   1.314 +    return(rc);
   1.315 +} /* --- end  pz_WaitCondVar() --- */
   1.316 +
   1.317 +extern PRStatus
   1.318 +    pz_NotifyCondVar(
   1.319 +        PZCondVar *cvar,
   1.320 +        char *file,
   1.321 +        PRIntn line
   1.322 +    )
   1.323 +{
   1.324 +    PRStatus    rc;
   1.325 +    
   1.326 +    rc = PR_NotifyCondVar( cvar->cvar );
   1.327 +    
   1.328 +    Vtrace( NotifyCondVar, cvar->ltype, 0, 0, cvar, line, file );
   1.329 +    return(rc);
   1.330 +} /* --- end  pz_NotifyCondVar() --- */
   1.331 +
   1.332 +extern PRStatus
   1.333 +    pz_NotifyAllCondVar(
   1.334 +        PZCondVar *cvar,
   1.335 +        char *file,
   1.336 +        PRIntn line
   1.337 +    )
   1.338 +{
   1.339 +    PRStatus    rc;
   1.340 +    
   1.341 +    rc = PR_NotifyAllCondVar( cvar->cvar );
   1.342 +    
   1.343 +    Vtrace( NotifyAllCondVar, cvar->ltype, 0, 0, cvar, line, file );
   1.344 +    return(rc);
   1.345 +} /* --- end  pz_NotifyAllCondVar() --- */
   1.346 +
   1.347 +extern PZMonitor *
   1.348 +    pz_NewMonitor( 
   1.349 +        nssILockType ltype,
   1.350 +        char *file,
   1.351 +        PRIntn line
   1.352 +    )
   1.353 +{
   1.354 +    PRStatus rc;
   1.355 +    PZMonitor   *mon;
   1.356 +
   1.357 +    /* Self Initialize the nssILock feature */
   1.358 +    if (!nssILockInitialized)  {
   1.359 +        rc = PR_CallOnce( &coNssILock, nssILockInit );
   1.360 +        if ( PR_FAILURE == rc ) {
   1.361 +            PR_SetError( PR_UNKNOWN_ERROR, 0 );
   1.362 +            return( NULL );
   1.363 +        }
   1.364 +    }
   1.365 +
   1.366 +    mon = PR_NEWZAP( PZMonitor );
   1.367 +    if ( NULL != mon )  {
   1.368 +        mon->ltype = ltype;
   1.369 +        mon->mon = PR_NewMonitor();
   1.370 +        if ( NULL == mon->mon )  {
   1.371 +            PR_DELETE( mon );
   1.372 +            PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.373 +        }
   1.374 +    } else {
   1.375 +        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.376 +    }
   1.377 +
   1.378 +    Vtrace( NewMonitor, ltype, 0, 0, mon, line, file );
   1.379 +    return(mon);
   1.380 +} /* --- end  pz_NewMonitor() --- */
   1.381 +
   1.382 +extern void
   1.383 +    pz_DestroyMonitor(
   1.384 +        PZMonitor *mon,
   1.385 +        char *file,
   1.386 +        PRIntn line
   1.387 +    )
   1.388 +{
   1.389 +    Vtrace( DestroyMonitor, mon->ltype, 0, 0, mon, line, file );
   1.390 +    PR_DestroyMonitor( mon->mon );
   1.391 +    PR_DELETE( mon );
   1.392 +    return;                
   1.393 +} /* --- end  pz_DestroyMonitor() --- */
   1.394 +
   1.395 +extern void
   1.396 +    pz_EnterMonitor(
   1.397 +        PZMonitor *mon,
   1.398 +        char *file,
   1.399 +        PRIntn line
   1.400 +    )
   1.401 +{
   1.402 +    PRIntervalTime callTime, now;
   1.403 +
   1.404 +    callTime = PR_IntervalNow();
   1.405 +    PR_EnterMonitor( mon->mon );
   1.406 +    now = PR_IntervalNow();
   1.407 +    callTime = now - callTime;
   1.408 +    if ( PR_GetMonitorEntryCount(mon->mon) == 1 )  {
   1.409 +        mon->time = now;
   1.410 +    }
   1.411 +    Vtrace( EnterMonitor, mon->ltype, callTime, 0, mon, line, file );
   1.412 +    return;
   1.413 +} /* --- end  pz_EnterMonitor() --- */
   1.414 +
   1.415 +extern PRStatus
   1.416 +    pz_ExitMonitor(
   1.417 +        PZMonitor *mon,
   1.418 +        char *file,
   1.419 +        PRIntn line
   1.420 +    )
   1.421 +{
   1.422 +    PRStatus rc;
   1.423 +    PRIntervalTime callTime, now, heldTime;
   1.424 +    PRIntn  mec = PR_GetMonitorEntryCount( mon->mon );
   1.425 +   
   1.426 +    heldTime = (PRIntervalTime)-1; 
   1.427 +    callTime = PR_IntervalNow();
   1.428 +    rc = PR_ExitMonitor( mon->mon );
   1.429 +    now = PR_IntervalNow();
   1.430 +    callTime = now - callTime;
   1.431 +    if ( mec == 1 )
   1.432 +        heldTime = now - mon->time;
   1.433 +    Vtrace( ExitMonitor, mon->ltype, callTime, heldTime, mon, line, file );
   1.434 +    return( rc );
   1.435 +} /* --- end  pz_ExitMonitor() --- */
   1.436 +
   1.437 +extern PRIntn
   1.438 +    pz_GetMonitorEntryCount(
   1.439 +        PZMonitor *mon,
   1.440 +        char *file,
   1.441 +        PRIntn line
   1.442 +    )
   1.443 +{
   1.444 +    return( PR_GetMonitorEntryCount(mon->mon));
   1.445 +} /* --- end pz_GetMonitorEntryCount() --- */
   1.446 +
   1.447 +
   1.448 +extern PRStatus
   1.449 +    pz_Wait(
   1.450 +        PZMonitor *mon,
   1.451 +        PRIntervalTime ticks,
   1.452 +        char *file,
   1.453 +        PRIntn line
   1.454 +    )
   1.455 +{
   1.456 +    PRStatus rc;
   1.457 +    PRIntervalTime callTime;
   1.458 +
   1.459 +    callTime = PR_IntervalNow();
   1.460 +    rc = PR_Wait( mon->mon, ticks );
   1.461 +    callTime = PR_IntervalNow() - callTime;
   1.462 +    Vtrace( Wait, mon->ltype, callTime, 0, mon, line, file );
   1.463 +    return( rc );
   1.464 +} /* --- end  pz_Wait() --- */
   1.465 +
   1.466 +extern PRStatus
   1.467 +    pz_Notify(
   1.468 +        PZMonitor *mon,
   1.469 +        char *file,
   1.470 +        PRIntn line
   1.471 +    )
   1.472 +{
   1.473 +    PRStatus rc;
   1.474 +    PRIntervalTime callTime;
   1.475 +
   1.476 +    callTime = PR_IntervalNow();
   1.477 +    rc = PR_Notify( mon->mon );
   1.478 +    callTime = PR_IntervalNow() - callTime;
   1.479 +    Vtrace( Notify, mon->ltype, callTime, 0, mon, line, file );
   1.480 +    return( rc );
   1.481 +} /* --- end  pz_Notify() --- */
   1.482 +
   1.483 +extern PRStatus
   1.484 +    pz_NotifyAll(
   1.485 +        PZMonitor *mon,
   1.486 +        char *file,
   1.487 +        PRIntn line
   1.488 +    )
   1.489 +{
   1.490 +    PRStatus rc;
   1.491 +    PRIntervalTime callTime;
   1.492 +
   1.493 +    callTime = PR_IntervalNow();
   1.494 +    rc = PR_NotifyAll( mon->mon );
   1.495 +    callTime = PR_IntervalNow() - callTime;
   1.496 +    Vtrace( NotifyAll, mon->ltype, callTime, 0, mon, line, file );
   1.497 +    return( rc );
   1.498 +} /* --- end  pz_NotifyAll() --- */
   1.499 +
   1.500 +#endif /* NEED_NSS_ILOCK */
   1.501 +/* --- end nssilock.c --------------------------------- */

mercurial