diff options
Diffstat (limited to 'nsprpub/pr/src/misc/prcountr.c')
-rw-r--r-- | nsprpub/pr/src/misc/prcountr.c | 474 |
1 files changed, 474 insertions, 0 deletions
diff --git a/nsprpub/pr/src/misc/prcountr.c b/nsprpub/pr/src/misc/prcountr.c new file mode 100644 index 000000000..0f126ad08 --- /dev/null +++ b/nsprpub/pr/src/misc/prcountr.c @@ -0,0 +1,474 @@ +/* -*- 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/. */ + +/* +** prcountr.c -- NSPR Instrumentation Counters +** +** Implement the interface defined in prcountr.h +** +** Design Notes: +** +** The Counter Facility (CF) has a single anchor: qNameList. +** The anchor is a PRCList. qNameList is a list of links in QName +** structures. From qNameList any QName structure and its +** associated RName structure can be located. +** +** For each QName, a list of RName structures is anchored at +** rnLink in the QName structure. +** +** The counter itself is embedded in the RName structure. +** +** For manipulating the counter database, single lock is used to +** protect the entire list: counterLock. +** +** A PRCounterHandle, defined in prcountr.h, is really a pointer +** to a RName structure. References by PRCounterHandle are +** dead-reconed to the RName structure. The PRCounterHandle is +** "overloaded" for traversing the QName structures; only the +** function PR_FindNextQnameHandle() uses this overloading. +** +** +** ToDo (lth): decide on how to lock or atomically update +** individual counters. Candidates are: the global lock; a lock +** per RName structure; Atomic operations (Note that there are +** not adaquate atomic operations (yet) to achieve this goal). At +** this writing (6/19/98) , the update of the counter variable in +** a QName structure is unprotected. +** +*/ + +#include "prcountr.h" +#include "prclist.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include <string.h> + +/* +** +*/ +typedef struct QName +{ + PRCList link; + PRCList rNameList; + char name[PRCOUNTER_NAME_MAX+1]; +} QName; + +/* +** +*/ +typedef struct RName +{ + PRCList link; + QName *qName; + PRLock *lock; + volatile PRUint32 counter; + char name[PRCOUNTER_NAME_MAX+1]; + char desc[PRCOUNTER_DESC_MAX+1]; +} RName; + + +/* +** Define the Counter Facility database +*/ +static PRLock *counterLock; +static PRCList qNameList; +static PRLogModuleInfo *lm; + +/* +** _PR_CounterInitialize() -- Initialize the Counter Facility +** +*/ +static void _PR_CounterInitialize( void ) +{ + /* + ** This function should be called only once + */ + PR_ASSERT( counterLock == NULL ); + + counterLock = PR_NewLock(); + PR_INIT_CLIST( &qNameList ); + lm = PR_NewLogModule("counters"); + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete")); + + return; +} /* end _PR_CounterInitialize() */ + +/* +** PR_CreateCounter() -- Create a counter +** +** ValidateArguments +** Lock +** if (qName not already in database) +** NewQname +** if (rName already in database ) +** Assert +** else NewRname +** NewCounter +** link 'em up +** Unlock +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_CreateCounter( + const char *qName, + const char *rName, + const char *description +) +{ + QName *qnp; + RName *rnp; + PRBool matchQname = PR_FALSE; + + /* Self initialize, if necessary */ + if ( counterLock == NULL ) + _PR_CounterInitialize(); + + /* Validate input arguments */ + PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX ); + PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX ); + PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX ); + + /* Lock the Facility */ + PR_Lock( counterLock ); + + /* 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(); + 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( counterLock ); + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t", + qName, qnp, rName, rnp )); + + return((PRCounterHandle)rnp); +} /* end PR_CreateCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DestroyCounter( + PRCounterHandle handle +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s", + qnp->name, rnp->name)); + + /* Lock the Facility */ + PR_Lock( counterLock ); + + /* + ** Remove RName from the list of RNames in QName + ** and free RName + */ + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: 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, ("PR_Counter: Deleting unused QName: %s, %p", + qnp->name, qnp)); + PR_REMOVE_LINK( &qnp->link ); + PR_DELETE( qnp ); + } + + /* Unlock the Facility */ + PR_Unlock( counterLock ); + return; +} /* end PR_DestroyCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_GetCounterHandleFromName( + const char *qName, + const char *rName +) +{ + const char *qn, *rn, *desc; + PRCounterHandle qh, rh = NULL; + RName *rnp = NULL; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t" + "QName: %s, RName: %s", qName, rName )); + + qh = PR_FindNextCounterQname( NULL ); + while (qh != NULL) + { + rh = PR_FindNextCounterRname( NULL, qh ); + while ( rh != NULL ) + { + PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc ); + if ( (strcmp( qName, qn ) == 0) + && (strcmp( rName, rn ) == 0 )) + { + rnp = (RName *)rh; + goto foundIt; + } + rh = PR_FindNextCounterRname( rh, qh ); + } + qh = PR_FindNextCounterQname( NULL ); + } + +foundIt: + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); + return(rh); +} /* end PR_GetCounterHandleFromName() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_GetCounterNameFromHandle( + PRCounterHandle handle, + const char **qName, + const char **rName, + const char **description +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + *qName = qnp->name; + *rName = rnp->name; + *description = rnp->desc; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterNameFromHandle: " + "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", + qnp, rnp, qnp->name, rnp->name, rnp->desc )); + + return; +} /* end PR_GetCounterNameFromHandle() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_IncrementCounter( + PRCounterHandle handle +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter++; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_IncrementCounter() */ + + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DecrementCounter( + PRCounterHandle handle +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter--; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_DecrementCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_AddToCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter += value; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_AddToCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SubtractFromCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter -= value; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_SubtractFromCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRUint32) + PR_GetCounter( + PRCounterHandle handle +) +{ + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return(((RName *)handle)->counter); +} /* end PR_GetCounter() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SetCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + ((RName *)handle)->counter = value; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_SetCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_FindNextCounterQname( + PRCounterHandle 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, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", + handle, qnp )); + + return((PRCounterHandle)qnp); +} /* end PR_FindNextCounterQname() */ + + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle 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, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", + rhandle, qhandle, rnp )); + + return((PRCounterHandle)rnp); +} /* end PR_FindNextCounterRname() */ |