summaryrefslogtreecommitdiffstats
path: root/nsprpub/pr/src/misc/prtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsprpub/pr/src/misc/prtrace.c')
-rw-r--r--nsprpub/pr/src/misc/prtrace.c901
1 files changed, 901 insertions, 0 deletions
diff --git a/nsprpub/pr/src/misc/prtrace.c b/nsprpub/pr/src/misc/prtrace.c
new file mode 100644
index 0000000000..ef6b65104e
--- /dev/null
+++ b/nsprpub/pr/src/misc/prtrace.c
@@ -0,0 +1,901 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** prtrace.c -- NSPR Trace Instrumentation
+**
+** Implement the API defined in prtrace.h
+**
+**
+**
+*/
+
+#include <string.h>
+#include "primpl.h"
+
+
+#define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 )
+#define DEFAULT_BUFFER_SEGMENTS 2
+
+/*
+** Enumerate states in a RName structure
+*/
+typedef enum TraceState
+{
+ Running = 1,
+ Suspended = 2
+} TraceState;
+
+/*
+** Define QName structure
+*/
+typedef struct QName
+{
+ PRCList link;
+ PRCList rNameList;
+ char name[PRTRACE_NAME_MAX+1];
+} QName;
+
+/*
+** Define RName structure
+*/
+typedef struct RName
+{
+ PRCList link;
+ PRLock *lock;
+ QName *qName;
+ TraceState state;
+ char name[PRTRACE_NAME_MAX+1];
+ char desc[PRTRACE_DESC_MAX+1];
+} RName;
+
+
+/*
+** The Trace Facility database
+**
+*/
+static PRLogModuleInfo *lm;
+
+static PRLock *traceLock; /* Facility Lock */
+static PRCList qNameList; /* anchor to all QName structures */
+static TraceState traceState = Running;
+
+/*
+** in-memory trace buffer controls
+*/
+static PRTraceEntry *tBuf; /* pointer to buffer */
+static PRInt32 bufSize; /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */
+static volatile PRInt32 next; /* index to next PRTraceEntry */
+static PRInt32 last; /* index of highest numbered trace entry */
+
+/*
+** Real-time buffer capture controls
+*/
+static PRInt32 fetchLastSeen = 0;
+static PRBool fetchLostData = PR_FALSE;
+
+/*
+** Buffer write-to-file controls
+*/
+static PRLock *logLock; /* Sync lock */
+static PRCondVar *logCVar; /* Sync Condidtion Variable */
+/*
+** Inter-thread state communication.
+** Controling thread writes to logOrder under protection of logCVar
+** the logging thread reads logOrder and sets logState on Notify.
+**
+** logSegments, logCount, logLostData must be read and written under
+** protection of logLock, logCVar.
+**
+*/
+static enum LogState
+{
+ LogNotRunning, /* Initial state */
+ LogReset, /* Causes logger to re-calc controls */
+ LogActive, /* Logging in progress, set only by log thread */
+ LogSuspend, /* Suspend Logging */
+ LogResume, /* Resume Logging => LogActive */
+ LogStop /* Stop the log thread */
+} logOrder, logState, localState; /* controlling state variables */
+static PRInt32 logSegments; /* Number of buffer segments */
+static PRInt32 logEntries; /* number of Trace Entries in the buffer */
+static PRInt32 logEntriesPerSegment; /* number of PRTraceEntries per buffer segment */
+static PRInt32 logSegSize; /* size of buffer segment */
+static PRInt32 logCount; /* number of segments pending output */
+static PRInt32 logLostData; /* number of lost log buffer segments */
+
+/*
+** end Trace Database
+**
+*/
+
+/*
+** _PR_InitializeTrace() -- Initialize the trace facility
+*/
+static void NewTraceBuffer( PRInt32 size )
+{
+ /*
+ ** calculate the size of the buffer
+ ** round down so that each segment has the same number of
+ ** trace entries
+ */
+ logSegments = DEFAULT_BUFFER_SEGMENTS;
+ logEntries = size / sizeof(PRTraceEntry);
+ logEntriesPerSegment = logEntries / logSegments;
+ logEntries = logSegments * logEntriesPerSegment;
+ bufSize = logEntries * sizeof(PRTraceEntry);
+ logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry);
+ PR_ASSERT( bufSize != 0);
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld",
+ logSegments, logEntries, logEntriesPerSegment, logSegSize ));
+
+
+ tBuf = PR_Malloc( bufSize );
+ if ( tBuf == NULL )
+ {
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("PRTrace: Failed to get trace buffer"));
+ PR_ASSERT( 0 );
+ }
+ else
+ {
+ PR_LOG( lm, PR_LOG_NOTICE,
+ ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf));
+ }
+
+ next = 0;
+ last = logEntries -1;
+ logCount = 0;
+ logLostData = PR_TRUE; /* not really on first call */
+ logOrder = LogReset;
+
+} /* end NewTraceBuffer() */
+
+/*
+** _PR_InitializeTrace() -- Initialize the trace facility
+*/
+static void _PR_InitializeTrace( void )
+{
+ /* The lock pointer better be null on this call */
+ PR_ASSERT( traceLock == NULL );
+
+ traceLock = PR_NewLock();
+ PR_ASSERT( traceLock != NULL );
+
+ PR_Lock( traceLock );
+
+ PR_INIT_CLIST( &qNameList );
+
+ lm = PR_NewLogModule("trace");
+
+ bufSize = DEFAULT_TRACE_BUFSIZE;
+ NewTraceBuffer( bufSize );
+
+ /* Initialize logging controls */
+ logLock = PR_NewLock();
+ logCVar = PR_NewCondVar( logLock );
+
+ PR_Unlock( traceLock );
+ return;
+} /* end _PR_InitializeTrace() */
+
+/*
+** Create a Trace Handle
+*/
+PR_IMPLEMENT(PRTraceHandle)
+PR_CreateTrace(
+ const char *qName, /* QName for this trace handle */
+ const char *rName, /* RName for this trace handle */
+ const char *description /* description for this trace handle */
+)
+{
+ QName *qnp;
+ RName *rnp;
+ PRBool matchQname = PR_FALSE;
+
+ /* Self initialize, if necessary */
+ if ( traceLock == NULL ) {
+ _PR_InitializeTrace();
+ }
+
+ /* Validate input arguments */
+ PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX );
+ PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX );
+ PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX );
+
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName));
+
+ /* Lock the Facility */
+ PR_Lock( traceLock );
+
+ /* Do we already have a matching QName? */
+ if (!PR_CLIST_IS_EMPTY( &qNameList ))
+ {
+ qnp = (QName *) PR_LIST_HEAD( &qNameList );
+ do {
+ if ( strcmp(qnp->name, qName) == 0)
+ {
+ matchQname = PR_TRUE;
+ break;
+ }
+ qnp = (QName *)PR_NEXT_LINK( &qnp->link );
+ } while( qnp != (QName *)&qNameList );
+ }
+ /*
+ ** If we did not find a matching QName,
+ ** allocate one and initialize it.
+ ** link it onto the qNameList.
+ **
+ */
+ if ( matchQname != PR_TRUE )
+ {
+ qnp = PR_NEWZAP( QName );
+ PR_ASSERT( qnp != NULL );
+ PR_INIT_CLIST( &qnp->link );
+ PR_INIT_CLIST( &qnp->rNameList );
+ strcpy( qnp->name, qName );
+ PR_APPEND_LINK( &qnp->link, &qNameList );
+ }
+
+ /* Do we already have a matching RName? */
+ if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
+ {
+ rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
+ do {
+ /*
+ ** No duplicate RNames are allowed within a QName
+ **
+ */
+ PR_ASSERT( strcmp(rnp->name, rName));
+ rnp = (RName *)PR_NEXT_LINK( &rnp->link );
+ } while( rnp != (RName *)&qnp->rNameList );
+ }
+
+ /* Get a new RName structure; initialize its members */
+ rnp = PR_NEWZAP( RName );
+ PR_ASSERT( rnp != NULL );
+ PR_INIT_CLIST( &rnp->link );
+ strcpy( rnp->name, rName );
+ strcpy( rnp->desc, description );
+ rnp->lock = PR_NewLock();
+ rnp->state = Running;
+ if ( rnp->lock == NULL )
+ {
+ PR_ASSERT(0);
+ }
+
+ PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */
+ rnp->qName = qnp; /* point the RName to the QName */
+
+ /* Unlock the Facility */
+ PR_Unlock( traceLock );
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t",
+ qName, qnp, rName, rnp ));
+
+ return((PRTraceHandle)rnp);
+} /* end PR_CreateTrace() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void)
+PR_DestroyTrace(
+ PRTraceHandle handle /* Handle to be destroyed */
+)
+{
+ RName *rnp = (RName *)handle;
+ QName *qnp = rnp->qName;
+
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s",
+ qnp->name, rnp->name));
+
+ /* Lock the Facility */
+ PR_Lock( traceLock );
+
+ /*
+ ** Remove RName from the list of RNames in QName
+ ** and free RName
+ */
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p",
+ rnp->name, rnp));
+ PR_REMOVE_LINK( &rnp->link );
+ PR_Free( rnp->lock );
+ PR_DELETE( rnp );
+
+ /*
+ ** If this is the last RName within QName
+ ** remove QName from the qNameList and free it
+ */
+ if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
+ {
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p",
+ qnp->name, qnp));
+ PR_REMOVE_LINK( &qnp->link );
+ PR_DELETE( qnp );
+ }
+
+ /* Unlock the Facility */
+ PR_Unlock( traceLock );
+ return;
+} /* end PR_DestroyTrace() */
+
+/*
+** Create a TraceEntry in the trace buffer
+*/
+PR_IMPLEMENT(void)
+PR_Trace(
+ PRTraceHandle handle, /* use this trace handle */
+ PRUint32 userData0, /* User supplied data word 0 */
+ PRUint32 userData1, /* User supplied data word 1 */
+ PRUint32 userData2, /* User supplied data word 2 */
+ PRUint32 userData3, /* User supplied data word 3 */
+ PRUint32 userData4, /* User supplied data word 4 */
+ PRUint32 userData5, /* User supplied data word 5 */
+ PRUint32 userData6, /* User supplied data word 6 */
+ PRUint32 userData7 /* User supplied data word 7 */
+)
+{
+ PRTraceEntry *tep;
+ PRInt32 mark;
+
+ if ( (traceState == Suspended )
+ || ( ((RName *)handle)->state == Suspended )) {
+ return;
+ }
+
+ /*
+ ** Get the next trace entry slot w/ minimum delay
+ */
+ PR_Lock( traceLock );
+
+ tep = &tBuf[next++];
+ if ( next > last ) {
+ next = 0;
+ }
+ if ( fetchLostData == PR_FALSE && next == fetchLastSeen ) {
+ fetchLostData = PR_TRUE;
+ }
+
+ mark = next;
+
+ PR_Unlock( traceLock );
+
+ /*
+ ** We have a trace entry. Fill it in.
+ */
+ tep->thread = PR_GetCurrentThread();
+ tep->handle = handle;
+ tep->time = PR_Now();
+ tep->userData[0] = userData0;
+ tep->userData[1] = userData1;
+ tep->userData[2] = userData2;
+ tep->userData[3] = userData3;
+ tep->userData[4] = userData4;
+ tep->userData[5] = userData5;
+ tep->userData[6] = userData6;
+ tep->userData[7] = userData7;
+
+ /* When buffer segment is full, signal trace log thread to run */
+ if (( mark % logEntriesPerSegment) == 0 )
+ {
+ PR_Lock( logLock );
+ logCount++;
+ PR_NotifyCondVar( logCVar );
+ PR_Unlock( logLock );
+ /*
+ ** Gh0D! This is awful!
+ ** Anyway, to minimize lost trace data segments,
+ ** I inserted the PR_Sleep(0) to cause a context switch
+ ** so that the log thread could run.
+ ** I know, it perturbs the universe and may cause
+ ** funny things to happen in the optimized builds.
+ ** Take it out, lose data; leave it in risk Heisenberg.
+ */
+ /* PR_Sleep(0); */
+ }
+
+ return;
+} /* end PR_Trace() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void)
+PR_SetTraceOption(
+ PRTraceOption command, /* One of the enumerated values */
+ void *value /* command value or NULL */
+)
+{
+ RName * rnp;
+
+ switch ( command )
+ {
+ case PRTraceBufSize :
+ PR_Lock( traceLock );
+ PR_Free( tBuf );
+ bufSize = *(PRInt32 *)value;
+ NewTraceBuffer( bufSize );
+ PR_Unlock( traceLock );
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize));
+ break;
+
+ case PRTraceEnable :
+ rnp = *(RName **)value;
+ rnp->state = Running;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceEnable: %p", rnp));
+ break;
+
+ case PRTraceDisable :
+ rnp = *(RName **)value;
+ rnp->state = Suspended;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceDisable: %p", rnp));
+ break;
+
+ case PRTraceSuspend :
+ traceState = Suspended;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceSuspend"));
+ break;
+
+ case PRTraceResume :
+ traceState = Running;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceResume"));
+ break;
+
+ case PRTraceSuspendRecording :
+ PR_Lock( logLock );
+ logOrder = LogSuspend;
+ PR_NotifyCondVar( logCVar );
+ PR_Unlock( logLock );
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceSuspendRecording"));
+ break;
+
+ case PRTraceResumeRecording :
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceResumeRecording"));
+ if ( logState != LogSuspend ) {
+ break;
+ }
+ PR_Lock( logLock );
+ logOrder = LogResume;
+ PR_NotifyCondVar( logCVar );
+ PR_Unlock( logLock );
+ break;
+
+ case PRTraceStopRecording :
+ PR_Lock( logLock );
+ logOrder = LogStop;
+ PR_NotifyCondVar( logCVar );
+ PR_Unlock( logLock );
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceStopRecording"));
+ break;
+
+ case PRTraceLockHandles :
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceLockTraceHandles"));
+ PR_Lock( traceLock );
+ break;
+
+ case PRTraceUnLockHandles :
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRSetTraceOption: PRTraceUnLockHandles"));
+ PR_Unlock( traceLock );
+ break;
+
+ default:
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("PRSetTraceOption: Invalid command %ld", command ));
+ PR_ASSERT( 0 );
+ break;
+ } /* end switch() */
+ return;
+} /* end PR_SetTraceOption() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void)
+PR_GetTraceOption(
+ PRTraceOption command, /* One of the enumerated values */
+ void *value /* command value or NULL */
+)
+{
+ switch ( command )
+ {
+ case PRTraceBufSize :
+ *((PRInt32 *)value) = bufSize;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize ));
+ break;
+
+ default:
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("PRGetTraceOption: Invalid command %ld", command ));
+ PR_ASSERT( 0 );
+ break;
+ } /* end switch() */
+ return;
+} /* end PR_GetTraceOption() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRTraceHandle)
+PR_GetTraceHandleFromName(
+ const char *qName, /* QName search argument */
+ const char *rName /* RName search argument */
+)
+{
+ const char *qn, *rn, *desc;
+ PRTraceHandle qh, rh = NULL;
+ RName *rnp = NULL;
+
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t"
+ "QName: %s, RName: %s", qName, rName ));
+
+ qh = PR_FindNextTraceQname( NULL );
+ while (qh != NULL)
+ {
+ rh = PR_FindNextTraceRname( NULL, qh );
+ while ( rh != NULL )
+ {
+ PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc );
+ if ( (strcmp( qName, qn ) == 0)
+ && (strcmp( rName, rn ) == 0 ))
+ {
+ rnp = (RName *)rh;
+ goto foundIt;
+ }
+ rh = PR_FindNextTraceRname( rh, qh );
+ }
+ qh = PR_FindNextTraceQname( NULL );
+ }
+
+foundIt:
+ PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
+ return(rh);
+} /* end PR_GetTraceHandleFromName() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void)
+PR_GetTraceNameFromHandle(
+ PRTraceHandle handle, /* handle as search argument */
+ const char **qName, /* pointer to associated QName */
+ const char **rName, /* pointer to associated RName */
+ const char **description /* pointer to associated description */
+)
+{
+ RName *rnp = (RName *)handle;
+ QName *qnp = rnp->qName;
+
+ *qName = qnp->name;
+ *rName = rnp->name;
+ *description = rnp->desc;
+
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: "
+ "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s",
+ qnp, rnp, qnp->name, rnp->name, rnp->desc ));
+
+ return;
+} /* end PR_GetTraceNameFromHandle() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRTraceHandle)
+PR_FindNextTraceQname(
+ PRTraceHandle handle
+)
+{
+ QName *qnp = (QName *)handle;
+
+ if ( PR_CLIST_IS_EMPTY( &qNameList )) {
+ qnp = NULL;
+ }
+ else if ( qnp == NULL ) {
+ qnp = (QName *)PR_LIST_HEAD( &qNameList );
+ }
+ else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) {
+ qnp = NULL;
+ }
+ else {
+ qnp = (QName *)PR_NEXT_LINK( &qnp->link );
+ }
+
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p",
+ handle, qnp ));
+
+ return((PRTraceHandle)qnp);
+} /* end PR_FindNextTraceQname() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRTraceHandle)
+PR_FindNextTraceRname(
+ PRTraceHandle rhandle,
+ PRTraceHandle qhandle
+)
+{
+ RName *rnp = (RName *)rhandle;
+ QName *qnp = (QName *)qhandle;
+
+
+ if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) {
+ rnp = NULL;
+ }
+ else if ( rnp == NULL ) {
+ rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
+ }
+ else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) {
+ rnp = NULL;
+ }
+ else {
+ rnp = (RName *)PR_NEXT_LINK( &rnp->link );
+ }
+
+ PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p",
+ rhandle, qhandle, rnp ));
+
+ return((PRTraceHandle)rnp);
+} /* end PR_FindNextTraceRname() */
+
+/*
+**
+*/
+static PRFileDesc * InitializeRecording( void )
+{
+ char *logFileName;
+ PRFileDesc *logFile;
+
+ /* Self initialize, if necessary */
+ if ( traceLock == NULL ) {
+ _PR_InitializeTrace();
+ }
+
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PR_RecordTraceEntries: begins"));
+
+ logLostData = 0; /* reset at entry */
+ logState = LogReset;
+
+ /* Get the filename for the logfile from the environment */
+ logFileName = PR_GetEnvSecure( "NSPR_TRACE_LOG" );
+ if ( logFileName == NULL )
+ {
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("RecordTraceEntries: Environment variable not defined. Exiting"));
+ return NULL;
+ }
+
+ /* Open the logfile */
+ logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 );
+ if ( logFile == NULL )
+ {
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld",
+ logFileName, PR_GetOSError()));
+ return NULL;
+ }
+ return logFile;
+} /* end InitializeRecording() */
+
+/*
+**
+*/
+static void ProcessOrders( void )
+{
+ switch ( logOrder )
+ {
+ case LogReset :
+ logOrder = logState = localState;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("RecordTraceEntries: LogReset"));
+ break;
+
+ case LogSuspend :
+ localState = logOrder = logState = LogSuspend;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("RecordTraceEntries: LogSuspend"));
+ break;
+
+ case LogResume :
+ localState = logOrder = logState = LogActive;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("RecordTraceEntries: LogResume"));
+ break;
+
+ case LogStop :
+ logOrder = logState = LogStop;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("RecordTraceEntries: LogStop"));
+ break;
+
+ default :
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("RecordTraceEntries: Invalid logOrder: %ld", logOrder ));
+ PR_ASSERT( 0 );
+ break;
+ } /* end switch() */
+ return ;
+} /* end ProcessOrders() */
+
+/*
+**
+*/
+static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount )
+{
+ PRInt32 rc;
+
+
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount));
+ rc = PR_Write( logFile, buf, amount );
+ if ( rc == -1 )
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() ));
+ else if ( rc != amount )
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc));
+ else
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount));
+
+ return;
+} /* end WriteTraceSegment() */
+
+/*
+**
+*/
+PR_IMPLEMENT(void)
+PR_RecordTraceEntries(
+ void
+)
+{
+ PRFileDesc *logFile;
+ PRInt32 lostSegments;
+ PRInt32 currentSegment = 0;
+ void *buf;
+ PRBool doWrite;
+
+ logFile = InitializeRecording();
+ if ( logFile == NULL )
+ {
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PR_RecordTraceEntries: Failed to initialize"));
+ return;
+ }
+
+ /* Do this until told to stop */
+ while ( logState != LogStop )
+ {
+
+ PR_Lock( logLock );
+
+ while ( (logCount == 0) && ( logOrder == logState ) ) {
+ PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT );
+ }
+
+ /* Handle state transitions */
+ if ( logOrder != logState ) {
+ ProcessOrders();
+ }
+
+ /* recalculate local controls */
+ if ( logCount )
+ {
+ lostSegments = logCount - logSegments;
+ if ( lostSegments > 0 )
+ {
+ logLostData += ( logCount - logSegments );
+ logCount = (logCount % logSegments);
+ currentSegment = logCount;
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("PR_RecordTraceEntries: LostData segments: %ld", logLostData));
+ }
+ else
+ {
+ logCount--;
+ }
+
+ buf = tBuf + ( logEntriesPerSegment * currentSegment );
+ if (++currentSegment >= logSegments ) {
+ currentSegment = 0;
+ }
+ doWrite = PR_TRUE;
+ }
+ else {
+ doWrite = PR_FALSE;
+ }
+
+ PR_Unlock( logLock );
+
+ if ( doWrite == PR_TRUE )
+ {
+ if ( localState != LogSuspend ) {
+ WriteTraceSegment( logFile, buf, logSegSize );
+ }
+ else
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("RecordTraceEntries: PR_Write(): is suspended" ));
+ }
+
+ } /* end while(logState...) */
+
+ PR_Close( logFile );
+ PR_LOG( lm, PR_LOG_DEBUG,
+ ("RecordTraceEntries: exiting"));
+ return;
+} /* end PR_RecordTraceEntries() */
+
+/*
+**
+*/
+PR_IMPLEMENT(PRIntn)
+PR_GetTraceEntries(
+ PRTraceEntry *buffer, /* where to write output */
+ PRInt32 count, /* number to get */
+ PRInt32 *found /* number you got */
+)
+{
+ PRInt32 rc;
+ PRInt32 copied = 0;
+
+ PR_Lock( traceLock );
+
+ /*
+ ** Depending on where the LastSeen and Next indices are,
+ ** copy the trace buffer in one or two pieces.
+ */
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen));
+
+ if ( fetchLastSeen <= next )
+ {
+ while (( count-- > 0 ) && (fetchLastSeen < next ))
+ {
+ *(buffer + copied++) = *(tBuf + fetchLastSeen++);
+ }
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
+ }
+ else /* copy in 2 parts */
+ {
+ while ( count-- > 0 && fetchLastSeen <= last )
+ {
+ *(buffer + copied++) = *(tBuf + fetchLastSeen++);
+ }
+ fetchLastSeen = 0;
+
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
+
+ while ( count-- > 0 && fetchLastSeen < next )
+ {
+ *(buffer + copied++) = *(tBuf + fetchLastSeen++);
+ }
+ PR_LOG( lm, PR_LOG_ERROR,
+ ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen));
+ }
+
+ *found = copied;
+ rc = ( fetchLostData == PR_TRUE )? 1 : 0;
+ fetchLostData = PR_FALSE;
+
+ PR_Unlock( traceLock );
+ return rc;
+} /* end PR_GetTraceEntries() */
+
+/* end prtrace.c */