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