Back to index

lightning-sunbird  0.9+nobinonly
prcountr.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** prcountr.c -- NSPR Instrumentation Counters
00040 **
00041 ** Implement the interface defined in prcountr.h
00042 **
00043 ** Design Notes:
00044 **
00045 ** The Counter Facility (CF) has a single anchor: qNameList.      
00046 ** The anchor is a PRCList. qNameList is a list of links in QName
00047 ** structures. From qNameList any QName structure and its
00048 ** associated RName structure can be located. 
00049 ** 
00050 ** For each QName, a list of RName structures is anchored at
00051 ** rnLink in the QName structure.
00052 ** 
00053 ** The counter itself is embedded in the RName structure.
00054 ** 
00055 ** For manipulating the counter database, single lock is used to
00056 ** protect the entire list: counterLock.
00057 **
00058 ** A PRCounterHandle, defined in prcountr.h, is really a pointer
00059 ** to a RName structure. References by PRCounterHandle are
00060 ** dead-reconed to the RName structure. The PRCounterHandle is
00061 ** "overloaded" for traversing the QName structures; only the
00062 ** function PR_FindNextQnameHandle() uses this overloading.
00063 **
00064 ** 
00065 ** ToDo (lth): decide on how to lock or atomically update
00066 ** individual counters. Candidates are: the global lock; a lock
00067 ** per RName structure; Atomic operations (Note that there are
00068 ** not adaquate atomic operations (yet) to achieve this goal). At
00069 ** this writing (6/19/98) , the update of the counter variable in
00070 ** a QName structure is unprotected.
00071 **
00072 */
00073 
00074 #include "prcountr.h"
00075 #include "prclist.h"
00076 #include "prlock.h"
00077 #include "prlog.h"
00078 #include "prmem.h"
00079 #include <string.h>
00080 
00081 /*
00082 **
00083 */
00084 typedef struct QName
00085 {
00086     PRCList link;
00087     PRCList rNameList;
00088     char    name[PRCOUNTER_NAME_MAX+1];
00089 } QName;
00090 
00091 /*
00092 **
00093 */
00094 typedef struct RName
00095 {
00096     PRCList link;
00097     QName   *qName;
00098     PRLock  *lock;
00099     volatile PRUint32   counter;    
00100     char    name[PRCOUNTER_NAME_MAX+1]; 
00101     char    desc[PRCOUNTER_DESC_MAX+1]; 
00102 } RName;
00103 
00104 
00105 /*
00106 ** Define the Counter Facility database
00107 */
00108 static PRLock  *counterLock;
00109 static PRCList qNameList;
00110 static PRLogModuleInfo *lm;
00111 
00112 /*
00113 ** _PR_CounterInitialize() -- Initialize the Counter Facility
00114 **
00115 */
00116 static void _PR_CounterInitialize( void )
00117 {
00118     /*
00119     ** This function should be called only once
00120     */
00121     PR_ASSERT( counterLock == NULL );
00122     
00123     counterLock = PR_NewLock();
00124     PR_INIT_CLIST( &qNameList );
00125     lm = PR_NewLogModule("counters");
00126     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete"));
00127 
00128     return;
00129 } /* end _PR_CounterInitialize() */
00130 
00131 /*
00132 ** PR_CreateCounter() -- Create a counter
00133 **
00134 **  ValidateArguments
00135 **  Lock
00136 **  if (qName not already in database)
00137 **      NewQname
00138 **  if (rName already in database )
00139 **      Assert
00140 **  else NewRname
00141 **  NewCounter
00142 **  link 'em up
00143 **  Unlock
00144 **
00145 */
00146 PR_IMPLEMENT(PRCounterHandle) 
00147        PR_CreateCounter( 
00148               const char *qName, 
00149        const char *rName, 
00150         const char *description 
00151 ) 
00152 {
00153     QName   *qnp;
00154     RName   *rnp;
00155     PRBool  matchQname = PR_FALSE;
00156 
00157     /* Self initialize, if necessary */
00158     if ( counterLock == NULL )
00159         _PR_CounterInitialize();
00160 
00161     /* Validate input arguments */
00162     PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX );
00163     PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX );
00164     PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX );
00165 
00166     /* Lock the Facility */
00167     PR_Lock( counterLock );
00168 
00169     /* Do we already have a matching QName? */
00170     if (!PR_CLIST_IS_EMPTY( &qNameList ))
00171     {
00172         qnp = (QName *) PR_LIST_HEAD( &qNameList );
00173         do {
00174             if ( strcmp(qnp->name, qName) == 0)
00175             {
00176                 matchQname = PR_TRUE;
00177                 break;
00178             }
00179             qnp = (QName *)PR_NEXT_LINK( &qnp->link );
00180         } while( qnp != (QName *)PR_LIST_HEAD( &qNameList ));
00181     }
00182     /*
00183     ** If we did not find a matching QName,
00184     **    allocate one and initialize it.
00185     **    link it onto the qNameList.
00186     **
00187     */
00188     if ( matchQname != PR_TRUE )
00189     {
00190         qnp = PR_NEWZAP( QName );
00191         PR_ASSERT( qnp != NULL );
00192         PR_INIT_CLIST( &qnp->link ); 
00193         PR_INIT_CLIST( &qnp->rNameList ); 
00194         strcpy( qnp->name, qName );
00195         PR_APPEND_LINK( &qnp->link, &qNameList ); 
00196     }
00197 
00198     /* Do we already have a matching RName? */
00199     if (!PR_CLIST_IS_EMPTY( &qnp->rNameList ))
00200     {
00201         rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList );
00202         do {
00203             /*
00204             ** No duplicate RNames are allowed within a QName
00205             **
00206             */
00207             PR_ASSERT( strcmp(rnp->name, rName));
00208             rnp = (RName *)PR_NEXT_LINK( &rnp->link );
00209         } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList ));
00210     }
00211 
00212     /* Get a new RName structure; initialize its members */
00213     rnp = PR_NEWZAP( RName );
00214     PR_ASSERT( rnp != NULL );
00215     PR_INIT_CLIST( &rnp->link );
00216     strcpy( rnp->name, rName );
00217     strcpy( rnp->desc, description );
00218     rnp->lock = PR_NewLock();
00219     if ( rnp->lock == NULL )
00220     {
00221         PR_ASSERT(0);
00222     }
00223 
00224     PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */    
00225     rnp->qName = qnp;                       /* point the RName to the QName */
00226 
00227     /* Unlock the Facility */
00228     PR_Unlock( counterLock );
00229     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t",
00230         qName, qnp, rName, rnp ));
00231 
00232     return((PRCounterHandle)rnp);
00233 } /*  end PR_CreateCounter() */
00234   
00235 
00236 /*
00237 **
00238 */
00239 PR_IMPLEMENT(void) 
00240        PR_DestroyCounter( 
00241               PRCounterHandle handle 
00242 )
00243 {
00244     RName   *rnp = (RName *)handle;
00245     QName   *qnp = rnp->qName;
00246 
00247     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s", 
00248         qnp->name, rnp->name));
00249 
00250     /* Lock the Facility */
00251     PR_Lock( counterLock );
00252 
00253     /*
00254     ** Remove RName from the list of RNames in QName
00255     ** and free RName
00256     */
00257     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting RName: %s, %p", 
00258         rnp->name, rnp));
00259     PR_REMOVE_LINK( &rnp->link );
00260     PR_Free( rnp->lock );
00261     PR_DELETE( rnp );
00262 
00263     /*
00264     ** If this is the last RName within QName
00265     **   remove QName from the qNameList and free it
00266     */
00267     if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) )
00268     {
00269         PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting unused QName: %s, %p", 
00270             qnp->name, qnp));
00271         PR_REMOVE_LINK( &qnp->link );
00272         PR_DELETE( qnp );
00273     } 
00274 
00275     /* Unlock the Facility */
00276     PR_Unlock( counterLock );
00277     return;
00278 } /*  end PR_DestroyCounter() */
00279 
00280 /*
00281 **
00282 */
00283 PR_IMPLEMENT(PRCounterHandle) 
00284        PR_GetCounterHandleFromName( 
00285        const char *qName, 
00286        const char *rName 
00287 )
00288 {
00289     const char    *qn, *rn, *desc;
00290     PRCounterHandle     qh, rh = NULL;
00291     RName   *rnp = NULL;
00292 
00293     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t"
00294         "QName: %s, RName: %s", qName, rName ));
00295 
00296     qh = PR_FindNextCounterQname( NULL );
00297     while (qh != NULL)
00298     {
00299         rh = PR_FindNextCounterRname( NULL, qh );
00300         while ( rh != NULL )
00301         {
00302             PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc );
00303             if ( (strcmp( qName, qn ) == 0)
00304                 && (strcmp( rName, rn ) == 0 ))
00305             {
00306                 rnp = (RName *)rh;
00307                 goto foundIt;
00308             }
00309             rh = PR_FindNextCounterRname( rh, qh );
00310         }
00311         qh = PR_FindNextCounterQname( NULL );
00312     }
00313 
00314 foundIt:
00315     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp ));
00316     return(rh);
00317 } /*  end PR_GetCounterHandleFromName() */
00318 
00319 /*
00320 **
00321 */
00322 PR_IMPLEMENT(void) 
00323        PR_GetCounterNameFromHandle( 
00324        PRCounterHandle handle,  
00325            const char **qName, 
00326            const char **rName, 
00327               const char **description 
00328 )
00329 {
00330     RName   *rnp = (RName *)handle;
00331     QName   *qnp = rnp->qName;
00332 
00333     *qName = qnp->name;
00334     *rName = rnp->name;
00335     *description = rnp->desc;
00336 
00337     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterNameFromHandle: "
00338         "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 
00339         qnp, rnp, qnp->name, rnp->name, rnp->desc ));
00340 
00341     return;
00342 } /*  end PR_GetCounterNameFromHandle() */
00343 
00344 
00345 /*
00346 **
00347 */
00348 PR_IMPLEMENT(void) 
00349        PR_IncrementCounter( 
00350               PRCounterHandle handle
00351 )
00352 {
00353     PR_Lock(((RName *)handle)->lock);
00354     ((RName *)handle)->counter++;
00355     PR_Unlock(((RName *)handle)->lock);
00356 
00357     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld", 
00358         handle, ((RName *)handle)->counter ));
00359 
00360     return;
00361 } /*  end PR_IncrementCounter() */
00362 
00363 
00364 
00365 /*
00366 **
00367 */
00368 PR_IMPLEMENT(void) 
00369        PR_DecrementCounter( 
00370               PRCounterHandle handle
00371 )
00372 {
00373     PR_Lock(((RName *)handle)->lock);
00374     ((RName *)handle)->counter--;
00375     PR_Unlock(((RName *)handle)->lock);
00376 
00377     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld", 
00378         handle, ((RName *)handle)->counter ));
00379 
00380     return;
00381 } /*  end PR_DecrementCounter()  */
00382 
00383 
00384 /*
00385 **
00386 */
00387 PR_IMPLEMENT(void) 
00388        PR_AddToCounter( 
00389        PRCounterHandle handle, 
00390            PRUint32 value 
00391 )
00392 {
00393     PR_Lock(((RName *)handle)->lock);
00394     ((RName *)handle)->counter += value;
00395     PR_Unlock(((RName *)handle)->lock);
00396 
00397     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld", 
00398         handle, ((RName *)handle)->counter ));
00399 
00400     return;
00401 } /*  end PR_AddToCounter() */
00402 
00403 
00404 /*
00405 **
00406 */
00407 PR_IMPLEMENT(void) 
00408        PR_SubtractFromCounter( 
00409        PRCounterHandle handle, 
00410            PRUint32 value 
00411 )
00412 {
00413     PR_Lock(((RName *)handle)->lock);
00414     ((RName *)handle)->counter -= value;
00415     PR_Unlock(((RName *)handle)->lock);
00416     
00417     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld", 
00418         handle, ((RName *)handle)->counter ));
00419 
00420     return;
00421 } /*  end  PR_SubtractFromCounter() */
00422 
00423 /*
00424 **
00425 */
00426 PR_IMPLEMENT(PRUint32) 
00427        PR_GetCounter( 
00428               PRCounterHandle handle 
00429 )
00430 {
00431     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld", 
00432         handle, ((RName *)handle)->counter ));
00433 
00434     return(((RName *)handle)->counter);
00435 } /*  end  PR_GetCounter() */
00436 
00437 /*
00438 **
00439 */
00440 PR_IMPLEMENT(void) 
00441        PR_SetCounter( 
00442               PRCounterHandle handle, 
00443               PRUint32 value 
00444 )
00445 {
00446     ((RName *)handle)->counter = value;
00447 
00448     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld", 
00449         handle, ((RName *)handle)->counter ));
00450 
00451     return;
00452 } /*  end  PR_SetCounter() */
00453 
00454 /*
00455 **
00456 */
00457 PR_IMPLEMENT(PRCounterHandle) 
00458        PR_FindNextCounterQname( 
00459         PRCounterHandle handle
00460 )
00461 {
00462     QName *qnp = (QName *)handle;
00463 
00464     if ( PR_CLIST_IS_EMPTY( &qNameList ))
00465             qnp = NULL;
00466     else if ( qnp == NULL )
00467         qnp = (QName *)PR_LIST_HEAD( &qNameList );
00468     else if ( PR_NEXT_LINK( &qnp->link ) ==  &qNameList )
00469         qnp = NULL;
00470     else  
00471         qnp = (QName *)PR_NEXT_LINK( &qnp->link );
00472 
00473     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", 
00474         handle, qnp ));
00475 
00476     return((PRCounterHandle)qnp);
00477 } /*  end  PR_FindNextCounterQname() */
00478 
00479 
00480 /*
00481 **
00482 */
00483 PR_IMPLEMENT(PRCounterHandle) 
00484        PR_FindNextCounterRname( 
00485         PRCounterHandle rhandle, 
00486         PRCounterHandle qhandle 
00487 )
00488 {
00489     RName *rnp = (RName *)rhandle;
00490     QName *qnp = (QName *)qhandle;
00491 
00492 
00493     if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ))
00494         rnp = NULL;
00495     else if ( rnp == NULL )
00496         rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList );
00497     else if ( PR_NEXT_LINK( &rnp->link ) ==  &qnp->rNameList )
00498         rnp = NULL;
00499     else
00500         rnp = (RName *)PR_NEXT_LINK( &rnp->link );
00501 
00502     PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 
00503         rhandle, qhandle, rnp ));
00504 
00505     return((PRCounterHandle)rnp);
00506 } /*  end PR_FindNextCounterRname() */