Bug 1792034 [wpt PR 36019] - Make location.search always expect UTF-8, a=testonly
[gecko.git] / nsprpub / pr / src / misc / prtrace.c
blobef6b65104e248f3205ae22ace9c15cbb8cf98585
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/. */
6 /*
7 ** prtrace.c -- NSPR Trace Instrumentation
8 **
9 ** Implement the API defined in prtrace.h
15 #include <string.h>
16 #include "primpl.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
27 Running = 1,
28 Suspended = 2
29 } TraceState;
32 ** Define QName structure
34 typedef struct QName
36 PRCList link;
37 PRCList rNameList;
38 char name[PRTRACE_NAME_MAX+1];
39 } QName;
42 ** Define RName structure
44 typedef struct RName
46 PRCList link;
47 PRLock *lock;
48 QName *qName;
49 TraceState state;
50 char name[PRTRACE_NAME_MAX+1];
51 char desc[PRTRACE_DESC_MAX+1];
52 } RName;
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.
93 static enum LogState
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
122 ** trace entries
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 );
137 if ( tBuf == NULL )
139 PR_LOG( lm, PR_LOG_ERROR,
140 ("PRTrace: Failed to get trace buffer"));
141 PR_ASSERT( 0 );
143 else
145 PR_LOG( lm, PR_LOG_NOTICE,
146 ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf));
149 next = 0;
150 last = logEntries -1;
151 logCount = 0;
152 logLostData = PR_TRUE; /* not really on first call */
153 logOrder = LogReset;
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 );
182 return;
183 } /* end _PR_InitializeTrace() */
186 ** Create a Trace Handle
188 PR_IMPLEMENT(PRTraceHandle)
189 PR_CreateTrace(
190 const char *qName, /* QName for this trace handle */
191 const char *rName, /* RName for this trace handle */
192 const char *description /* description for this trace handle */
195 QName *qnp;
196 RName *rnp;
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 );
219 do {
220 if ( strcmp(qnp->name, qName) == 0)
222 matchQname = PR_TRUE;
223 break;
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 );
248 do {
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 )
268 PR_ASSERT(0);
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() */
285 PR_IMPLEMENT(void)
286 PR_DestroyTrace(
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
301 ** and free RName
303 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p",
304 rnp->name, rnp));
305 PR_REMOVE_LINK( &rnp->link );
306 PR_Free( rnp->lock );
307 PR_DELETE( rnp );
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",
316 qnp->name, qnp));
317 PR_REMOVE_LINK( &qnp->link );
318 PR_DELETE( qnp );
321 /* Unlock the Facility */
322 PR_Unlock( traceLock );
323 return;
324 } /* end PR_DestroyTrace() */
327 ** Create a TraceEntry in the trace buffer
329 PR_IMPLEMENT(void)
330 PR_Trace(
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 */
342 PRTraceEntry *tep;
343 PRInt32 mark;
345 if ( (traceState == Suspended )
346 || ( ((RName *)handle)->state == Suspended )) {
347 return;
351 ** Get the next trace entry slot w/ minimum delay
353 PR_Lock( traceLock );
355 tep = &tBuf[next++];
356 if ( next > last ) {
357 next = 0;
359 if ( fetchLostData == PR_FALSE && next == fetchLastSeen ) {
360 fetchLostData = PR_TRUE;
363 mark = next;
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 )
385 PR_Lock( logLock );
386 logCount++;
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.
398 /* PR_Sleep(0); */
401 return;
402 } /* end PR_Trace() */
407 PR_IMPLEMENT(void)
408 PR_SetTraceOption(
409 PRTraceOption command, /* One of the enumerated values */
410 void *value /* command value or NULL */
413 RName * rnp;
415 switch ( command )
417 case PRTraceBufSize :
418 PR_Lock( traceLock );
419 PR_Free( tBuf );
420 bufSize = *(PRInt32 *)value;
421 NewTraceBuffer( bufSize );
422 PR_Unlock( traceLock );
423 PR_LOG( lm, PR_LOG_DEBUG,
424 ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize));
425 break;
427 case PRTraceEnable :
428 rnp = *(RName **)value;
429 rnp->state = Running;
430 PR_LOG( lm, PR_LOG_DEBUG,
431 ("PRSetTraceOption: PRTraceEnable: %p", rnp));
432 break;
434 case PRTraceDisable :
435 rnp = *(RName **)value;
436 rnp->state = Suspended;
437 PR_LOG( lm, PR_LOG_DEBUG,
438 ("PRSetTraceOption: PRTraceDisable: %p", rnp));
439 break;
441 case PRTraceSuspend :
442 traceState = Suspended;
443 PR_LOG( lm, PR_LOG_DEBUG,
444 ("PRSetTraceOption: PRTraceSuspend"));
445 break;
447 case PRTraceResume :
448 traceState = Running;
449 PR_LOG( lm, PR_LOG_DEBUG,
450 ("PRSetTraceOption: PRTraceResume"));
451 break;
453 case PRTraceSuspendRecording :
454 PR_Lock( logLock );
455 logOrder = LogSuspend;
456 PR_NotifyCondVar( logCVar );
457 PR_Unlock( logLock );
458 PR_LOG( lm, PR_LOG_DEBUG,
459 ("PRSetTraceOption: PRTraceSuspendRecording"));
460 break;
462 case PRTraceResumeRecording :
463 PR_LOG( lm, PR_LOG_DEBUG,
464 ("PRSetTraceOption: PRTraceResumeRecording"));
465 if ( logState != LogSuspend ) {
466 break;
468 PR_Lock( logLock );
469 logOrder = LogResume;
470 PR_NotifyCondVar( logCVar );
471 PR_Unlock( logLock );
472 break;
474 case PRTraceStopRecording :
475 PR_Lock( logLock );
476 logOrder = LogStop;
477 PR_NotifyCondVar( logCVar );
478 PR_Unlock( logLock );
479 PR_LOG( lm, PR_LOG_DEBUG,
480 ("PRSetTraceOption: PRTraceStopRecording"));
481 break;
483 case PRTraceLockHandles :
484 PR_LOG( lm, PR_LOG_DEBUG,
485 ("PRSetTraceOption: PRTraceLockTraceHandles"));
486 PR_Lock( traceLock );
487 break;
489 case PRTraceUnLockHandles :
490 PR_LOG( lm, PR_LOG_DEBUG,
491 ("PRSetTraceOption: PRTraceUnLockHandles"));
492 PR_Unlock( traceLock );
493 break;
495 default:
496 PR_LOG( lm, PR_LOG_ERROR,
497 ("PRSetTraceOption: Invalid command %ld", command ));
498 PR_ASSERT( 0 );
499 break;
500 } /* end switch() */
501 return;
502 } /* end PR_SetTraceOption() */
507 PR_IMPLEMENT(void)
508 PR_GetTraceOption(
509 PRTraceOption command, /* One of the enumerated values */
510 void *value /* command value or NULL */
513 switch ( command )
515 case PRTraceBufSize :
516 *((PRInt32 *)value) = bufSize;
517 PR_LOG( lm, PR_LOG_DEBUG,
518 ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize ));
519 break;
521 default:
522 PR_LOG( lm, PR_LOG_ERROR,
523 ("PRGetTraceOption: Invalid command %ld", command ));
524 PR_ASSERT( 0 );
525 break;
526 } /* end switch() */
527 return;
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;
541 RName *rnp = NULL;
543 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t"
544 "QName: %s, RName: %s", qName, rName ));
546 qh = PR_FindNextTraceQname( NULL );
547 while (qh != NULL)
549 rh = PR_FindNextTraceRname( NULL, qh );
550 while ( rh != NULL )
552 PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc );
553 if ( (strcmp( qName, qn ) == 0)
554 && (strcmp( rName, rn ) == 0 ))
556 rnp = (RName *)rh;
557 goto foundIt;
559 rh = PR_FindNextTraceRname( rh, qh );
561 qh = PR_FindNextTraceQname( NULL );
564 foundIt:
565 PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
566 return(rh);
567 } /* end PR_GetTraceHandleFromName() */
572 PR_IMPLEMENT(void)
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;
583 *qName = qnp->name;
584 *rName = rnp->name;
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 ));
591 return;
592 } /* end PR_GetTraceNameFromHandle() */
597 PR_IMPLEMENT(PRTraceHandle)
598 PR_FindNextTraceQname(
599 PRTraceHandle handle
602 QName *qnp = (QName *)handle;
604 if ( PR_CLIST_IS_EMPTY( &qNameList )) {
605 qnp = NULL;
607 else if ( qnp == NULL ) {
608 qnp = (QName *)PR_LIST_HEAD( &qNameList );
610 else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) {
611 qnp = NULL;
613 else {
614 qnp = (QName *)PR_NEXT_LINK( &qnp->link );
617 PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p",
618 handle, qnp ));
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 )) {
637 rnp = NULL;
639 else if ( rnp == NULL ) {
640 rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
642 else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) {
643 rnp = NULL;
645 else {
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 )
660 char *logFileName;
661 PRFileDesc *logFile;
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 */
672 logState = LogReset;
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"));
680 return NULL;
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()));
690 return NULL;
692 return logFile;
693 } /* end InitializeRecording() */
698 static void ProcessOrders( void )
700 switch ( logOrder )
702 case LogReset :
703 logOrder = logState = localState;
704 PR_LOG( lm, PR_LOG_DEBUG,
705 ("RecordTraceEntries: LogReset"));
706 break;
708 case LogSuspend :
709 localState = logOrder = logState = LogSuspend;
710 PR_LOG( lm, PR_LOG_DEBUG,
711 ("RecordTraceEntries: LogSuspend"));
712 break;
714 case LogResume :
715 localState = logOrder = logState = LogActive;
716 PR_LOG( lm, PR_LOG_DEBUG,
717 ("RecordTraceEntries: LogResume"));
718 break;
720 case LogStop :
721 logOrder = logState = LogStop;
722 PR_LOG( lm, PR_LOG_DEBUG,
723 ("RecordTraceEntries: LogStop"));
724 break;
726 default :
727 PR_LOG( lm, PR_LOG_ERROR,
728 ("RecordTraceEntries: Invalid logOrder: %ld", logOrder ));
729 PR_ASSERT( 0 );
730 break;
731 } /* end switch() */
732 return ;
733 } /* end ProcessOrders() */
738 static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount )
740 PRInt32 rc;
743 PR_LOG( lm, PR_LOG_ERROR,
744 ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount));
745 rc = PR_Write( logFile, buf, amount );
746 if ( rc == -1 )
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));
752 else
753 PR_LOG( lm, PR_LOG_DEBUG,
754 ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount));
756 return;
757 } /* end WriteTraceSegment() */
762 PR_IMPLEMENT(void)
763 PR_RecordTraceEntries(
764 void
767 PRFileDesc *logFile;
768 PRInt32 lostSegments;
769 PRInt32 currentSegment = 0;
770 void *buf;
771 PRBool doWrite;
773 logFile = InitializeRecording();
774 if ( logFile == NULL )
776 PR_LOG( lm, PR_LOG_DEBUG,
777 ("PR_RecordTraceEntries: Failed to initialize"));
778 return;
781 /* Do this until told to stop */
782 while ( logState != LogStop )
785 PR_Lock( logLock );
787 while ( (logCount == 0) && ( logOrder == logState ) ) {
788 PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT );
791 /* Handle state transitions */
792 if ( logOrder != logState ) {
793 ProcessOrders();
796 /* recalculate local controls */
797 if ( logCount )
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));
808 else
810 logCount--;
813 buf = tBuf + ( logEntriesPerSegment * currentSegment );
814 if (++currentSegment >= logSegments ) {
815 currentSegment = 0;
817 doWrite = PR_TRUE;
819 else {
820 doWrite = PR_FALSE;
823 PR_Unlock( logLock );
825 if ( doWrite == PR_TRUE )
827 if ( localState != LogSuspend ) {
828 WriteTraceSegment( logFile, buf, logSegSize );
830 else
831 PR_LOG( lm, PR_LOG_DEBUG,
832 ("RecordTraceEntries: PR_Write(): is suspended" ));
835 } /* end while(logState...) */
837 PR_Close( logFile );
838 PR_LOG( lm, PR_LOG_DEBUG,
839 ("RecordTraceEntries: exiting"));
840 return;
841 } /* end PR_RecordTraceEntries() */
846 PR_IMPLEMENT(PRIntn)
847 PR_GetTraceEntries(
848 PRTraceEntry *buffer, /* where to write output */
849 PRInt32 count, /* number to get */
850 PRInt32 *found /* number you got */
853 PRInt32 rc;
854 PRInt32 copied = 0;
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++);
880 fetchLastSeen = 0;
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));
893 *found = copied;
894 rc = ( fetchLostData == PR_TRUE )? 1 : 0;
895 fetchLostData = PR_FALSE;
897 PR_Unlock( traceLock );
898 return rc;
899 } /* end PR_GetTraceEntries() */
901 /* end prtrace.c */