1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/misc/prcountr.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,474 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** prcountr.c -- NSPR Instrumentation Counters 1.11 +** 1.12 +** Implement the interface defined in prcountr.h 1.13 +** 1.14 +** Design Notes: 1.15 +** 1.16 +** The Counter Facility (CF) has a single anchor: qNameList. 1.17 +** The anchor is a PRCList. qNameList is a list of links in QName 1.18 +** structures. From qNameList any QName structure and its 1.19 +** associated RName structure can be located. 1.20 +** 1.21 +** For each QName, a list of RName structures is anchored at 1.22 +** rnLink in the QName structure. 1.23 +** 1.24 +** The counter itself is embedded in the RName structure. 1.25 +** 1.26 +** For manipulating the counter database, single lock is used to 1.27 +** protect the entire list: counterLock. 1.28 +** 1.29 +** A PRCounterHandle, defined in prcountr.h, is really a pointer 1.30 +** to a RName structure. References by PRCounterHandle are 1.31 +** dead-reconed to the RName structure. The PRCounterHandle is 1.32 +** "overloaded" for traversing the QName structures; only the 1.33 +** function PR_FindNextQnameHandle() uses this overloading. 1.34 +** 1.35 +** 1.36 +** ToDo (lth): decide on how to lock or atomically update 1.37 +** individual counters. Candidates are: the global lock; a lock 1.38 +** per RName structure; Atomic operations (Note that there are 1.39 +** not adaquate atomic operations (yet) to achieve this goal). At 1.40 +** this writing (6/19/98) , the update of the counter variable in 1.41 +** a QName structure is unprotected. 1.42 +** 1.43 +*/ 1.44 + 1.45 +#include "prcountr.h" 1.46 +#include "prclist.h" 1.47 +#include "prlock.h" 1.48 +#include "prlog.h" 1.49 +#include "prmem.h" 1.50 +#include <string.h> 1.51 + 1.52 +/* 1.53 +** 1.54 +*/ 1.55 +typedef struct QName 1.56 +{ 1.57 + PRCList link; 1.58 + PRCList rNameList; 1.59 + char name[PRCOUNTER_NAME_MAX+1]; 1.60 +} QName; 1.61 + 1.62 +/* 1.63 +** 1.64 +*/ 1.65 +typedef struct RName 1.66 +{ 1.67 + PRCList link; 1.68 + QName *qName; 1.69 + PRLock *lock; 1.70 + volatile PRUint32 counter; 1.71 + char name[PRCOUNTER_NAME_MAX+1]; 1.72 + char desc[PRCOUNTER_DESC_MAX+1]; 1.73 +} RName; 1.74 + 1.75 + 1.76 +/* 1.77 +** Define the Counter Facility database 1.78 +*/ 1.79 +static PRLock *counterLock; 1.80 +static PRCList qNameList; 1.81 +static PRLogModuleInfo *lm; 1.82 + 1.83 +/* 1.84 +** _PR_CounterInitialize() -- Initialize the Counter Facility 1.85 +** 1.86 +*/ 1.87 +static void _PR_CounterInitialize( void ) 1.88 +{ 1.89 + /* 1.90 + ** This function should be called only once 1.91 + */ 1.92 + PR_ASSERT( counterLock == NULL ); 1.93 + 1.94 + counterLock = PR_NewLock(); 1.95 + PR_INIT_CLIST( &qNameList ); 1.96 + lm = PR_NewLogModule("counters"); 1.97 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete")); 1.98 + 1.99 + return; 1.100 +} /* end _PR_CounterInitialize() */ 1.101 + 1.102 +/* 1.103 +** PR_CreateCounter() -- Create a counter 1.104 +** 1.105 +** ValidateArguments 1.106 +** Lock 1.107 +** if (qName not already in database) 1.108 +** NewQname 1.109 +** if (rName already in database ) 1.110 +** Assert 1.111 +** else NewRname 1.112 +** NewCounter 1.113 +** link 'em up 1.114 +** Unlock 1.115 +** 1.116 +*/ 1.117 +PR_IMPLEMENT(PRCounterHandle) 1.118 + PR_CreateCounter( 1.119 + const char *qName, 1.120 + const char *rName, 1.121 + const char *description 1.122 +) 1.123 +{ 1.124 + QName *qnp; 1.125 + RName *rnp; 1.126 + PRBool matchQname = PR_FALSE; 1.127 + 1.128 + /* Self initialize, if necessary */ 1.129 + if ( counterLock == NULL ) 1.130 + _PR_CounterInitialize(); 1.131 + 1.132 + /* Validate input arguments */ 1.133 + PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX ); 1.134 + PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX ); 1.135 + PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX ); 1.136 + 1.137 + /* Lock the Facility */ 1.138 + PR_Lock( counterLock ); 1.139 + 1.140 + /* Do we already have a matching QName? */ 1.141 + if (!PR_CLIST_IS_EMPTY( &qNameList )) 1.142 + { 1.143 + qnp = (QName *) PR_LIST_HEAD( &qNameList ); 1.144 + do { 1.145 + if ( strcmp(qnp->name, qName) == 0) 1.146 + { 1.147 + matchQname = PR_TRUE; 1.148 + break; 1.149 + } 1.150 + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); 1.151 + } while( qnp != (QName *)&qNameList ); 1.152 + } 1.153 + /* 1.154 + ** If we did not find a matching QName, 1.155 + ** allocate one and initialize it. 1.156 + ** link it onto the qNameList. 1.157 + ** 1.158 + */ 1.159 + if ( matchQname != PR_TRUE ) 1.160 + { 1.161 + qnp = PR_NEWZAP( QName ); 1.162 + PR_ASSERT( qnp != NULL ); 1.163 + PR_INIT_CLIST( &qnp->link ); 1.164 + PR_INIT_CLIST( &qnp->rNameList ); 1.165 + strcpy( qnp->name, qName ); 1.166 + PR_APPEND_LINK( &qnp->link, &qNameList ); 1.167 + } 1.168 + 1.169 + /* Do we already have a matching RName? */ 1.170 + if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) 1.171 + { 1.172 + rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); 1.173 + do { 1.174 + /* 1.175 + ** No duplicate RNames are allowed within a QName 1.176 + ** 1.177 + */ 1.178 + PR_ASSERT( strcmp(rnp->name, rName)); 1.179 + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); 1.180 + } while( rnp != (RName *)&qnp->rNameList ); 1.181 + } 1.182 + 1.183 + /* Get a new RName structure; initialize its members */ 1.184 + rnp = PR_NEWZAP( RName ); 1.185 + PR_ASSERT( rnp != NULL ); 1.186 + PR_INIT_CLIST( &rnp->link ); 1.187 + strcpy( rnp->name, rName ); 1.188 + strcpy( rnp->desc, description ); 1.189 + rnp->lock = PR_NewLock(); 1.190 + if ( rnp->lock == NULL ) 1.191 + { 1.192 + PR_ASSERT(0); 1.193 + } 1.194 + 1.195 + PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ 1.196 + rnp->qName = qnp; /* point the RName to the QName */ 1.197 + 1.198 + /* Unlock the Facility */ 1.199 + PR_Unlock( counterLock ); 1.200 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t", 1.201 + qName, qnp, rName, rnp )); 1.202 + 1.203 + return((PRCounterHandle)rnp); 1.204 +} /* end PR_CreateCounter() */ 1.205 + 1.206 + 1.207 +/* 1.208 +** 1.209 +*/ 1.210 +PR_IMPLEMENT(void) 1.211 + PR_DestroyCounter( 1.212 + PRCounterHandle handle 1.213 +) 1.214 +{ 1.215 + RName *rnp = (RName *)handle; 1.216 + QName *qnp = rnp->qName; 1.217 + 1.218 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s", 1.219 + qnp->name, rnp->name)); 1.220 + 1.221 + /* Lock the Facility */ 1.222 + PR_Lock( counterLock ); 1.223 + 1.224 + /* 1.225 + ** Remove RName from the list of RNames in QName 1.226 + ** and free RName 1.227 + */ 1.228 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting RName: %s, %p", 1.229 + rnp->name, rnp)); 1.230 + PR_REMOVE_LINK( &rnp->link ); 1.231 + PR_Free( rnp->lock ); 1.232 + PR_DELETE( rnp ); 1.233 + 1.234 + /* 1.235 + ** If this is the last RName within QName 1.236 + ** remove QName from the qNameList and free it 1.237 + */ 1.238 + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) 1.239 + { 1.240 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting unused QName: %s, %p", 1.241 + qnp->name, qnp)); 1.242 + PR_REMOVE_LINK( &qnp->link ); 1.243 + PR_DELETE( qnp ); 1.244 + } 1.245 + 1.246 + /* Unlock the Facility */ 1.247 + PR_Unlock( counterLock ); 1.248 + return; 1.249 +} /* end PR_DestroyCounter() */ 1.250 + 1.251 +/* 1.252 +** 1.253 +*/ 1.254 +PR_IMPLEMENT(PRCounterHandle) 1.255 + PR_GetCounterHandleFromName( 1.256 + const char *qName, 1.257 + const char *rName 1.258 +) 1.259 +{ 1.260 + const char *qn, *rn, *desc; 1.261 + PRCounterHandle qh, rh = NULL; 1.262 + RName *rnp = NULL; 1.263 + 1.264 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t" 1.265 + "QName: %s, RName: %s", qName, rName )); 1.266 + 1.267 + qh = PR_FindNextCounterQname( NULL ); 1.268 + while (qh != NULL) 1.269 + { 1.270 + rh = PR_FindNextCounterRname( NULL, qh ); 1.271 + while ( rh != NULL ) 1.272 + { 1.273 + PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc ); 1.274 + if ( (strcmp( qName, qn ) == 0) 1.275 + && (strcmp( rName, rn ) == 0 )) 1.276 + { 1.277 + rnp = (RName *)rh; 1.278 + goto foundIt; 1.279 + } 1.280 + rh = PR_FindNextCounterRname( rh, qh ); 1.281 + } 1.282 + qh = PR_FindNextCounterQname( NULL ); 1.283 + } 1.284 + 1.285 +foundIt: 1.286 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); 1.287 + return(rh); 1.288 +} /* end PR_GetCounterHandleFromName() */ 1.289 + 1.290 +/* 1.291 +** 1.292 +*/ 1.293 +PR_IMPLEMENT(void) 1.294 + PR_GetCounterNameFromHandle( 1.295 + PRCounterHandle handle, 1.296 + const char **qName, 1.297 + const char **rName, 1.298 + const char **description 1.299 +) 1.300 +{ 1.301 + RName *rnp = (RName *)handle; 1.302 + QName *qnp = rnp->qName; 1.303 + 1.304 + *qName = qnp->name; 1.305 + *rName = rnp->name; 1.306 + *description = rnp->desc; 1.307 + 1.308 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterNameFromHandle: " 1.309 + "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 1.310 + qnp, rnp, qnp->name, rnp->name, rnp->desc )); 1.311 + 1.312 + return; 1.313 +} /* end PR_GetCounterNameFromHandle() */ 1.314 + 1.315 + 1.316 +/* 1.317 +** 1.318 +*/ 1.319 +PR_IMPLEMENT(void) 1.320 + PR_IncrementCounter( 1.321 + PRCounterHandle handle 1.322 +) 1.323 +{ 1.324 + PR_Lock(((RName *)handle)->lock); 1.325 + ((RName *)handle)->counter++; 1.326 + PR_Unlock(((RName *)handle)->lock); 1.327 + 1.328 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld", 1.329 + handle, ((RName *)handle)->counter )); 1.330 + 1.331 + return; 1.332 +} /* end PR_IncrementCounter() */ 1.333 + 1.334 + 1.335 + 1.336 +/* 1.337 +** 1.338 +*/ 1.339 +PR_IMPLEMENT(void) 1.340 + PR_DecrementCounter( 1.341 + PRCounterHandle handle 1.342 +) 1.343 +{ 1.344 + PR_Lock(((RName *)handle)->lock); 1.345 + ((RName *)handle)->counter--; 1.346 + PR_Unlock(((RName *)handle)->lock); 1.347 + 1.348 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld", 1.349 + handle, ((RName *)handle)->counter )); 1.350 + 1.351 + return; 1.352 +} /* end PR_DecrementCounter() */ 1.353 + 1.354 + 1.355 +/* 1.356 +** 1.357 +*/ 1.358 +PR_IMPLEMENT(void) 1.359 + PR_AddToCounter( 1.360 + PRCounterHandle handle, 1.361 + PRUint32 value 1.362 +) 1.363 +{ 1.364 + PR_Lock(((RName *)handle)->lock); 1.365 + ((RName *)handle)->counter += value; 1.366 + PR_Unlock(((RName *)handle)->lock); 1.367 + 1.368 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld", 1.369 + handle, ((RName *)handle)->counter )); 1.370 + 1.371 + return; 1.372 +} /* end PR_AddToCounter() */ 1.373 + 1.374 + 1.375 +/* 1.376 +** 1.377 +*/ 1.378 +PR_IMPLEMENT(void) 1.379 + PR_SubtractFromCounter( 1.380 + PRCounterHandle handle, 1.381 + PRUint32 value 1.382 +) 1.383 +{ 1.384 + PR_Lock(((RName *)handle)->lock); 1.385 + ((RName *)handle)->counter -= value; 1.386 + PR_Unlock(((RName *)handle)->lock); 1.387 + 1.388 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld", 1.389 + handle, ((RName *)handle)->counter )); 1.390 + 1.391 + return; 1.392 +} /* end PR_SubtractFromCounter() */ 1.393 + 1.394 +/* 1.395 +** 1.396 +*/ 1.397 +PR_IMPLEMENT(PRUint32) 1.398 + PR_GetCounter( 1.399 + PRCounterHandle handle 1.400 +) 1.401 +{ 1.402 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld", 1.403 + handle, ((RName *)handle)->counter )); 1.404 + 1.405 + return(((RName *)handle)->counter); 1.406 +} /* end PR_GetCounter() */ 1.407 + 1.408 +/* 1.409 +** 1.410 +*/ 1.411 +PR_IMPLEMENT(void) 1.412 + PR_SetCounter( 1.413 + PRCounterHandle handle, 1.414 + PRUint32 value 1.415 +) 1.416 +{ 1.417 + ((RName *)handle)->counter = value; 1.418 + 1.419 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld", 1.420 + handle, ((RName *)handle)->counter )); 1.421 + 1.422 + return; 1.423 +} /* end PR_SetCounter() */ 1.424 + 1.425 +/* 1.426 +** 1.427 +*/ 1.428 +PR_IMPLEMENT(PRCounterHandle) 1.429 + PR_FindNextCounterQname( 1.430 + PRCounterHandle handle 1.431 +) 1.432 +{ 1.433 + QName *qnp = (QName *)handle; 1.434 + 1.435 + if ( PR_CLIST_IS_EMPTY( &qNameList )) 1.436 + qnp = NULL; 1.437 + else if ( qnp == NULL ) 1.438 + qnp = (QName *)PR_LIST_HEAD( &qNameList ); 1.439 + else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) 1.440 + qnp = NULL; 1.441 + else 1.442 + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); 1.443 + 1.444 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", 1.445 + handle, qnp )); 1.446 + 1.447 + return((PRCounterHandle)qnp); 1.448 +} /* end PR_FindNextCounterQname() */ 1.449 + 1.450 + 1.451 +/* 1.452 +** 1.453 +*/ 1.454 +PR_IMPLEMENT(PRCounterHandle) 1.455 + PR_FindNextCounterRname( 1.456 + PRCounterHandle rhandle, 1.457 + PRCounterHandle qhandle 1.458 +) 1.459 +{ 1.460 + RName *rnp = (RName *)rhandle; 1.461 + QName *qnp = (QName *)qhandle; 1.462 + 1.463 + 1.464 + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) 1.465 + rnp = NULL; 1.466 + else if ( rnp == NULL ) 1.467 + rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); 1.468 + else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) 1.469 + rnp = NULL; 1.470 + else 1.471 + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); 1.472 + 1.473 + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 1.474 + rhandle, qhandle, rnp )); 1.475 + 1.476 + return((PRCounterHandle)rnp); 1.477 +} /* end PR_FindNextCounterRname() */