nsprpub/pr/src/misc/prtrace.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial