1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/misc/prtrace.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,888 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** prtrace.c -- NSPR Trace Instrumentation 1.11 +** 1.12 +** Implement the API defined in prtrace.h 1.13 +** 1.14 +** 1.15 +** 1.16 +*/ 1.17 + 1.18 +#include <string.h> 1.19 +#include "primpl.h" 1.20 + 1.21 + 1.22 +#define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 ) 1.23 +#define DEFAULT_BUFFER_SEGMENTS 2 1.24 + 1.25 +/* 1.26 +** Enumerate states in a RName structure 1.27 +*/ 1.28 +typedef enum TraceState 1.29 +{ 1.30 + Running = 1, 1.31 + Suspended = 2 1.32 +} TraceState; 1.33 + 1.34 +/* 1.35 +** Define QName structure 1.36 +*/ 1.37 +typedef struct QName 1.38 +{ 1.39 + PRCList link; 1.40 + PRCList rNameList; 1.41 + char name[PRTRACE_NAME_MAX+1]; 1.42 +} QName; 1.43 + 1.44 +/* 1.45 +** Define RName structure 1.46 +*/ 1.47 +typedef struct RName 1.48 +{ 1.49 + PRCList link; 1.50 + PRLock *lock; 1.51 + QName *qName; 1.52 + TraceState state; 1.53 + char name[PRTRACE_NAME_MAX+1]; 1.54 + char desc[PRTRACE_DESC_MAX+1]; 1.55 +} RName; 1.56 + 1.57 + 1.58 +/* 1.59 +** The Trace Facility database 1.60 +** 1.61 +*/ 1.62 +static PRLogModuleInfo *lm; 1.63 + 1.64 +static PRLock *traceLock; /* Facility Lock */ 1.65 +static PRCList qNameList; /* anchor to all QName structures */ 1.66 +static TraceState traceState = Running; 1.67 + 1.68 +/* 1.69 +** in-memory trace buffer controls 1.70 +*/ 1.71 +static PRTraceEntry *tBuf; /* pointer to buffer */ 1.72 +static PRInt32 bufSize; /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */ 1.73 +static volatile PRInt32 next; /* index to next PRTraceEntry */ 1.74 +static PRInt32 last; /* index of highest numbered trace entry */ 1.75 + 1.76 +/* 1.77 +** Real-time buffer capture controls 1.78 +*/ 1.79 +static PRInt32 fetchLastSeen = 0; 1.80 +static PRBool fetchLostData = PR_FALSE; 1.81 + 1.82 +/* 1.83 +** Buffer write-to-file controls 1.84 +*/ 1.85 +static PRLock *logLock; /* Sync lock */ 1.86 +static PRCondVar *logCVar; /* Sync Condidtion Variable */ 1.87 +/* 1.88 +** Inter-thread state communication. 1.89 +** Controling thread writes to logOrder under protection of logCVar 1.90 +** the logging thread reads logOrder and sets logState on Notify. 1.91 +** 1.92 +** logSegments, logCount, logLostData must be read and written under 1.93 +** protection of logLock, logCVar. 1.94 +** 1.95 +*/ 1.96 +static enum LogState 1.97 +{ 1.98 + LogNotRunning, /* Initial state */ 1.99 + LogReset, /* Causes logger to re-calc controls */ 1.100 + LogActive, /* Logging in progress, set only by log thread */ 1.101 + LogSuspend, /* Suspend Logging */ 1.102 + LogResume, /* Resume Logging => LogActive */ 1.103 + LogStop /* Stop the log thread */ 1.104 +} logOrder, logState, localState; /* controlling state variables */ 1.105 +static PRInt32 logSegments; /* Number of buffer segments */ 1.106 +static PRInt32 logEntries; /* number of Trace Entries in the buffer */ 1.107 +static PRInt32 logEntriesPerSegment; /* number of PRTraceEntries per buffer segment */ 1.108 +static PRInt32 logSegSize; /* size of buffer segment */ 1.109 +static PRInt32 logCount; /* number of segments pending output */ 1.110 +static PRInt32 logLostData; /* number of lost log buffer segments */ 1.111 + 1.112 +/* 1.113 +** end Trace Database 1.114 +** 1.115 +*/ 1.116 + 1.117 +/* 1.118 +** _PR_InitializeTrace() -- Initialize the trace facility 1.119 +*/ 1.120 +static void NewTraceBuffer( PRInt32 size ) 1.121 +{ 1.122 + /* 1.123 + ** calculate the size of the buffer 1.124 + ** round down so that each segment has the same number of 1.125 + ** trace entries 1.126 + */ 1.127 + logSegments = DEFAULT_BUFFER_SEGMENTS; 1.128 + logEntries = size / sizeof(PRTraceEntry); 1.129 + logEntriesPerSegment = logEntries / logSegments; 1.130 + logEntries = logSegments * logEntriesPerSegment; 1.131 + bufSize = logEntries * sizeof(PRTraceEntry); 1.132 + logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry); 1.133 + PR_ASSERT( bufSize != 0); 1.134 + PR_LOG( lm, PR_LOG_ERROR, 1.135 + ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld", 1.136 + logSegments, logEntries, logEntriesPerSegment, logSegSize )); 1.137 + 1.138 + 1.139 + tBuf = PR_Malloc( bufSize ); 1.140 + if ( tBuf == NULL ) 1.141 + { 1.142 + PR_LOG( lm, PR_LOG_ERROR, 1.143 + ("PRTrace: Failed to get trace buffer")); 1.144 + PR_ASSERT( 0 ); 1.145 + } 1.146 + else 1.147 + { 1.148 + PR_LOG( lm, PR_LOG_NOTICE, 1.149 + ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf)); 1.150 + } 1.151 + 1.152 + next = 0; 1.153 + last = logEntries -1; 1.154 + logCount = 0; 1.155 + logLostData = PR_TRUE; /* not really on first call */ 1.156 + logOrder = LogReset; 1.157 + 1.158 +} /* end NewTraceBuffer() */ 1.159 + 1.160 +/* 1.161 +** _PR_InitializeTrace() -- Initialize the trace facility 1.162 +*/ 1.163 +static void _PR_InitializeTrace( void ) 1.164 +{ 1.165 + /* The lock pointer better be null on this call */ 1.166 + PR_ASSERT( traceLock == NULL ); 1.167 + 1.168 + traceLock = PR_NewLock(); 1.169 + PR_ASSERT( traceLock != NULL ); 1.170 + 1.171 + PR_Lock( traceLock ); 1.172 + 1.173 + PR_INIT_CLIST( &qNameList ); 1.174 + 1.175 + lm = PR_NewLogModule("trace"); 1.176 + 1.177 + bufSize = DEFAULT_TRACE_BUFSIZE; 1.178 + NewTraceBuffer( bufSize ); 1.179 + 1.180 + /* Initialize logging controls */ 1.181 + logLock = PR_NewLock(); 1.182 + logCVar = PR_NewCondVar( logLock ); 1.183 + 1.184 + PR_Unlock( traceLock ); 1.185 + return; 1.186 +} /* end _PR_InitializeTrace() */ 1.187 + 1.188 +/* 1.189 +** Create a Trace Handle 1.190 +*/ 1.191 +PR_IMPLEMENT(PRTraceHandle) 1.192 + PR_CreateTrace( 1.193 + const char *qName, /* QName for this trace handle */ 1.194 + const char *rName, /* RName for this trace handle */ 1.195 + const char *description /* description for this trace handle */ 1.196 +) 1.197 +{ 1.198 + QName *qnp; 1.199 + RName *rnp; 1.200 + PRBool matchQname = PR_FALSE; 1.201 + 1.202 + /* Self initialize, if necessary */ 1.203 + if ( traceLock == NULL ) 1.204 + _PR_InitializeTrace(); 1.205 + 1.206 + /* Validate input arguments */ 1.207 + PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX ); 1.208 + PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX ); 1.209 + PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX ); 1.210 + 1.211 + PR_LOG( lm, PR_LOG_DEBUG, 1.212 + ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName)); 1.213 + 1.214 + /* Lock the Facility */ 1.215 + PR_Lock( traceLock ); 1.216 + 1.217 + /* Do we already have a matching QName? */ 1.218 + if (!PR_CLIST_IS_EMPTY( &qNameList )) 1.219 + { 1.220 + qnp = (QName *) PR_LIST_HEAD( &qNameList ); 1.221 + do { 1.222 + if ( strcmp(qnp->name, qName) == 0) 1.223 + { 1.224 + matchQname = PR_TRUE; 1.225 + break; 1.226 + } 1.227 + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); 1.228 + } while( qnp != (QName *)&qNameList ); 1.229 + } 1.230 + /* 1.231 + ** If we did not find a matching QName, 1.232 + ** allocate one and initialize it. 1.233 + ** link it onto the qNameList. 1.234 + ** 1.235 + */ 1.236 + if ( matchQname != PR_TRUE ) 1.237 + { 1.238 + qnp = PR_NEWZAP( QName ); 1.239 + PR_ASSERT( qnp != NULL ); 1.240 + PR_INIT_CLIST( &qnp->link ); 1.241 + PR_INIT_CLIST( &qnp->rNameList ); 1.242 + strcpy( qnp->name, qName ); 1.243 + PR_APPEND_LINK( &qnp->link, &qNameList ); 1.244 + } 1.245 + 1.246 + /* Do we already have a matching RName? */ 1.247 + if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) 1.248 + { 1.249 + rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); 1.250 + do { 1.251 + /* 1.252 + ** No duplicate RNames are allowed within a QName 1.253 + ** 1.254 + */ 1.255 + PR_ASSERT( strcmp(rnp->name, rName)); 1.256 + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); 1.257 + } while( rnp != (RName *)&qnp->rNameList ); 1.258 + } 1.259 + 1.260 + /* Get a new RName structure; initialize its members */ 1.261 + rnp = PR_NEWZAP( RName ); 1.262 + PR_ASSERT( rnp != NULL ); 1.263 + PR_INIT_CLIST( &rnp->link ); 1.264 + strcpy( rnp->name, rName ); 1.265 + strcpy( rnp->desc, description ); 1.266 + rnp->lock = PR_NewLock(); 1.267 + rnp->state = Running; 1.268 + if ( rnp->lock == NULL ) 1.269 + { 1.270 + PR_ASSERT(0); 1.271 + } 1.272 + 1.273 + PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ 1.274 + rnp->qName = qnp; /* point the RName to the QName */ 1.275 + 1.276 + /* Unlock the Facility */ 1.277 + PR_Unlock( traceLock ); 1.278 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t", 1.279 + qName, qnp, rName, rnp )); 1.280 + 1.281 + return((PRTraceHandle)rnp); 1.282 +} /* end PR_CreateTrace() */ 1.283 + 1.284 +/* 1.285 +** 1.286 +*/ 1.287 +PR_IMPLEMENT(void) 1.288 + PR_DestroyTrace( 1.289 + PRTraceHandle handle /* Handle to be destroyed */ 1.290 +) 1.291 +{ 1.292 + RName *rnp = (RName *)handle; 1.293 + QName *qnp = rnp->qName; 1.294 + 1.295 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", 1.296 + qnp->name, rnp->name)); 1.297 + 1.298 + /* Lock the Facility */ 1.299 + PR_Lock( traceLock ); 1.300 + 1.301 + /* 1.302 + ** Remove RName from the list of RNames in QName 1.303 + ** and free RName 1.304 + */ 1.305 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", 1.306 + rnp->name, rnp)); 1.307 + PR_REMOVE_LINK( &rnp->link ); 1.308 + PR_Free( rnp->lock ); 1.309 + PR_DELETE( rnp ); 1.310 + 1.311 + /* 1.312 + ** If this is the last RName within QName 1.313 + ** remove QName from the qNameList and free it 1.314 + */ 1.315 + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) 1.316 + { 1.317 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", 1.318 + qnp->name, qnp)); 1.319 + PR_REMOVE_LINK( &qnp->link ); 1.320 + PR_DELETE( qnp ); 1.321 + } 1.322 + 1.323 + /* Unlock the Facility */ 1.324 + PR_Unlock( traceLock ); 1.325 + return; 1.326 +} /* end PR_DestroyTrace() */ 1.327 + 1.328 +/* 1.329 +** Create a TraceEntry in the trace buffer 1.330 +*/ 1.331 +PR_IMPLEMENT(void) 1.332 + PR_Trace( 1.333 + PRTraceHandle handle, /* use this trace handle */ 1.334 + PRUint32 userData0, /* User supplied data word 0 */ 1.335 + PRUint32 userData1, /* User supplied data word 1 */ 1.336 + PRUint32 userData2, /* User supplied data word 2 */ 1.337 + PRUint32 userData3, /* User supplied data word 3 */ 1.338 + PRUint32 userData4, /* User supplied data word 4 */ 1.339 + PRUint32 userData5, /* User supplied data word 5 */ 1.340 + PRUint32 userData6, /* User supplied data word 6 */ 1.341 + PRUint32 userData7 /* User supplied data word 7 */ 1.342 +) 1.343 +{ 1.344 + PRTraceEntry *tep; 1.345 + PRInt32 mark; 1.346 + 1.347 + if ( (traceState == Suspended ) 1.348 + || ( ((RName *)handle)->state == Suspended )) 1.349 + return; 1.350 + 1.351 + /* 1.352 + ** Get the next trace entry slot w/ minimum delay 1.353 + */ 1.354 + PR_Lock( traceLock ); 1.355 + 1.356 + tep = &tBuf[next++]; 1.357 + if ( next > last ) 1.358 + next = 0; 1.359 + if ( fetchLostData == PR_FALSE && next == fetchLastSeen ) 1.360 + fetchLostData = PR_TRUE; 1.361 + 1.362 + mark = next; 1.363 + 1.364 + PR_Unlock( traceLock ); 1.365 + 1.366 + /* 1.367 + ** We have a trace entry. Fill it in. 1.368 + */ 1.369 + tep->thread = PR_GetCurrentThread(); 1.370 + tep->handle = handle; 1.371 + tep->time = PR_Now(); 1.372 + tep->userData[0] = userData0; 1.373 + tep->userData[1] = userData1; 1.374 + tep->userData[2] = userData2; 1.375 + tep->userData[3] = userData3; 1.376 + tep->userData[4] = userData4; 1.377 + tep->userData[5] = userData5; 1.378 + tep->userData[6] = userData6; 1.379 + tep->userData[7] = userData7; 1.380 + 1.381 + /* When buffer segment is full, signal trace log thread to run */ 1.382 + if (( mark % logEntriesPerSegment) == 0 ) 1.383 + { 1.384 + PR_Lock( logLock ); 1.385 + logCount++; 1.386 + PR_NotifyCondVar( logCVar ); 1.387 + PR_Unlock( logLock ); 1.388 + /* 1.389 + ** Gh0D! This is awful! 1.390 + ** Anyway, to minimize lost trace data segments, 1.391 + ** I inserted the PR_Sleep(0) to cause a context switch 1.392 + ** so that the log thread could run. 1.393 + ** I know, it perturbs the universe and may cause 1.394 + ** funny things to happen in the optimized builds. 1.395 + ** Take it out, lose data; leave it in risk Heisenberg. 1.396 + */ 1.397 + /* PR_Sleep(0); */ 1.398 + } 1.399 + 1.400 + return; 1.401 +} /* end PR_Trace() */ 1.402 + 1.403 +/* 1.404 +** 1.405 +*/ 1.406 +PR_IMPLEMENT(void) 1.407 + PR_SetTraceOption( 1.408 + PRTraceOption command, /* One of the enumerated values */ 1.409 + void *value /* command value or NULL */ 1.410 +) 1.411 +{ 1.412 + RName * rnp; 1.413 + 1.414 + switch ( command ) 1.415 + { 1.416 + case PRTraceBufSize : 1.417 + PR_Lock( traceLock ); 1.418 + PR_Free( tBuf ); 1.419 + bufSize = *(PRInt32 *)value; 1.420 + NewTraceBuffer( bufSize ); 1.421 + PR_Unlock( traceLock ); 1.422 + PR_LOG( lm, PR_LOG_DEBUG, 1.423 + ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize)); 1.424 + break; 1.425 + 1.426 + case PRTraceEnable : 1.427 + rnp = *(RName **)value; 1.428 + rnp->state = Running; 1.429 + PR_LOG( lm, PR_LOG_DEBUG, 1.430 + ("PRSetTraceOption: PRTraceEnable: %p", rnp)); 1.431 + break; 1.432 + 1.433 + case PRTraceDisable : 1.434 + rnp = *(RName **)value; 1.435 + rnp->state = Suspended; 1.436 + PR_LOG( lm, PR_LOG_DEBUG, 1.437 + ("PRSetTraceOption: PRTraceDisable: %p", rnp)); 1.438 + break; 1.439 + 1.440 + case PRTraceSuspend : 1.441 + traceState = Suspended; 1.442 + PR_LOG( lm, PR_LOG_DEBUG, 1.443 + ("PRSetTraceOption: PRTraceSuspend")); 1.444 + break; 1.445 + 1.446 + case PRTraceResume : 1.447 + traceState = Running; 1.448 + PR_LOG( lm, PR_LOG_DEBUG, 1.449 + ("PRSetTraceOption: PRTraceResume")); 1.450 + break; 1.451 + 1.452 + case PRTraceSuspendRecording : 1.453 + PR_Lock( logLock ); 1.454 + logOrder = LogSuspend; 1.455 + PR_NotifyCondVar( logCVar ); 1.456 + PR_Unlock( logLock ); 1.457 + PR_LOG( lm, PR_LOG_DEBUG, 1.458 + ("PRSetTraceOption: PRTraceSuspendRecording")); 1.459 + break; 1.460 + 1.461 + case PRTraceResumeRecording : 1.462 + PR_LOG( lm, PR_LOG_DEBUG, 1.463 + ("PRSetTraceOption: PRTraceResumeRecording")); 1.464 + if ( logState != LogSuspend ) 1.465 + break; 1.466 + PR_Lock( logLock ); 1.467 + logOrder = LogResume; 1.468 + PR_NotifyCondVar( logCVar ); 1.469 + PR_Unlock( logLock ); 1.470 + break; 1.471 + 1.472 + case PRTraceStopRecording : 1.473 + PR_Lock( logLock ); 1.474 + logOrder = LogStop; 1.475 + PR_NotifyCondVar( logCVar ); 1.476 + PR_Unlock( logLock ); 1.477 + PR_LOG( lm, PR_LOG_DEBUG, 1.478 + ("PRSetTraceOption: PRTraceStopRecording")); 1.479 + break; 1.480 + 1.481 + case PRTraceLockHandles : 1.482 + PR_LOG( lm, PR_LOG_DEBUG, 1.483 + ("PRSetTraceOption: PRTraceLockTraceHandles")); 1.484 + PR_Lock( traceLock ); 1.485 + break; 1.486 + 1.487 + case PRTraceUnLockHandles : 1.488 + PR_LOG( lm, PR_LOG_DEBUG, 1.489 + ("PRSetTraceOption: PRTraceUnLockHandles")); 1.490 + PR_Unlock( traceLock ); 1.491 + break; 1.492 + 1.493 + default: 1.494 + PR_LOG( lm, PR_LOG_ERROR, 1.495 + ("PRSetTraceOption: Invalid command %ld", command )); 1.496 + PR_ASSERT( 0 ); 1.497 + break; 1.498 + } /* end switch() */ 1.499 + return; 1.500 +} /* end PR_SetTraceOption() */ 1.501 + 1.502 +/* 1.503 +** 1.504 +*/ 1.505 +PR_IMPLEMENT(void) 1.506 + PR_GetTraceOption( 1.507 + PRTraceOption command, /* One of the enumerated values */ 1.508 + void *value /* command value or NULL */ 1.509 +) 1.510 +{ 1.511 + switch ( command ) 1.512 + { 1.513 + case PRTraceBufSize : 1.514 + *((PRInt32 *)value) = bufSize; 1.515 + PR_LOG( lm, PR_LOG_DEBUG, 1.516 + ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize )); 1.517 + break; 1.518 + 1.519 + default: 1.520 + PR_LOG( lm, PR_LOG_ERROR, 1.521 + ("PRGetTraceOption: Invalid command %ld", command )); 1.522 + PR_ASSERT( 0 ); 1.523 + break; 1.524 + } /* end switch() */ 1.525 + return; 1.526 +} /* end PR_GetTraceOption() */ 1.527 + 1.528 +/* 1.529 +** 1.530 +*/ 1.531 +PR_IMPLEMENT(PRTraceHandle) 1.532 + PR_GetTraceHandleFromName( 1.533 + const char *qName, /* QName search argument */ 1.534 + const char *rName /* RName search argument */ 1.535 +) 1.536 +{ 1.537 + const char *qn, *rn, *desc; 1.538 + PRTraceHandle qh, rh = NULL; 1.539 + RName *rnp = NULL; 1.540 + 1.541 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t" 1.542 + "QName: %s, RName: %s", qName, rName )); 1.543 + 1.544 + qh = PR_FindNextTraceQname( NULL ); 1.545 + while (qh != NULL) 1.546 + { 1.547 + rh = PR_FindNextTraceRname( NULL, qh ); 1.548 + while ( rh != NULL ) 1.549 + { 1.550 + PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc ); 1.551 + if ( (strcmp( qName, qn ) == 0) 1.552 + && (strcmp( rName, rn ) == 0 )) 1.553 + { 1.554 + rnp = (RName *)rh; 1.555 + goto foundIt; 1.556 + } 1.557 + rh = PR_FindNextTraceRname( rh, qh ); 1.558 + } 1.559 + qh = PR_FindNextTraceQname( NULL ); 1.560 + } 1.561 + 1.562 +foundIt: 1.563 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); 1.564 + return(rh); 1.565 +} /* end PR_GetTraceHandleFromName() */ 1.566 + 1.567 +/* 1.568 +** 1.569 +*/ 1.570 +PR_IMPLEMENT(void) 1.571 + PR_GetTraceNameFromHandle( 1.572 + PRTraceHandle handle, /* handle as search argument */ 1.573 + const char **qName, /* pointer to associated QName */ 1.574 + const char **rName, /* pointer to associated RName */ 1.575 + const char **description /* pointer to associated description */ 1.576 +) 1.577 +{ 1.578 + RName *rnp = (RName *)handle; 1.579 + QName *qnp = rnp->qName; 1.580 + 1.581 + *qName = qnp->name; 1.582 + *rName = rnp->name; 1.583 + *description = rnp->desc; 1.584 + 1.585 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: " 1.586 + "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 1.587 + qnp, rnp, qnp->name, rnp->name, rnp->desc )); 1.588 + 1.589 + return; 1.590 +} /* end PR_GetTraceNameFromHandle() */ 1.591 + 1.592 +/* 1.593 +** 1.594 +*/ 1.595 +PR_IMPLEMENT(PRTraceHandle) 1.596 + PR_FindNextTraceQname( 1.597 + PRTraceHandle handle 1.598 +) 1.599 +{ 1.600 + QName *qnp = (QName *)handle; 1.601 + 1.602 + if ( PR_CLIST_IS_EMPTY( &qNameList )) 1.603 + qnp = NULL; 1.604 + else if ( qnp == NULL ) 1.605 + qnp = (QName *)PR_LIST_HEAD( &qNameList ); 1.606 + else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) 1.607 + qnp = NULL; 1.608 + else 1.609 + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); 1.610 + 1.611 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", 1.612 + handle, qnp )); 1.613 + 1.614 + return((PRTraceHandle)qnp); 1.615 +} /* end PR_FindNextTraceQname() */ 1.616 + 1.617 +/* 1.618 +** 1.619 +*/ 1.620 +PR_IMPLEMENT(PRTraceHandle) 1.621 + PR_FindNextTraceRname( 1.622 + PRTraceHandle rhandle, 1.623 + PRTraceHandle qhandle 1.624 +) 1.625 +{ 1.626 + RName *rnp = (RName *)rhandle; 1.627 + QName *qnp = (QName *)qhandle; 1.628 + 1.629 + 1.630 + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) 1.631 + rnp = NULL; 1.632 + else if ( rnp == NULL ) 1.633 + rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); 1.634 + else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) 1.635 + rnp = NULL; 1.636 + else 1.637 + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); 1.638 + 1.639 + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 1.640 + rhandle, qhandle, rnp )); 1.641 + 1.642 + return((PRTraceHandle)rnp); 1.643 +} /* end PR_FindNextTraceRname() */ 1.644 + 1.645 +/* 1.646 +** 1.647 +*/ 1.648 +static PRFileDesc * InitializeRecording( void ) 1.649 +{ 1.650 + char *logFileName; 1.651 + PRFileDesc *logFile; 1.652 + 1.653 + /* Self initialize, if necessary */ 1.654 + if ( traceLock == NULL ) 1.655 + _PR_InitializeTrace(); 1.656 + 1.657 + PR_LOG( lm, PR_LOG_DEBUG, 1.658 + ("PR_RecordTraceEntries: begins")); 1.659 + 1.660 + logLostData = 0; /* reset at entry */ 1.661 + logState = LogReset; 1.662 + 1.663 +#ifdef XP_UNIX 1.664 + if ((getuid() != geteuid()) || (getgid() != getegid())) { 1.665 + return NULL; 1.666 + } 1.667 +#endif /* XP_UNIX */ 1.668 + 1.669 + /* Get the filename for the logfile from the environment */ 1.670 + logFileName = PR_GetEnv( "NSPR_TRACE_LOG" ); 1.671 + if ( logFileName == NULL ) 1.672 + { 1.673 + PR_LOG( lm, PR_LOG_ERROR, 1.674 + ("RecordTraceEntries: Environment variable not defined. Exiting")); 1.675 + return NULL; 1.676 + } 1.677 + 1.678 + /* Open the logfile */ 1.679 + logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 ); 1.680 + if ( logFile == NULL ) 1.681 + { 1.682 + PR_LOG( lm, PR_LOG_ERROR, 1.683 + ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", 1.684 + logFileName, PR_GetOSError())); 1.685 + return NULL; 1.686 + } 1.687 + return logFile; 1.688 +} /* end InitializeRecording() */ 1.689 + 1.690 +/* 1.691 +** 1.692 +*/ 1.693 +static void ProcessOrders( void ) 1.694 +{ 1.695 + switch ( logOrder ) 1.696 + { 1.697 + case LogReset : 1.698 + logOrder = logState = localState; 1.699 + PR_LOG( lm, PR_LOG_DEBUG, 1.700 + ("RecordTraceEntries: LogReset")); 1.701 + break; 1.702 + 1.703 + case LogSuspend : 1.704 + localState = logOrder = logState = LogSuspend; 1.705 + PR_LOG( lm, PR_LOG_DEBUG, 1.706 + ("RecordTraceEntries: LogSuspend")); 1.707 + break; 1.708 + 1.709 + case LogResume : 1.710 + localState = logOrder = logState = LogActive; 1.711 + PR_LOG( lm, PR_LOG_DEBUG, 1.712 + ("RecordTraceEntries: LogResume")); 1.713 + break; 1.714 + 1.715 + case LogStop : 1.716 + logOrder = logState = LogStop; 1.717 + PR_LOG( lm, PR_LOG_DEBUG, 1.718 + ("RecordTraceEntries: LogStop")); 1.719 + break; 1.720 + 1.721 + default : 1.722 + PR_LOG( lm, PR_LOG_ERROR, 1.723 + ("RecordTraceEntries: Invalid logOrder: %ld", logOrder )); 1.724 + PR_ASSERT( 0 ); 1.725 + break; 1.726 + } /* end switch() */ 1.727 + return ; 1.728 +} /* end ProcessOrders() */ 1.729 + 1.730 +/* 1.731 +** 1.732 +*/ 1.733 +static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount ) 1.734 +{ 1.735 + PRInt32 rc; 1.736 + 1.737 + 1.738 + PR_LOG( lm, PR_LOG_ERROR, 1.739 + ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount)); 1.740 + rc = PR_Write( logFile, buf , amount ); 1.741 + if ( rc == -1 ) 1.742 + PR_LOG( lm, PR_LOG_ERROR, 1.743 + ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() )); 1.744 + else if ( rc != amount ) 1.745 + PR_LOG( lm, PR_LOG_ERROR, 1.746 + ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc)); 1.747 + else 1.748 + PR_LOG( lm, PR_LOG_DEBUG, 1.749 + ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount)); 1.750 + 1.751 + return; 1.752 +} /* end WriteTraceSegment() */ 1.753 + 1.754 +/* 1.755 +** 1.756 +*/ 1.757 +PR_IMPLEMENT(void) 1.758 + PR_RecordTraceEntries( 1.759 + void 1.760 +) 1.761 +{ 1.762 + PRFileDesc *logFile; 1.763 + PRInt32 lostSegments; 1.764 + PRInt32 currentSegment = 0; 1.765 + void *buf; 1.766 + PRBool doWrite; 1.767 + 1.768 + logFile = InitializeRecording(); 1.769 + if ( logFile == NULL ) 1.770 + { 1.771 + PR_LOG( lm, PR_LOG_DEBUG, 1.772 + ("PR_RecordTraceEntries: Failed to initialize")); 1.773 + return; 1.774 + } 1.775 + 1.776 + /* Do this until told to stop */ 1.777 + while ( logState != LogStop ) 1.778 + { 1.779 + 1.780 + PR_Lock( logLock ); 1.781 + 1.782 + while ( (logCount == 0) && ( logOrder == logState ) ) 1.783 + PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT ); 1.784 + 1.785 + /* Handle state transitions */ 1.786 + if ( logOrder != logState ) 1.787 + ProcessOrders(); 1.788 + 1.789 + /* recalculate local controls */ 1.790 + if ( logCount ) 1.791 + { 1.792 + lostSegments = logCount - logSegments; 1.793 + if ( lostSegments > 0 ) 1.794 + { 1.795 + logLostData += ( logCount - logSegments ); 1.796 + logCount = (logCount % logSegments); 1.797 + currentSegment = logCount; 1.798 + PR_LOG( lm, PR_LOG_DEBUG, 1.799 + ("PR_RecordTraceEntries: LostData segments: %ld", logLostData)); 1.800 + } 1.801 + else 1.802 + { 1.803 + logCount--; 1.804 + } 1.805 + 1.806 + buf = tBuf + ( logEntriesPerSegment * currentSegment ); 1.807 + if (++currentSegment >= logSegments ) 1.808 + currentSegment = 0; 1.809 + doWrite = PR_TRUE; 1.810 + } 1.811 + else 1.812 + doWrite = PR_FALSE; 1.813 + 1.814 + PR_Unlock( logLock ); 1.815 + 1.816 + if ( doWrite == PR_TRUE ) 1.817 + { 1.818 + if ( localState != LogSuspend ) 1.819 + WriteTraceSegment( logFile, buf, logSegSize ); 1.820 + else 1.821 + PR_LOG( lm, PR_LOG_DEBUG, 1.822 + ("RecordTraceEntries: PR_Write(): is suspended" )); 1.823 + } 1.824 + 1.825 + } /* end while(logState...) */ 1.826 + 1.827 + PR_Close( logFile ); 1.828 + PR_LOG( lm, PR_LOG_DEBUG, 1.829 + ("RecordTraceEntries: exiting")); 1.830 + return; 1.831 +} /* end PR_RecordTraceEntries() */ 1.832 + 1.833 +/* 1.834 +** 1.835 +*/ 1.836 +PR_IMPLEMENT(PRIntn) 1.837 + PR_GetTraceEntries( 1.838 + PRTraceEntry *buffer, /* where to write output */ 1.839 + PRInt32 count, /* number to get */ 1.840 + PRInt32 *found /* number you got */ 1.841 +) 1.842 +{ 1.843 + PRInt32 rc; 1.844 + PRInt32 copied = 0; 1.845 + 1.846 + PR_Lock( traceLock ); 1.847 + 1.848 + /* 1.849 + ** Depending on where the LastSeen and Next indices are, 1.850 + ** copy the trace buffer in one or two pieces. 1.851 + */ 1.852 + PR_LOG( lm, PR_LOG_ERROR, 1.853 + ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen)); 1.854 + 1.855 + if ( fetchLastSeen <= next ) 1.856 + { 1.857 + while (( count-- > 0 ) && (fetchLastSeen < next )) 1.858 + { 1.859 + *(buffer + copied++) = *(tBuf + fetchLastSeen++); 1.860 + } 1.861 + PR_LOG( lm, PR_LOG_ERROR, 1.862 + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); 1.863 + } 1.864 + else /* copy in 2 parts */ 1.865 + { 1.866 + while ( count-- > 0 && fetchLastSeen <= last ) 1.867 + { 1.868 + *(buffer + copied++) = *(tBuf + fetchLastSeen++); 1.869 + } 1.870 + fetchLastSeen = 0; 1.871 + 1.872 + PR_LOG( lm, PR_LOG_ERROR, 1.873 + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); 1.874 + 1.875 + while ( count-- > 0 && fetchLastSeen < next ) 1.876 + { 1.877 + *(buffer + copied++) = *(tBuf + fetchLastSeen++); 1.878 + } 1.879 + PR_LOG( lm, PR_LOG_ERROR, 1.880 + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); 1.881 + } 1.882 + 1.883 + *found = copied; 1.884 + rc = ( fetchLostData == PR_TRUE )? 1 : 0; 1.885 + fetchLostData = PR_FALSE; 1.886 + 1.887 + PR_Unlock( traceLock ); 1.888 + return rc; 1.889 +} /* end PR_GetTraceEntries() */ 1.890 + 1.891 +/* end prtrace.c */