| OLD | NEW |
| (Empty) |
| 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
| 2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 5 | |
| 6 /* | |
| 7 ** prtrace.c -- NSPR Trace Instrumentation | |
| 8 ** | |
| 9 ** Implement the API defined in prtrace.h | |
| 10 ** | |
| 11 ** | |
| 12 ** | |
| 13 */ | |
| 14 | |
| 15 #include <string.h> | |
| 16 #include "primpl.h" | |
| 17 | |
| 18 | |
| 19 #define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 ) | |
| 20 #define DEFAULT_BUFFER_SEGMENTS 2 | |
| 21 | |
| 22 /* | |
| 23 ** Enumerate states in a RName structure | |
| 24 */ | |
| 25 typedef enum TraceState | |
| 26 { | |
| 27 Running = 1, | |
| 28 Suspended = 2 | |
| 29 } TraceState; | |
| 30 | |
| 31 /* | |
| 32 ** Define QName structure | |
| 33 */ | |
| 34 typedef struct QName | |
| 35 { | |
| 36 PRCList link; | |
| 37 PRCList rNameList; | |
| 38 char name[PRTRACE_NAME_MAX+1]; | |
| 39 } QName; | |
| 40 | |
| 41 /* | |
| 42 ** Define RName structure | |
| 43 */ | |
| 44 typedef struct RName | |
| 45 { | |
| 46 PRCList link; | |
| 47 PRLock *lock; | |
| 48 QName *qName; | |
| 49 TraceState state; | |
| 50 char name[PRTRACE_NAME_MAX+1]; | |
| 51 char desc[PRTRACE_DESC_MAX+1]; | |
| 52 } RName; | |
| 53 | |
| 54 | |
| 55 /* | |
| 56 ** The Trace Facility database | |
| 57 ** | |
| 58 */ | |
| 59 static PRLogModuleInfo *lm; | |
| 60 | |
| 61 static PRLock *traceLock; /* Facility Lock */ | |
| 62 static PRCList qNameList; /* anchor to all QName structures */ | |
| 63 static TraceState traceState = Running; | |
| 64 | |
| 65 /* | |
| 66 ** in-memory trace buffer controls | |
| 67 */ | |
| 68 static PRTraceEntry *tBuf; /* pointer to buffer */ | |
| 69 static PRInt32 bufSize; /* size of buffer, in bytes, rounded up to s
izeof(PRTraceEntry) */ | |
| 70 static volatile PRInt32 next; /* index to next PRTraceEntry */ | |
| 71 static PRInt32 last; /* index of highest numbered trace entry */ | |
| 72 | |
| 73 /* | |
| 74 ** Real-time buffer capture controls | |
| 75 */ | |
| 76 static PRInt32 fetchLastSeen = 0; | |
| 77 static PRBool fetchLostData = PR_FALSE; | |
| 78 | |
| 79 /* | |
| 80 ** Buffer write-to-file controls | |
| 81 */ | |
| 82 static PRLock *logLock; /* Sync lock */ | |
| 83 static PRCondVar *logCVar; /* Sync Condidtion Variable */ | |
| 84 /* | |
| 85 ** Inter-thread state communication. | |
| 86 ** Controling thread writes to logOrder under protection of logCVar | |
| 87 ** the logging thread reads logOrder and sets logState on Notify. | |
| 88 ** | |
| 89 ** logSegments, logCount, logLostData must be read and written under | |
| 90 ** protection of logLock, logCVar. | |
| 91 ** | |
| 92 */ | |
| 93 static enum LogState | |
| 94 { | |
| 95 LogNotRunning, /* Initial state */ | |
| 96 LogReset, /* Causes logger to re-calc controls */ | |
| 97 LogActive, /* Logging in progress, set only by log thread */ | |
| 98 LogSuspend, /* Suspend Logging */ | |
| 99 LogResume, /* Resume Logging => LogActive */ | |
| 100 LogStop /* Stop the log thread */ | |
| 101 } logOrder, logState, localState; /* controlling state variables */ | |
| 102 static PRInt32 logSegments; /* Number of buffer segments */ | |
| 103 static PRInt32 logEntries; /* number of Trace Entries in the bu
ffer */ | |
| 104 static PRInt32 logEntriesPerSegment; /* number of PRTraceEntries per buff
er segment */ | |
| 105 static PRInt32 logSegSize; /* size of buffer segment */ | |
| 106 static PRInt32 logCount; /* number of segments pending output
*/ | |
| 107 static PRInt32 logLostData; /* number of lost log buffer segment
s */ | |
| 108 | |
| 109 /* | |
| 110 ** end Trace Database | |
| 111 ** | |
| 112 */ | |
| 113 | |
| 114 /* | |
| 115 ** _PR_InitializeTrace() -- Initialize the trace facility | |
| 116 */ | |
| 117 static void NewTraceBuffer( PRInt32 size ) | |
| 118 { | |
| 119 /* | |
| 120 ** calculate the size of the buffer | |
| 121 ** round down so that each segment has the same number of | |
| 122 ** trace entries | |
| 123 */ | |
| 124 logSegments = DEFAULT_BUFFER_SEGMENTS; | |
| 125 logEntries = size / sizeof(PRTraceEntry); | |
| 126 logEntriesPerSegment = logEntries / logSegments; | |
| 127 logEntries = logSegments * logEntriesPerSegment; | |
| 128 bufSize = logEntries * sizeof(PRTraceEntry); | |
| 129 logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry); | |
| 130 PR_ASSERT( bufSize != 0); | |
| 131 PR_LOG( lm, PR_LOG_ERROR, | |
| 132 ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegmen
t: %ld, logSegSize: %ld", | |
| 133 logSegments, logEntries, logEntriesPerSegment, logSegSize )); | |
| 134 | |
| 135 | |
| 136 tBuf = PR_Malloc( bufSize ); | |
| 137 if ( tBuf == NULL ) | |
| 138 { | |
| 139 PR_LOG( lm, PR_LOG_ERROR, | |
| 140 ("PRTrace: Failed to get trace buffer")); | |
| 141 PR_ASSERT( 0 ); | |
| 142 } | |
| 143 else | |
| 144 { | |
| 145 PR_LOG( lm, PR_LOG_NOTICE, | |
| 146 ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf)); | |
| 147 } | |
| 148 | |
| 149 next = 0; | |
| 150 last = logEntries -1; | |
| 151 logCount = 0; | |
| 152 logLostData = PR_TRUE; /* not really on first call */ | |
| 153 logOrder = LogReset; | |
| 154 | |
| 155 } /* end NewTraceBuffer() */ | |
| 156 | |
| 157 /* | |
| 158 ** _PR_InitializeTrace() -- Initialize the trace facility | |
| 159 */ | |
| 160 static void _PR_InitializeTrace( void ) | |
| 161 { | |
| 162 /* The lock pointer better be null on this call */ | |
| 163 PR_ASSERT( traceLock == NULL ); | |
| 164 | |
| 165 traceLock = PR_NewLock(); | |
| 166 PR_ASSERT( traceLock != NULL ); | |
| 167 | |
| 168 PR_Lock( traceLock ); | |
| 169 | |
| 170 PR_INIT_CLIST( &qNameList ); | |
| 171 | |
| 172 lm = PR_NewLogModule("trace"); | |
| 173 | |
| 174 bufSize = DEFAULT_TRACE_BUFSIZE; | |
| 175 NewTraceBuffer( bufSize ); | |
| 176 | |
| 177 /* Initialize logging controls */ | |
| 178 logLock = PR_NewLock(); | |
| 179 logCVar = PR_NewCondVar( logLock ); | |
| 180 | |
| 181 PR_Unlock( traceLock ); | |
| 182 return; | |
| 183 } /* end _PR_InitializeTrace() */ | |
| 184 | |
| 185 /* | |
| 186 ** Create a Trace Handle | |
| 187 */ | |
| 188 PR_IMPLEMENT(PRTraceHandle) | |
| 189 PR_CreateTrace( | |
| 190 const char *qName, /* QName for this trace handle */ | |
| 191 const char *rName, /* RName for this trace handle */ | |
| 192 const char *description /* description for this trace handle */ | |
| 193 ) | |
| 194 { | |
| 195 QName *qnp; | |
| 196 RName *rnp; | |
| 197 PRBool matchQname = PR_FALSE; | |
| 198 | |
| 199 /* Self initialize, if necessary */ | |
| 200 if ( traceLock == NULL ) | |
| 201 _PR_InitializeTrace(); | |
| 202 | |
| 203 /* Validate input arguments */ | |
| 204 PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX ); | |
| 205 PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX ); | |
| 206 PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX ); | |
| 207 | |
| 208 PR_LOG( lm, PR_LOG_DEBUG, | |
| 209 ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName)); | |
| 210 | |
| 211 /* Lock the Facility */ | |
| 212 PR_Lock( traceLock ); | |
| 213 | |
| 214 /* Do we already have a matching QName? */ | |
| 215 if (!PR_CLIST_IS_EMPTY( &qNameList )) | |
| 216 { | |
| 217 qnp = (QName *) PR_LIST_HEAD( &qNameList ); | |
| 218 do { | |
| 219 if ( strcmp(qnp->name, qName) == 0) | |
| 220 { | |
| 221 matchQname = PR_TRUE; | |
| 222 break; | |
| 223 } | |
| 224 qnp = (QName *)PR_NEXT_LINK( &qnp->link ); | |
| 225 } while( qnp != (QName *)&qNameList ); | |
| 226 } | |
| 227 /* | |
| 228 ** If we did not find a matching QName, | |
| 229 ** allocate one and initialize it. | |
| 230 ** link it onto the qNameList. | |
| 231 ** | |
| 232 */ | |
| 233 if ( matchQname != PR_TRUE ) | |
| 234 { | |
| 235 qnp = PR_NEWZAP( QName ); | |
| 236 PR_ASSERT( qnp != NULL ); | |
| 237 PR_INIT_CLIST( &qnp->link ); | |
| 238 PR_INIT_CLIST( &qnp->rNameList ); | |
| 239 strcpy( qnp->name, qName ); | |
| 240 PR_APPEND_LINK( &qnp->link, &qNameList ); | |
| 241 } | |
| 242 | |
| 243 /* Do we already have a matching RName? */ | |
| 244 if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) | |
| 245 { | |
| 246 rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); | |
| 247 do { | |
| 248 /* | |
| 249 ** No duplicate RNames are allowed within a QName | |
| 250 ** | |
| 251 */ | |
| 252 PR_ASSERT( strcmp(rnp->name, rName)); | |
| 253 rnp = (RName *)PR_NEXT_LINK( &rnp->link ); | |
| 254 } while( rnp != (RName *)&qnp->rNameList ); | |
| 255 } | |
| 256 | |
| 257 /* Get a new RName structure; initialize its members */ | |
| 258 rnp = PR_NEWZAP( RName ); | |
| 259 PR_ASSERT( rnp != NULL ); | |
| 260 PR_INIT_CLIST( &rnp->link ); | |
| 261 strcpy( rnp->name, rName ); | |
| 262 strcpy( rnp->desc, description ); | |
| 263 rnp->lock = PR_NewLock(); | |
| 264 rnp->state = Running; | |
| 265 if ( rnp->lock == NULL ) | |
| 266 { | |
| 267 PR_ASSERT(0); | |
| 268 } | |
| 269 | |
| 270 PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnLis
t */ | |
| 271 rnp->qName = qnp; /* point the RName to the QName */ | |
| 272 | |
| 273 /* Unlock the Facility */ | |
| 274 PR_Unlock( traceLock ); | |
| 275 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t"
, | |
| 276 qName, qnp, rName, rnp )); | |
| 277 | |
| 278 return((PRTraceHandle)rnp); | |
| 279 } /* end PR_CreateTrace() */ | |
| 280 | |
| 281 /* | |
| 282 ** | |
| 283 */ | |
| 284 PR_IMPLEMENT(void) | |
| 285 PR_DestroyTrace( | |
| 286 PRTraceHandle handle /* Handle to be destroyed */ | |
| 287 ) | |
| 288 { | |
| 289 RName *rnp = (RName *)handle; | |
| 290 QName *qnp = rnp->qName; | |
| 291 | |
| 292 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", | |
| 293 qnp->name, rnp->name)); | |
| 294 | |
| 295 /* Lock the Facility */ | |
| 296 PR_Lock( traceLock ); | |
| 297 | |
| 298 /* | |
| 299 ** Remove RName from the list of RNames in QName | |
| 300 ** and free RName | |
| 301 */ | |
| 302 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", | |
| 303 rnp->name, rnp)); | |
| 304 PR_REMOVE_LINK( &rnp->link ); | |
| 305 PR_Free( rnp->lock ); | |
| 306 PR_DELETE( rnp ); | |
| 307 | |
| 308 /* | |
| 309 ** If this is the last RName within QName | |
| 310 ** remove QName from the qNameList and free it | |
| 311 */ | |
| 312 if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) | |
| 313 { | |
| 314 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", | |
| 315 qnp->name, qnp)); | |
| 316 PR_REMOVE_LINK( &qnp->link ); | |
| 317 PR_DELETE( qnp ); | |
| 318 } | |
| 319 | |
| 320 /* Unlock the Facility */ | |
| 321 PR_Unlock( traceLock ); | |
| 322 return; | |
| 323 } /* end PR_DestroyTrace() */ | |
| 324 | |
| 325 /* | |
| 326 ** Create a TraceEntry in the trace buffer | |
| 327 */ | |
| 328 PR_IMPLEMENT(void) | |
| 329 PR_Trace( | |
| 330 PRTraceHandle handle, /* use this trace handle */ | |
| 331 PRUint32 userData0, /* User supplied data word 0 */ | |
| 332 PRUint32 userData1, /* User supplied data word 1 */ | |
| 333 PRUint32 userData2, /* User supplied data word 2 */ | |
| 334 PRUint32 userData3, /* User supplied data word 3 */ | |
| 335 PRUint32 userData4, /* User supplied data word 4 */ | |
| 336 PRUint32 userData5, /* User supplied data word 5 */ | |
| 337 PRUint32 userData6, /* User supplied data word 6 */ | |
| 338 PRUint32 userData7 /* User supplied data word 7 */ | |
| 339 ) | |
| 340 { | |
| 341 PRTraceEntry *tep; | |
| 342 PRInt32 mark; | |
| 343 | |
| 344 if ( (traceState == Suspended ) | |
| 345 || ( ((RName *)handle)->state == Suspended )) | |
| 346 return; | |
| 347 | |
| 348 /* | |
| 349 ** Get the next trace entry slot w/ minimum delay | |
| 350 */ | |
| 351 PR_Lock( traceLock ); | |
| 352 | |
| 353 tep = &tBuf[next++]; | |
| 354 if ( next > last ) | |
| 355 next = 0; | |
| 356 if ( fetchLostData == PR_FALSE && next == fetchLastSeen ) | |
| 357 fetchLostData = PR_TRUE; | |
| 358 | |
| 359 mark = next; | |
| 360 | |
| 361 PR_Unlock( traceLock ); | |
| 362 | |
| 363 /* | |
| 364 ** We have a trace entry. Fill it in. | |
| 365 */ | |
| 366 tep->thread = PR_GetCurrentThread(); | |
| 367 tep->handle = handle; | |
| 368 tep->time = PR_Now(); | |
| 369 tep->userData[0] = userData0; | |
| 370 tep->userData[1] = userData1; | |
| 371 tep->userData[2] = userData2; | |
| 372 tep->userData[3] = userData3; | |
| 373 tep->userData[4] = userData4; | |
| 374 tep->userData[5] = userData5; | |
| 375 tep->userData[6] = userData6; | |
| 376 tep->userData[7] = userData7; | |
| 377 | |
| 378 /* When buffer segment is full, signal trace log thread to run */ | |
| 379 if (( mark % logEntriesPerSegment) == 0 ) | |
| 380 { | |
| 381 PR_Lock( logLock ); | |
| 382 logCount++; | |
| 383 PR_NotifyCondVar( logCVar ); | |
| 384 PR_Unlock( logLock ); | |
| 385 /* | |
| 386 ** Gh0D! This is awful! | |
| 387 ** Anyway, to minimize lost trace data segments, | |
| 388 ** I inserted the PR_Sleep(0) to cause a context switch | |
| 389 ** so that the log thread could run. | |
| 390 ** I know, it perturbs the universe and may cause | |
| 391 ** funny things to happen in the optimized builds. | |
| 392 ** Take it out, lose data; leave it in risk Heisenberg. | |
| 393 */ | |
| 394 /* PR_Sleep(0); */ | |
| 395 } | |
| 396 | |
| 397 return; | |
| 398 } /* end PR_Trace() */ | |
| 399 | |
| 400 /* | |
| 401 ** | |
| 402 */ | |
| 403 PR_IMPLEMENT(void) | |
| 404 PR_SetTraceOption( | |
| 405 PRTraceOption command, /* One of the enumerated values */ | |
| 406 void *value /* command value or NULL */ | |
| 407 ) | |
| 408 { | |
| 409 RName * rnp; | |
| 410 | |
| 411 switch ( command ) | |
| 412 { | |
| 413 case PRTraceBufSize : | |
| 414 PR_Lock( traceLock ); | |
| 415 PR_Free( tBuf ); | |
| 416 bufSize = *(PRInt32 *)value; | |
| 417 NewTraceBuffer( bufSize ); | |
| 418 PR_Unlock( traceLock ); | |
| 419 PR_LOG( lm, PR_LOG_DEBUG, | |
| 420 ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize)); | |
| 421 break; | |
| 422 | |
| 423 case PRTraceEnable : | |
| 424 rnp = *(RName **)value; | |
| 425 rnp->state = Running; | |
| 426 PR_LOG( lm, PR_LOG_DEBUG, | |
| 427 ("PRSetTraceOption: PRTraceEnable: %p", rnp)); | |
| 428 break; | |
| 429 | |
| 430 case PRTraceDisable : | |
| 431 rnp = *(RName **)value; | |
| 432 rnp->state = Suspended; | |
| 433 PR_LOG( lm, PR_LOG_DEBUG, | |
| 434 ("PRSetTraceOption: PRTraceDisable: %p", rnp)); | |
| 435 break; | |
| 436 | |
| 437 case PRTraceSuspend : | |
| 438 traceState = Suspended; | |
| 439 PR_LOG( lm, PR_LOG_DEBUG, | |
| 440 ("PRSetTraceOption: PRTraceSuspend")); | |
| 441 break; | |
| 442 | |
| 443 case PRTraceResume : | |
| 444 traceState = Running; | |
| 445 PR_LOG( lm, PR_LOG_DEBUG, | |
| 446 ("PRSetTraceOption: PRTraceResume")); | |
| 447 break; | |
| 448 | |
| 449 case PRTraceSuspendRecording : | |
| 450 PR_Lock( logLock ); | |
| 451 logOrder = LogSuspend; | |
| 452 PR_NotifyCondVar( logCVar ); | |
| 453 PR_Unlock( logLock ); | |
| 454 PR_LOG( lm, PR_LOG_DEBUG, | |
| 455 ("PRSetTraceOption: PRTraceSuspendRecording")); | |
| 456 break; | |
| 457 | |
| 458 case PRTraceResumeRecording : | |
| 459 PR_LOG( lm, PR_LOG_DEBUG, | |
| 460 ("PRSetTraceOption: PRTraceResumeRecording")); | |
| 461 if ( logState != LogSuspend ) | |
| 462 break; | |
| 463 PR_Lock( logLock ); | |
| 464 logOrder = LogResume; | |
| 465 PR_NotifyCondVar( logCVar ); | |
| 466 PR_Unlock( logLock ); | |
| 467 break; | |
| 468 | |
| 469 case PRTraceStopRecording : | |
| 470 PR_Lock( logLock ); | |
| 471 logOrder = LogStop; | |
| 472 PR_NotifyCondVar( logCVar ); | |
| 473 PR_Unlock( logLock ); | |
| 474 PR_LOG( lm, PR_LOG_DEBUG, | |
| 475 ("PRSetTraceOption: PRTraceStopRecording")); | |
| 476 break; | |
| 477 | |
| 478 case PRTraceLockHandles : | |
| 479 PR_LOG( lm, PR_LOG_DEBUG, | |
| 480 ("PRSetTraceOption: PRTraceLockTraceHandles")); | |
| 481 PR_Lock( traceLock ); | |
| 482 break; | |
| 483 | |
| 484 case PRTraceUnLockHandles : | |
| 485 PR_LOG( lm, PR_LOG_DEBUG, | |
| 486 ("PRSetTraceOption: PRTraceUnLockHandles")); | |
| 487 PR_Unlock( traceLock ); | |
| 488 break; | |
| 489 | |
| 490 default: | |
| 491 PR_LOG( lm, PR_LOG_ERROR, | |
| 492 ("PRSetTraceOption: Invalid command %ld", command )); | |
| 493 PR_ASSERT( 0 ); | |
| 494 break; | |
| 495 } /* end switch() */ | |
| 496 return; | |
| 497 } /* end PR_SetTraceOption() */ | |
| 498 | |
| 499 /* | |
| 500 ** | |
| 501 */ | |
| 502 PR_IMPLEMENT(void) | |
| 503 PR_GetTraceOption( | |
| 504 PRTraceOption command, /* One of the enumerated values */ | |
| 505 void *value /* command value or NULL */ | |
| 506 ) | |
| 507 { | |
| 508 switch ( command ) | |
| 509 { | |
| 510 case PRTraceBufSize : | |
| 511 *((PRInt32 *)value) = bufSize; | |
| 512 PR_LOG( lm, PR_LOG_DEBUG, | |
| 513 ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize )); | |
| 514 break; | |
| 515 | |
| 516 default: | |
| 517 PR_LOG( lm, PR_LOG_ERROR, | |
| 518 ("PRGetTraceOption: Invalid command %ld", command )); | |
| 519 PR_ASSERT( 0 ); | |
| 520 break; | |
| 521 } /* end switch() */ | |
| 522 return; | |
| 523 } /* end PR_GetTraceOption() */ | |
| 524 | |
| 525 /* | |
| 526 ** | |
| 527 */ | |
| 528 PR_IMPLEMENT(PRTraceHandle) | |
| 529 PR_GetTraceHandleFromName( | |
| 530 const char *qName, /* QName search argument */ | |
| 531 const char *rName /* RName search argument */ | |
| 532 ) | |
| 533 { | |
| 534 const char *qn, *rn, *desc; | |
| 535 PRTraceHandle qh, rh = NULL; | |
| 536 RName *rnp = NULL; | |
| 537 | |
| 538 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t" | |
| 539 "QName: %s, RName: %s", qName, rName )); | |
| 540 | |
| 541 qh = PR_FindNextTraceQname( NULL ); | |
| 542 while (qh != NULL) | |
| 543 { | |
| 544 rh = PR_FindNextTraceRname( NULL, qh ); | |
| 545 while ( rh != NULL ) | |
| 546 { | |
| 547 PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc ); | |
| 548 if ( (strcmp( qName, qn ) == 0) | |
| 549 && (strcmp( rName, rn ) == 0 )) | |
| 550 { | |
| 551 rnp = (RName *)rh; | |
| 552 goto foundIt; | |
| 553 } | |
| 554 rh = PR_FindNextTraceRname( rh, qh ); | |
| 555 } | |
| 556 qh = PR_FindNextTraceQname( NULL ); | |
| 557 } | |
| 558 | |
| 559 foundIt: | |
| 560 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ))
; | |
| 561 return(rh); | |
| 562 } /* end PR_GetTraceHandleFromName() */ | |
| 563 | |
| 564 /* | |
| 565 ** | |
| 566 */ | |
| 567 PR_IMPLEMENT(void) | |
| 568 PR_GetTraceNameFromHandle( | |
| 569 PRTraceHandle handle, /* handle as search argument */ | |
| 570 const char **qName, /* pointer to associated QName */ | |
| 571 const char **rName, /* pointer to associated RName */ | |
| 572 const char **description /* pointer to associated description */ | |
| 573 ) | |
| 574 { | |
| 575 RName *rnp = (RName *)handle; | |
| 576 QName *qnp = rnp->qName; | |
| 577 | |
| 578 *qName = qnp->name; | |
| 579 *rName = rnp->name; | |
| 580 *description = rnp->desc; | |
| 581 | |
| 582 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: " | |
| 583 "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", | |
| 584 qnp, rnp, qnp->name, rnp->name, rnp->desc )); | |
| 585 | |
| 586 return; | |
| 587 } /* end PR_GetTraceNameFromHandle() */ | |
| 588 | |
| 589 /* | |
| 590 ** | |
| 591 */ | |
| 592 PR_IMPLEMENT(PRTraceHandle) | |
| 593 PR_FindNextTraceQname( | |
| 594 PRTraceHandle handle | |
| 595 ) | |
| 596 { | |
| 597 QName *qnp = (QName *)handle; | |
| 598 | |
| 599 if ( PR_CLIST_IS_EMPTY( &qNameList )) | |
| 600 qnp = NULL; | |
| 601 else if ( qnp == NULL ) | |
| 602 qnp = (QName *)PR_LIST_HEAD( &qNameList ); | |
| 603 else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) | |
| 604 qnp = NULL; | |
| 605 else | |
| 606 qnp = (QName *)PR_NEXT_LINK( &qnp->link ); | |
| 607 | |
| 608 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p"
, | |
| 609 handle, qnp )); | |
| 610 | |
| 611 return((PRTraceHandle)qnp); | |
| 612 } /* end PR_FindNextTraceQname() */ | |
| 613 | |
| 614 /* | |
| 615 ** | |
| 616 */ | |
| 617 PR_IMPLEMENT(PRTraceHandle) | |
| 618 PR_FindNextTraceRname( | |
| 619 PRTraceHandle rhandle, | |
| 620 PRTraceHandle qhandle | |
| 621 ) | |
| 622 { | |
| 623 RName *rnp = (RName *)rhandle; | |
| 624 QName *qnp = (QName *)qhandle; | |
| 625 | |
| 626 | |
| 627 if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) | |
| 628 rnp = NULL; | |
| 629 else if ( rnp == NULL ) | |
| 630 rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); | |
| 631 else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) | |
| 632 rnp = NULL; | |
| 633 else | |
| 634 rnp = (RName *)PR_NEXT_LINK( &rnp->link ); | |
| 635 | |
| 636 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p
, Returns: %p", | |
| 637 rhandle, qhandle, rnp )); | |
| 638 | |
| 639 return((PRTraceHandle)rnp); | |
| 640 } /* end PR_FindNextTraceRname() */ | |
| 641 | |
| 642 /* | |
| 643 ** | |
| 644 */ | |
| 645 static PRFileDesc * InitializeRecording( void ) | |
| 646 { | |
| 647 char *logFileName; | |
| 648 PRFileDesc *logFile; | |
| 649 | |
| 650 /* Self initialize, if necessary */ | |
| 651 if ( traceLock == NULL ) | |
| 652 _PR_InitializeTrace(); | |
| 653 | |
| 654 PR_LOG( lm, PR_LOG_DEBUG, | |
| 655 ("PR_RecordTraceEntries: begins")); | |
| 656 | |
| 657 logLostData = 0; /* reset at entry */ | |
| 658 logState = LogReset; | |
| 659 | |
| 660 /* Get the filename for the logfile from the environment */ | |
| 661 logFileName = PR_GetEnvSecure( "NSPR_TRACE_LOG" ); | |
| 662 if ( logFileName == NULL ) | |
| 663 { | |
| 664 PR_LOG( lm, PR_LOG_ERROR, | |
| 665 ("RecordTraceEntries: Environment variable not defined. Exiting")); | |
| 666 return NULL; | |
| 667 } | |
| 668 | |
| 669 /* Open the logfile */ | |
| 670 logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 ); | |
| 671 if ( logFile == NULL ) | |
| 672 { | |
| 673 PR_LOG( lm, PR_LOG_ERROR, | |
| 674 ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %l
d", | |
| 675 logFileName, PR_GetOSError())); | |
| 676 return NULL; | |
| 677 } | |
| 678 return logFile; | |
| 679 } /* end InitializeRecording() */ | |
| 680 | |
| 681 /* | |
| 682 ** | |
| 683 */ | |
| 684 static void ProcessOrders( void ) | |
| 685 { | |
| 686 switch ( logOrder ) | |
| 687 { | |
| 688 case LogReset : | |
| 689 logOrder = logState = localState; | |
| 690 PR_LOG( lm, PR_LOG_DEBUG, | |
| 691 ("RecordTraceEntries: LogReset")); | |
| 692 break; | |
| 693 | |
| 694 case LogSuspend : | |
| 695 localState = logOrder = logState = LogSuspend; | |
| 696 PR_LOG( lm, PR_LOG_DEBUG, | |
| 697 ("RecordTraceEntries: LogSuspend")); | |
| 698 break; | |
| 699 | |
| 700 case LogResume : | |
| 701 localState = logOrder = logState = LogActive; | |
| 702 PR_LOG( lm, PR_LOG_DEBUG, | |
| 703 ("RecordTraceEntries: LogResume")); | |
| 704 break; | |
| 705 | |
| 706 case LogStop : | |
| 707 logOrder = logState = LogStop; | |
| 708 PR_LOG( lm, PR_LOG_DEBUG, | |
| 709 ("RecordTraceEntries: LogStop")); | |
| 710 break; | |
| 711 | |
| 712 default : | |
| 713 PR_LOG( lm, PR_LOG_ERROR, | |
| 714 ("RecordTraceEntries: Invalid logOrder: %ld", logOrder )); | |
| 715 PR_ASSERT( 0 ); | |
| 716 break; | |
| 717 } /* end switch() */ | |
| 718 return ; | |
| 719 } /* end ProcessOrders() */ | |
| 720 | |
| 721 /* | |
| 722 ** | |
| 723 */ | |
| 724 static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount ) | |
| 725 { | |
| 726 PRInt32 rc; | |
| 727 | |
| 728 | |
| 729 PR_LOG( lm, PR_LOG_ERROR, | |
| 730 ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount)); | |
| 731 rc = PR_Write( logFile, buf , amount ); | |
| 732 if ( rc == -1 ) | |
| 733 PR_LOG( lm, PR_LOG_ERROR, | |
| 734 ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError()
)); | |
| 735 else if ( rc != amount ) | |
| 736 PR_LOG( lm, PR_LOG_ERROR, | |
| 737 ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", a
mount, rc)); | |
| 738 else | |
| 739 PR_LOG( lm, PR_LOG_DEBUG, | |
| 740 ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amou
nt)); | |
| 741 | |
| 742 return; | |
| 743 } /* end WriteTraceSegment() */ | |
| 744 | |
| 745 /* | |
| 746 ** | |
| 747 */ | |
| 748 PR_IMPLEMENT(void) | |
| 749 PR_RecordTraceEntries( | |
| 750 void | |
| 751 ) | |
| 752 { | |
| 753 PRFileDesc *logFile; | |
| 754 PRInt32 lostSegments; | |
| 755 PRInt32 currentSegment = 0; | |
| 756 void *buf; | |
| 757 PRBool doWrite; | |
| 758 | |
| 759 logFile = InitializeRecording(); | |
| 760 if ( logFile == NULL ) | |
| 761 { | |
| 762 PR_LOG( lm, PR_LOG_DEBUG, | |
| 763 ("PR_RecordTraceEntries: Failed to initialize")); | |
| 764 return; | |
| 765 } | |
| 766 | |
| 767 /* Do this until told to stop */ | |
| 768 while ( logState != LogStop ) | |
| 769 { | |
| 770 | |
| 771 PR_Lock( logLock ); | |
| 772 | |
| 773 while ( (logCount == 0) && ( logOrder == logState ) ) | |
| 774 PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT ); | |
| 775 | |
| 776 /* Handle state transitions */ | |
| 777 if ( logOrder != logState ) | |
| 778 ProcessOrders(); | |
| 779 | |
| 780 /* recalculate local controls */ | |
| 781 if ( logCount ) | |
| 782 { | |
| 783 lostSegments = logCount - logSegments; | |
| 784 if ( lostSegments > 0 ) | |
| 785 { | |
| 786 logLostData += ( logCount - logSegments ); | |
| 787 logCount = (logCount % logSegments); | |
| 788 currentSegment = logCount; | |
| 789 PR_LOG( lm, PR_LOG_DEBUG, | |
| 790 ("PR_RecordTraceEntries: LostData segments: %ld", logLostDat
a)); | |
| 791 } | |
| 792 else | |
| 793 { | |
| 794 logCount--; | |
| 795 } | |
| 796 | |
| 797 buf = tBuf + ( logEntriesPerSegment * currentSegment ); | |
| 798 if (++currentSegment >= logSegments ) | |
| 799 currentSegment = 0; | |
| 800 doWrite = PR_TRUE; | |
| 801 } | |
| 802 else | |
| 803 doWrite = PR_FALSE; | |
| 804 | |
| 805 PR_Unlock( logLock ); | |
| 806 | |
| 807 if ( doWrite == PR_TRUE ) | |
| 808 { | |
| 809 if ( localState != LogSuspend ) | |
| 810 WriteTraceSegment( logFile, buf, logSegSize ); | |
| 811 else | |
| 812 PR_LOG( lm, PR_LOG_DEBUG, | |
| 813 ("RecordTraceEntries: PR_Write(): is suspended" )); | |
| 814 } | |
| 815 | |
| 816 } /* end while(logState...) */ | |
| 817 | |
| 818 PR_Close( logFile ); | |
| 819 PR_LOG( lm, PR_LOG_DEBUG, | |
| 820 ("RecordTraceEntries: exiting")); | |
| 821 return; | |
| 822 } /* end PR_RecordTraceEntries() */ | |
| 823 | |
| 824 /* | |
| 825 ** | |
| 826 */ | |
| 827 PR_IMPLEMENT(PRIntn) | |
| 828 PR_GetTraceEntries( | |
| 829 PRTraceEntry *buffer, /* where to write output */ | |
| 830 PRInt32 count, /* number to get */ | |
| 831 PRInt32 *found /* number you got */ | |
| 832 ) | |
| 833 { | |
| 834 PRInt32 rc; | |
| 835 PRInt32 copied = 0; | |
| 836 | |
| 837 PR_Lock( traceLock ); | |
| 838 | |
| 839 /* | |
| 840 ** Depending on where the LastSeen and Next indices are, | |
| 841 ** copy the trace buffer in one or two pieces. | |
| 842 */ | |
| 843 PR_LOG( lm, PR_LOG_ERROR, | |
| 844 ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen)); | |
| 845 | |
| 846 if ( fetchLastSeen <= next ) | |
| 847 { | |
| 848 while (( count-- > 0 ) && (fetchLastSeen < next )) | |
| 849 { | |
| 850 *(buffer + copied++) = *(tBuf + fetchLastSeen++); | |
| 851 } | |
| 852 PR_LOG( lm, PR_LOG_ERROR, | |
| 853 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLast
Seen)); | |
| 854 } | |
| 855 else /* copy in 2 parts */ | |
| 856 { | |
| 857 while ( count-- > 0 && fetchLastSeen <= last ) | |
| 858 { | |
| 859 *(buffer + copied++) = *(tBuf + fetchLastSeen++); | |
| 860 } | |
| 861 fetchLastSeen = 0; | |
| 862 | |
| 863 PR_LOG( lm, PR_LOG_ERROR, | |
| 864 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLast
Seen)); | |
| 865 | |
| 866 while ( count-- > 0 && fetchLastSeen < next ) | |
| 867 { | |
| 868 *(buffer + copied++) = *(tBuf + fetchLastSeen++); | |
| 869 } | |
| 870 PR_LOG( lm, PR_LOG_ERROR, | |
| 871 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLast
Seen)); | |
| 872 } | |
| 873 | |
| 874 *found = copied; | |
| 875 rc = ( fetchLostData == PR_TRUE )? 1 : 0; | |
| 876 fetchLostData = PR_FALSE; | |
| 877 | |
| 878 PR_Unlock( traceLock ); | |
| 879 return rc; | |
| 880 } /* end PR_GetTraceEntries() */ | |
| 881 | |
| 882 /* end prtrace.c */ | |
| OLD | NEW |