📄 prtrace.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//*** prtrace.c -- NSPR Trace Instrumentation**** Implement the API defined in prtrace.h*******/#if defined (DEBUG) || defined (FORCE_NSPR_TRACE)#include <string.h>#include "prtrace.h"#include "prclist.h"#include "prlock.h"#include "prcvar.h"#include "prio.h"#include "prlog.h"#include "prenv.h"#include "prmem.h"#include "prerror.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 *)PR_LIST_HEAD( &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 *)PR_LIST_HEAD( &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, loose 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -