Wed, 31 Dec 2014 06:09:35 +0100
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 */ |