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