1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 ** prtrace.c -- NSPR Trace Instrumentation
9 ** Implement the API defined in prtrace.h
19 #define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 )
20 #define DEFAULT_BUFFER_SEGMENTS 2
23 ** Enumerate states in a RName structure
25 typedef enum TraceState
32 ** Define QName structure
38 char name
[PRTRACE_NAME_MAX
+1];
42 ** Define RName structure
50 char name
[PRTRACE_NAME_MAX
+1];
51 char desc
[PRTRACE_DESC_MAX
+1];
56 ** The Trace Facility database
59 static PRLogModuleInfo
*lm
;
61 static PRLock
*traceLock
; /* Facility Lock */
62 static PRCList qNameList
; /* anchor to all QName structures */
63 static TraceState traceState
= Running
;
66 ** in-memory trace buffer controls
68 static PRTraceEntry
*tBuf
; /* pointer to buffer */
69 static PRInt32 bufSize
; /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */
70 static volatile PRInt32 next
; /* index to next PRTraceEntry */
71 static PRInt32 last
; /* index of highest numbered trace entry */
74 ** Real-time buffer capture controls
76 static PRInt32 fetchLastSeen
= 0;
77 static PRBool fetchLostData
= PR_FALSE
;
80 ** Buffer write-to-file controls
82 static PRLock
*logLock
; /* Sync lock */
83 static PRCondVar
*logCVar
; /* Sync Condidtion Variable */
85 ** Inter-thread state communication.
86 ** Controling thread writes to logOrder under protection of logCVar
87 ** the logging thread reads logOrder and sets logState on Notify.
89 ** logSegments, logCount, logLostData must be read and written under
90 ** protection of logLock, logCVar.
95 LogNotRunning
, /* Initial state */
96 LogReset
, /* Causes logger to re-calc controls */
97 LogActive
, /* Logging in progress, set only by log thread */
98 LogSuspend
, /* Suspend Logging */
99 LogResume
, /* Resume Logging => LogActive */
100 LogStop
/* Stop the log thread */
101 } logOrder
, logState
, localState
; /* controlling state variables */
102 static PRInt32 logSegments
; /* Number of buffer segments */
103 static PRInt32 logEntries
; /* number of Trace Entries in the buffer */
104 static PRInt32 logEntriesPerSegment
; /* number of PRTraceEntries per buffer segment */
105 static PRInt32 logSegSize
; /* size of buffer segment */
106 static PRInt32 logCount
; /* number of segments pending output */
107 static PRInt32 logLostData
; /* number of lost log buffer segments */
110 ** end Trace Database
115 ** _PR_InitializeTrace() -- Initialize the trace facility
117 static void NewTraceBuffer( PRInt32 size
)
120 ** calculate the size of the buffer
121 ** round down so that each segment has the same number of
124 logSegments
= DEFAULT_BUFFER_SEGMENTS
;
125 logEntries
= size
/ sizeof(PRTraceEntry
);
126 logEntriesPerSegment
= logEntries
/ logSegments
;
127 logEntries
= logSegments
* logEntriesPerSegment
;
128 bufSize
= logEntries
* sizeof(PRTraceEntry
);
129 logSegSize
= logEntriesPerSegment
* sizeof(PRTraceEntry
);
130 PR_ASSERT( bufSize
!= 0);
131 PR_LOG( lm
, PR_LOG_ERROR
,
132 ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld",
133 logSegments
, logEntries
, logEntriesPerSegment
, logSegSize
));
136 tBuf
= PR_Malloc( bufSize
);
139 PR_LOG( lm
, PR_LOG_ERROR
,
140 ("PRTrace: Failed to get trace buffer"));
145 PR_LOG( lm
, PR_LOG_NOTICE
,
146 ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize
, tBuf
));
150 last
= logEntries
-1;
152 logLostData
= PR_TRUE
; /* not really on first call */
155 } /* end NewTraceBuffer() */
158 ** _PR_InitializeTrace() -- Initialize the trace facility
160 static void _PR_InitializeTrace( void )
162 /* The lock pointer better be null on this call */
163 PR_ASSERT( traceLock
== NULL
);
165 traceLock
= PR_NewLock();
166 PR_ASSERT( traceLock
!= NULL
);
168 PR_Lock( traceLock
);
170 PR_INIT_CLIST( &qNameList
);
172 lm
= PR_NewLogModule("trace");
174 bufSize
= DEFAULT_TRACE_BUFSIZE
;
175 NewTraceBuffer( bufSize
);
177 /* Initialize logging controls */
178 logLock
= PR_NewLock();
179 logCVar
= PR_NewCondVar( logLock
);
181 PR_Unlock( traceLock
);
183 } /* end _PR_InitializeTrace() */
186 ** Create a Trace Handle
188 PR_IMPLEMENT(PRTraceHandle
)
190 const char *qName
, /* QName for this trace handle */
191 const char *rName
, /* RName for this trace handle */
192 const char *description
/* description for this trace handle */
197 PRBool matchQname
= PR_FALSE
;
199 /* Self initialize, if necessary */
200 if ( traceLock
== NULL
) {
201 _PR_InitializeTrace();
204 /* Validate input arguments */
205 PR_ASSERT( strlen(qName
) <= PRTRACE_NAME_MAX
);
206 PR_ASSERT( strlen(rName
) <= PRTRACE_NAME_MAX
);
207 PR_ASSERT( strlen(description
) <= PRTRACE_DESC_MAX
);
209 PR_LOG( lm
, PR_LOG_DEBUG
,
210 ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName
, rName
));
212 /* Lock the Facility */
213 PR_Lock( traceLock
);
215 /* Do we already have a matching QName? */
216 if (!PR_CLIST_IS_EMPTY( &qNameList
))
218 qnp
= (QName
*) PR_LIST_HEAD( &qNameList
);
220 if ( strcmp(qnp
->name
, qName
) == 0)
222 matchQname
= PR_TRUE
;
225 qnp
= (QName
*)PR_NEXT_LINK( &qnp
->link
);
226 } while( qnp
!= (QName
*)&qNameList
);
229 ** If we did not find a matching QName,
230 ** allocate one and initialize it.
231 ** link it onto the qNameList.
234 if ( matchQname
!= PR_TRUE
)
236 qnp
= PR_NEWZAP( QName
);
237 PR_ASSERT( qnp
!= NULL
);
238 PR_INIT_CLIST( &qnp
->link
);
239 PR_INIT_CLIST( &qnp
->rNameList
);
240 strcpy( qnp
->name
, qName
);
241 PR_APPEND_LINK( &qnp
->link
, &qNameList
);
244 /* Do we already have a matching RName? */
245 if (!PR_CLIST_IS_EMPTY( &qnp
->rNameList
))
247 rnp
= (RName
*) PR_LIST_HEAD( &qnp
->rNameList
);
250 ** No duplicate RNames are allowed within a QName
253 PR_ASSERT( strcmp(rnp
->name
, rName
));
254 rnp
= (RName
*)PR_NEXT_LINK( &rnp
->link
);
255 } while( rnp
!= (RName
*)&qnp
->rNameList
);
258 /* Get a new RName structure; initialize its members */
259 rnp
= PR_NEWZAP( RName
);
260 PR_ASSERT( rnp
!= NULL
);
261 PR_INIT_CLIST( &rnp
->link
);
262 strcpy( rnp
->name
, rName
);
263 strcpy( rnp
->desc
, description
);
264 rnp
->lock
= PR_NewLock();
265 rnp
->state
= Running
;
266 if ( rnp
->lock
== NULL
)
271 PR_APPEND_LINK( &rnp
->link
, &qnp
->rNameList
); /* add RName to QName's rnList */
272 rnp
->qName
= qnp
; /* point the RName to the QName */
274 /* Unlock the Facility */
275 PR_Unlock( traceLock
);
276 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t",
277 qName
, qnp
, rName
, rnp
));
279 return((PRTraceHandle
)rnp
);
280 } /* end PR_CreateTrace() */
287 PRTraceHandle handle
/* Handle to be destroyed */
290 RName
*rnp
= (RName
*)handle
;
291 QName
*qnp
= rnp
->qName
;
293 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: Deleting: QName: %s, RName: %s",
294 qnp
->name
, rnp
->name
));
296 /* Lock the Facility */
297 PR_Lock( traceLock
);
300 ** Remove RName from the list of RNames in QName
303 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: Deleting RName: %s, %p",
305 PR_REMOVE_LINK( &rnp
->link
);
306 PR_Free( rnp
->lock
);
310 ** If this is the last RName within QName
311 ** remove QName from the qNameList and free it
313 if ( PR_CLIST_IS_EMPTY( &qnp
->rNameList
) )
315 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: Deleting unused QName: %s, %p",
317 PR_REMOVE_LINK( &qnp
->link
);
321 /* Unlock the Facility */
322 PR_Unlock( traceLock
);
324 } /* end PR_DestroyTrace() */
327 ** Create a TraceEntry in the trace buffer
331 PRTraceHandle handle
, /* use this trace handle */
332 PRUint32 userData0
, /* User supplied data word 0 */
333 PRUint32 userData1
, /* User supplied data word 1 */
334 PRUint32 userData2
, /* User supplied data word 2 */
335 PRUint32 userData3
, /* User supplied data word 3 */
336 PRUint32 userData4
, /* User supplied data word 4 */
337 PRUint32 userData5
, /* User supplied data word 5 */
338 PRUint32 userData6
, /* User supplied data word 6 */
339 PRUint32 userData7
/* User supplied data word 7 */
345 if ( (traceState
== Suspended
)
346 || ( ((RName
*)handle
)->state
== Suspended
)) {
351 ** Get the next trace entry slot w/ minimum delay
353 PR_Lock( traceLock
);
359 if ( fetchLostData
== PR_FALSE
&& next
== fetchLastSeen
) {
360 fetchLostData
= PR_TRUE
;
365 PR_Unlock( traceLock
);
368 ** We have a trace entry. Fill it in.
370 tep
->thread
= PR_GetCurrentThread();
371 tep
->handle
= handle
;
372 tep
->time
= PR_Now();
373 tep
->userData
[0] = userData0
;
374 tep
->userData
[1] = userData1
;
375 tep
->userData
[2] = userData2
;
376 tep
->userData
[3] = userData3
;
377 tep
->userData
[4] = userData4
;
378 tep
->userData
[5] = userData5
;
379 tep
->userData
[6] = userData6
;
380 tep
->userData
[7] = userData7
;
382 /* When buffer segment is full, signal trace log thread to run */
383 if (( mark
% logEntriesPerSegment
) == 0 )
387 PR_NotifyCondVar( logCVar
);
388 PR_Unlock( logLock
);
390 ** Gh0D! This is awful!
391 ** Anyway, to minimize lost trace data segments,
392 ** I inserted the PR_Sleep(0) to cause a context switch
393 ** so that the log thread could run.
394 ** I know, it perturbs the universe and may cause
395 ** funny things to happen in the optimized builds.
396 ** Take it out, lose data; leave it in risk Heisenberg.
402 } /* end PR_Trace() */
409 PRTraceOption command
, /* One of the enumerated values */
410 void *value
/* command value or NULL */
417 case PRTraceBufSize
:
418 PR_Lock( traceLock
);
420 bufSize
= *(PRInt32
*)value
;
421 NewTraceBuffer( bufSize
);
422 PR_Unlock( traceLock
);
423 PR_LOG( lm
, PR_LOG_DEBUG
,
424 ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize
));
428 rnp
= *(RName
**)value
;
429 rnp
->state
= Running
;
430 PR_LOG( lm
, PR_LOG_DEBUG
,
431 ("PRSetTraceOption: PRTraceEnable: %p", rnp
));
434 case PRTraceDisable
:
435 rnp
= *(RName
**)value
;
436 rnp
->state
= Suspended
;
437 PR_LOG( lm
, PR_LOG_DEBUG
,
438 ("PRSetTraceOption: PRTraceDisable: %p", rnp
));
441 case PRTraceSuspend
:
442 traceState
= Suspended
;
443 PR_LOG( lm
, PR_LOG_DEBUG
,
444 ("PRSetTraceOption: PRTraceSuspend"));
448 traceState
= Running
;
449 PR_LOG( lm
, PR_LOG_DEBUG
,
450 ("PRSetTraceOption: PRTraceResume"));
453 case PRTraceSuspendRecording
:
455 logOrder
= LogSuspend
;
456 PR_NotifyCondVar( logCVar
);
457 PR_Unlock( logLock
);
458 PR_LOG( lm
, PR_LOG_DEBUG
,
459 ("PRSetTraceOption: PRTraceSuspendRecording"));
462 case PRTraceResumeRecording
:
463 PR_LOG( lm
, PR_LOG_DEBUG
,
464 ("PRSetTraceOption: PRTraceResumeRecording"));
465 if ( logState
!= LogSuspend
) {
469 logOrder
= LogResume
;
470 PR_NotifyCondVar( logCVar
);
471 PR_Unlock( logLock
);
474 case PRTraceStopRecording
:
477 PR_NotifyCondVar( logCVar
);
478 PR_Unlock( logLock
);
479 PR_LOG( lm
, PR_LOG_DEBUG
,
480 ("PRSetTraceOption: PRTraceStopRecording"));
483 case PRTraceLockHandles
:
484 PR_LOG( lm
, PR_LOG_DEBUG
,
485 ("PRSetTraceOption: PRTraceLockTraceHandles"));
486 PR_Lock( traceLock
);
489 case PRTraceUnLockHandles
:
490 PR_LOG( lm
, PR_LOG_DEBUG
,
491 ("PRSetTraceOption: PRTraceUnLockHandles"));
492 PR_Unlock( traceLock
);
496 PR_LOG( lm
, PR_LOG_ERROR
,
497 ("PRSetTraceOption: Invalid command %ld", command
));
502 } /* end PR_SetTraceOption() */
509 PRTraceOption command
, /* One of the enumerated values */
510 void *value
/* command value or NULL */
515 case PRTraceBufSize
:
516 *((PRInt32
*)value
) = bufSize
;
517 PR_LOG( lm
, PR_LOG_DEBUG
,
518 ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize
));
522 PR_LOG( lm
, PR_LOG_ERROR
,
523 ("PRGetTraceOption: Invalid command %ld", command
));
528 } /* end PR_GetTraceOption() */
533 PR_IMPLEMENT(PRTraceHandle
)
534 PR_GetTraceHandleFromName(
535 const char *qName
, /* QName search argument */
536 const char *rName
/* RName search argument */
539 const char *qn
, *rn
, *desc
;
540 PRTraceHandle qh
, rh
= NULL
;
543 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: GetTraceHandleFromName:\n\t"
544 "QName: %s, RName: %s", qName
, rName
));
546 qh
= PR_FindNextTraceQname( NULL
);
549 rh
= PR_FindNextTraceRname( NULL
, qh
);
552 PR_GetTraceNameFromHandle( rh
, &qn
, &rn
, &desc
);
553 if ( (strcmp( qName
, qn
) == 0)
554 && (strcmp( rName
, rn
) == 0 ))
559 rh
= PR_FindNextTraceRname( rh
, qh
);
561 qh
= PR_FindNextTraceQname( NULL
);
565 PR_LOG( lm
, PR_LOG_DEBUG
, ("PR_Counter: GetConterHandleFromName: %p", rnp
));
567 } /* end PR_GetTraceHandleFromName() */
573 PR_GetTraceNameFromHandle(
574 PRTraceHandle handle
, /* handle as search argument */
575 const char **qName
, /* pointer to associated QName */
576 const char **rName
, /* pointer to associated RName */
577 const char **description
/* pointer to associated description */
580 RName
*rnp
= (RName
*)handle
;
581 QName
*qnp
= rnp
->qName
;
585 *description
= rnp
->desc
;
587 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: GetConterNameFromHandle: "
588 "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s",
589 qnp
, rnp
, qnp
->name
, rnp
->name
, rnp
->desc
));
592 } /* end PR_GetTraceNameFromHandle() */
597 PR_IMPLEMENT(PRTraceHandle
)
598 PR_FindNextTraceQname(
602 QName
*qnp
= (QName
*)handle
;
604 if ( PR_CLIST_IS_EMPTY( &qNameList
)) {
607 else if ( qnp
== NULL
) {
608 qnp
= (QName
*)PR_LIST_HEAD( &qNameList
);
610 else if ( PR_NEXT_LINK( &qnp
->link
) == &qNameList
) {
614 qnp
= (QName
*)PR_NEXT_LINK( &qnp
->link
);
617 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: FindNextQname: Handle: %p, Returns: %p",
620 return((PRTraceHandle
)qnp
);
621 } /* end PR_FindNextTraceQname() */
626 PR_IMPLEMENT(PRTraceHandle
)
627 PR_FindNextTraceRname(
628 PRTraceHandle rhandle
,
629 PRTraceHandle qhandle
632 RName
*rnp
= (RName
*)rhandle
;
633 QName
*qnp
= (QName
*)qhandle
;
636 if ( PR_CLIST_IS_EMPTY( &qnp
->rNameList
)) {
639 else if ( rnp
== NULL
) {
640 rnp
= (RName
*)PR_LIST_HEAD( &qnp
->rNameList
);
642 else if ( PR_NEXT_LINK( &rnp
->link
) == &qnp
->rNameList
) {
646 rnp
= (RName
*)PR_NEXT_LINK( &rnp
->link
);
649 PR_LOG( lm
, PR_LOG_DEBUG
, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p",
650 rhandle
, qhandle
, rnp
));
652 return((PRTraceHandle
)rnp
);
653 } /* end PR_FindNextTraceRname() */
658 static PRFileDesc
* InitializeRecording( void )
663 /* Self initialize, if necessary */
664 if ( traceLock
== NULL
) {
665 _PR_InitializeTrace();
668 PR_LOG( lm
, PR_LOG_DEBUG
,
669 ("PR_RecordTraceEntries: begins"));
671 logLostData
= 0; /* reset at entry */
674 /* Get the filename for the logfile from the environment */
675 logFileName
= PR_GetEnvSecure( "NSPR_TRACE_LOG" );
676 if ( logFileName
== NULL
)
678 PR_LOG( lm
, PR_LOG_ERROR
,
679 ("RecordTraceEntries: Environment variable not defined. Exiting"));
683 /* Open the logfile */
684 logFile
= PR_Open( logFileName
, PR_WRONLY
| PR_CREATE_FILE
, 0666 );
685 if ( logFile
== NULL
)
687 PR_LOG( lm
, PR_LOG_ERROR
,
688 ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld",
689 logFileName
, PR_GetOSError()));
693 } /* end InitializeRecording() */
698 static void ProcessOrders( void )
703 logOrder
= logState
= localState
;
704 PR_LOG( lm
, PR_LOG_DEBUG
,
705 ("RecordTraceEntries: LogReset"));
709 localState
= logOrder
= logState
= LogSuspend
;
710 PR_LOG( lm
, PR_LOG_DEBUG
,
711 ("RecordTraceEntries: LogSuspend"));
715 localState
= logOrder
= logState
= LogActive
;
716 PR_LOG( lm
, PR_LOG_DEBUG
,
717 ("RecordTraceEntries: LogResume"));
721 logOrder
= logState
= LogStop
;
722 PR_LOG( lm
, PR_LOG_DEBUG
,
723 ("RecordTraceEntries: LogStop"));
727 PR_LOG( lm
, PR_LOG_ERROR
,
728 ("RecordTraceEntries: Invalid logOrder: %ld", logOrder
));
733 } /* end ProcessOrders() */
738 static void WriteTraceSegment( PRFileDesc
*logFile
, void *buf
, PRInt32 amount
)
743 PR_LOG( lm
, PR_LOG_ERROR
,
744 ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf
, amount
));
745 rc
= PR_Write( logFile
, buf
, amount
);
747 PR_LOG( lm
, PR_LOG_ERROR
,
748 ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() ));
749 else if ( rc
!= amount
)
750 PR_LOG( lm
, PR_LOG_ERROR
,
751 ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount
, rc
));
753 PR_LOG( lm
, PR_LOG_DEBUG
,
754 ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf
, amount
));
757 } /* end WriteTraceSegment() */
763 PR_RecordTraceEntries(
768 PRInt32 lostSegments
;
769 PRInt32 currentSegment
= 0;
773 logFile
= InitializeRecording();
774 if ( logFile
== NULL
)
776 PR_LOG( lm
, PR_LOG_DEBUG
,
777 ("PR_RecordTraceEntries: Failed to initialize"));
781 /* Do this until told to stop */
782 while ( logState
!= LogStop
)
787 while ( (logCount
== 0) && ( logOrder
== logState
) ) {
788 PR_WaitCondVar( logCVar
, PR_INTERVAL_NO_TIMEOUT
);
791 /* Handle state transitions */
792 if ( logOrder
!= logState
) {
796 /* recalculate local controls */
799 lostSegments
= logCount
- logSegments
;
800 if ( lostSegments
> 0 )
802 logLostData
+= ( logCount
- logSegments
);
803 logCount
= (logCount
% logSegments
);
804 currentSegment
= logCount
;
805 PR_LOG( lm
, PR_LOG_DEBUG
,
806 ("PR_RecordTraceEntries: LostData segments: %ld", logLostData
));
813 buf
= tBuf
+ ( logEntriesPerSegment
* currentSegment
);
814 if (++currentSegment
>= logSegments
) {
823 PR_Unlock( logLock
);
825 if ( doWrite
== PR_TRUE
)
827 if ( localState
!= LogSuspend
) {
828 WriteTraceSegment( logFile
, buf
, logSegSize
);
831 PR_LOG( lm
, PR_LOG_DEBUG
,
832 ("RecordTraceEntries: PR_Write(): is suspended" ));
835 } /* end while(logState...) */
838 PR_LOG( lm
, PR_LOG_DEBUG
,
839 ("RecordTraceEntries: exiting"));
841 } /* end PR_RecordTraceEntries() */
848 PRTraceEntry
*buffer
, /* where to write output */
849 PRInt32 count
, /* number to get */
850 PRInt32
*found
/* number you got */
856 PR_Lock( traceLock
);
859 ** Depending on where the LastSeen and Next indices are,
860 ** copy the trace buffer in one or two pieces.
862 PR_LOG( lm
, PR_LOG_ERROR
,
863 ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next
, fetchLastSeen
));
865 if ( fetchLastSeen
<= next
)
867 while (( count
-- > 0 ) && (fetchLastSeen
< next
))
869 *(buffer
+ copied
++) = *(tBuf
+ fetchLastSeen
++);
871 PR_LOG( lm
, PR_LOG_ERROR
,
872 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied
, fetchLastSeen
));
874 else /* copy in 2 parts */
876 while ( count
-- > 0 && fetchLastSeen
<= last
)
878 *(buffer
+ copied
++) = *(tBuf
+ fetchLastSeen
++);
882 PR_LOG( lm
, PR_LOG_ERROR
,
883 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied
, fetchLastSeen
));
885 while ( count
-- > 0 && fetchLastSeen
< next
)
887 *(buffer
+ copied
++) = *(tBuf
+ fetchLastSeen
++);
889 PR_LOG( lm
, PR_LOG_ERROR
,
890 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied
, fetchLastSeen
));
894 rc
= ( fetchLostData
== PR_TRUE
)? 1 : 0;
895 fetchLostData
= PR_FALSE
;
897 PR_Unlock( traceLock
);
899 } /* end PR_GetTraceEntries() */