blob: a4e4f6cc7905596f3762b32b6e33f2bf4727e996 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
** 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 *)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();
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() */