security/nss/lib/util/nssilock.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial