prcountr.c (10624B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 ** prcountr.c -- NSPR Instrumentation Counters 8 ** 9 ** Implement the interface defined in prcountr.h 10 ** 11 ** Design Notes: 12 ** 13 ** The Counter Facility (CF) has a single anchor: qNameList. 14 ** The anchor is a PRCList. qNameList is a list of links in QName 15 ** structures. From qNameList any QName structure and its 16 ** associated RName structure can be located. 17 ** 18 ** For each QName, a list of RName structures is anchored at 19 ** rnLink in the QName structure. 20 ** 21 ** The counter itself is embedded in the RName structure. 22 ** 23 ** For manipulating the counter database, single lock is used to 24 ** protect the entire list: counterLock. 25 ** 26 ** A PRCounterHandle, defined in prcountr.h, is really a pointer 27 ** to a RName structure. References by PRCounterHandle are 28 ** dead-reconed to the RName structure. The PRCounterHandle is 29 ** "overloaded" for traversing the QName structures; only the 30 ** function PR_FindNextQnameHandle() uses this overloading. 31 ** 32 ** 33 ** ToDo (lth): decide on how to lock or atomically update 34 ** individual counters. Candidates are: the global lock; a lock 35 ** per RName structure; Atomic operations (Note that there are 36 ** not adaquate atomic operations (yet) to achieve this goal). At 37 ** this writing (6/19/98) , the update of the counter variable in 38 ** a QName structure is unprotected. 39 ** 40 */ 41 42 #include "prcountr.h" 43 #include "prclist.h" 44 #include "prlock.h" 45 #include "prlog.h" 46 #include "prmem.h" 47 #include <string.h> 48 49 /* 50 ** 51 */ 52 typedef struct QName { 53 PRCList link; 54 PRCList rNameList; 55 char name[PRCOUNTER_NAME_MAX + 1]; 56 } QName; 57 58 /* 59 ** 60 */ 61 typedef struct RName { 62 PRCList link; 63 QName* qName; 64 PRLock* lock; 65 volatile PRUint32 counter; 66 char name[PRCOUNTER_NAME_MAX + 1]; 67 char desc[PRCOUNTER_DESC_MAX + 1]; 68 } RName; 69 70 /* 71 ** Define the Counter Facility database 72 */ 73 static PRLock* counterLock; 74 static PRCList qNameList; 75 static PRLogModuleInfo* lm; 76 77 /* 78 ** _PR_CounterInitialize() -- Initialize the Counter Facility 79 ** 80 */ 81 static void _PR_CounterInitialize(void) { 82 /* 83 ** This function should be called only once 84 */ 85 PR_ASSERT(counterLock == NULL); 86 87 counterLock = PR_NewLock(); 88 PR_INIT_CLIST(&qNameList); 89 lm = PR_NewLogModule("counters"); 90 PR_LOG(lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete")); 91 92 return; 93 } /* end _PR_CounterInitialize() */ 94 95 /* 96 ** PR_CreateCounter() -- Create a counter 97 ** 98 ** ValidateArguments 99 ** Lock 100 ** if (qName not already in database) 101 ** NewQname 102 ** if (rName already in database ) 103 ** Assert 104 ** else NewRname 105 ** NewCounter 106 ** link 'em up 107 ** Unlock 108 ** 109 */ 110 PR_IMPLEMENT(PRCounterHandle) 111 PR_CreateCounter(const char* qName, const char* rName, 112 const char* description) { 113 QName* qnp; 114 RName* rnp; 115 PRBool matchQname = PR_FALSE; 116 117 /* Self initialize, if necessary */ 118 if (counterLock == NULL) { 119 _PR_CounterInitialize(); 120 } 121 122 /* Validate input arguments */ 123 PR_ASSERT(strlen(qName) <= PRCOUNTER_NAME_MAX); 124 PR_ASSERT(strlen(rName) <= PRCOUNTER_NAME_MAX); 125 PR_ASSERT(strlen(description) <= PRCOUNTER_DESC_MAX); 126 127 /* Lock the Facility */ 128 PR_Lock(counterLock); 129 130 /* Do we already have a matching QName? */ 131 if (!PR_CLIST_IS_EMPTY(&qNameList)) { 132 qnp = (QName*)PR_LIST_HEAD(&qNameList); 133 do { 134 if (strcmp(qnp->name, qName) == 0) { 135 matchQname = PR_TRUE; 136 break; 137 } 138 qnp = (QName*)PR_NEXT_LINK(&qnp->link); 139 } while (qnp != (QName*)&qNameList); 140 } 141 /* 142 ** If we did not find a matching QName, 143 ** allocate one and initialize it. 144 ** link it onto the qNameList. 145 ** 146 */ 147 if (matchQname != PR_TRUE) { 148 qnp = PR_NEWZAP(QName); 149 PR_ASSERT(qnp != NULL); 150 PR_INIT_CLIST(&qnp->link); 151 PR_INIT_CLIST(&qnp->rNameList); 152 strcpy(qnp->name, qName); 153 PR_APPEND_LINK(&qnp->link, &qNameList); 154 } 155 156 /* Do we already have a matching RName? */ 157 if (!PR_CLIST_IS_EMPTY(&qnp->rNameList)) { 158 rnp = (RName*)PR_LIST_HEAD(&qnp->rNameList); 159 do { 160 /* 161 ** No duplicate RNames are allowed within a QName 162 ** 163 */ 164 PR_ASSERT(strcmp(rnp->name, rName)); 165 rnp = (RName*)PR_NEXT_LINK(&rnp->link); 166 } while (rnp != (RName*)&qnp->rNameList); 167 } 168 169 /* Get a new RName structure; initialize its members */ 170 rnp = PR_NEWZAP(RName); 171 PR_ASSERT(rnp != NULL); 172 PR_INIT_CLIST(&rnp->link); 173 strcpy(rnp->name, rName); 174 strcpy(rnp->desc, description); 175 rnp->lock = PR_NewLock(); 176 if (rnp->lock == NULL) { 177 PR_ASSERT(0); 178 } 179 180 PR_APPEND_LINK(&rnp->link, &qnp->rNameList); /* add RName to QName's rnList */ 181 rnp->qName = qnp; /* point the RName to the QName */ 182 183 /* Unlock the Facility */ 184 PR_Unlock(counterLock); 185 PR_LOG(lm, PR_LOG_DEBUG, 186 ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t", qName, qnp, 187 rName, rnp)); 188 189 return ((PRCounterHandle)rnp); 190 } /* end PR_CreateCounter() */ 191 192 /* 193 ** 194 */ 195 PR_IMPLEMENT(void) 196 PR_DestroyCounter(PRCounterHandle handle) { 197 RName* rnp = (RName*)handle; 198 QName* qnp = rnp->qName; 199 200 PR_LOG(lm, PR_LOG_DEBUG, 201 ("PR_Counter: Deleting: QName: %s, RName: %s", qnp->name, rnp->name)); 202 203 /* Lock the Facility */ 204 PR_Lock(counterLock); 205 206 /* 207 ** Remove RName from the list of RNames in QName 208 ** and free RName 209 */ 210 PR_LOG(lm, PR_LOG_DEBUG, 211 ("PR_Counter: Deleting RName: %s, %p", rnp->name, rnp)); 212 PR_REMOVE_LINK(&rnp->link); 213 PR_Free(rnp->lock); 214 PR_DELETE(rnp); 215 216 /* 217 ** If this is the last RName within QName 218 ** remove QName from the qNameList and free it 219 */ 220 if (PR_CLIST_IS_EMPTY(&qnp->rNameList)) { 221 PR_LOG(lm, PR_LOG_DEBUG, 222 ("PR_Counter: Deleting unused QName: %s, %p", qnp->name, qnp)); 223 PR_REMOVE_LINK(&qnp->link); 224 PR_DELETE(qnp); 225 } 226 227 /* Unlock the Facility */ 228 PR_Unlock(counterLock); 229 return; 230 } /* end PR_DestroyCounter() */ 231 232 /* 233 ** 234 */ 235 PR_IMPLEMENT(PRCounterHandle) 236 PR_GetCounterHandleFromName(const char* qName, const char* rName) { 237 const char *qn, *rn, *desc; 238 PRCounterHandle qh, rh = NULL; 239 RName* rnp = NULL; 240 241 PR_LOG(lm, PR_LOG_DEBUG, 242 ("PR_Counter: GetCounterHandleFromName:\n\t" 243 "QName: %s, RName: %s", 244 qName, rName)); 245 246 qh = PR_FindNextCounterQname(NULL); 247 while (qh != NULL) { 248 rh = PR_FindNextCounterRname(NULL, qh); 249 while (rh != NULL) { 250 PR_GetCounterNameFromHandle(rh, &qn, &rn, &desc); 251 if ((strcmp(qName, qn) == 0) && (strcmp(rName, rn) == 0)) { 252 rnp = (RName*)rh; 253 goto foundIt; 254 } 255 rh = PR_FindNextCounterRname(rh, qh); 256 } 257 qh = PR_FindNextCounterQname(NULL); 258 } 259 260 foundIt: 261 PR_LOG(lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp)); 262 return (rh); 263 } /* end PR_GetCounterHandleFromName() */ 264 265 /* 266 ** 267 */ 268 PR_IMPLEMENT(void) 269 PR_GetCounterNameFromHandle(PRCounterHandle handle, const char** qName, 270 const char** rName, const char** description) { 271 RName* rnp = (RName*)handle; 272 QName* qnp = rnp->qName; 273 274 *qName = qnp->name; 275 *rName = rnp->name; 276 *description = rnp->desc; 277 278 PR_LOG(lm, PR_LOG_DEBUG, 279 ("PR_Counter: GetConterNameFromHandle: " 280 "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 281 qnp, rnp, qnp->name, rnp->name, rnp->desc)); 282 283 return; 284 } /* end PR_GetCounterNameFromHandle() */ 285 286 /* 287 ** 288 */ 289 PR_IMPLEMENT(void) 290 PR_IncrementCounter(PRCounterHandle handle) { 291 PR_Lock(((RName*)handle)->lock); 292 ((RName*)handle)->counter++; 293 PR_Unlock(((RName*)handle)->lock); 294 295 PR_LOG(lm, PR_LOG_DEBUG, 296 ("PR_Counter: Increment: %p, %ld", handle, ((RName*)handle)->counter)); 297 298 return; 299 } /* end PR_IncrementCounter() */ 300 301 /* 302 ** 303 */ 304 PR_IMPLEMENT(void) 305 PR_DecrementCounter(PRCounterHandle handle) { 306 PR_Lock(((RName*)handle)->lock); 307 ((RName*)handle)->counter--; 308 PR_Unlock(((RName*)handle)->lock); 309 310 PR_LOG(lm, PR_LOG_DEBUG, 311 ("PR_Counter: Decrement: %p, %ld", handle, ((RName*)handle)->counter)); 312 313 return; 314 } /* end PR_DecrementCounter() */ 315 316 /* 317 ** 318 */ 319 PR_IMPLEMENT(void) 320 PR_AddToCounter(PRCounterHandle handle, PRUint32 value) { 321 PR_Lock(((RName*)handle)->lock); 322 ((RName*)handle)->counter += value; 323 PR_Unlock(((RName*)handle)->lock); 324 325 PR_LOG( 326 lm, PR_LOG_DEBUG, 327 ("PR_Counter: AddToCounter: %p, %ld", handle, ((RName*)handle)->counter)); 328 329 return; 330 } /* end PR_AddToCounter() */ 331 332 /* 333 ** 334 */ 335 PR_IMPLEMENT(void) 336 PR_SubtractFromCounter(PRCounterHandle handle, PRUint32 value) { 337 PR_Lock(((RName*)handle)->lock); 338 ((RName*)handle)->counter -= value; 339 PR_Unlock(((RName*)handle)->lock); 340 341 PR_LOG(lm, PR_LOG_DEBUG, 342 ("PR_Counter: SubtractFromCounter: %p, %ld", handle, 343 ((RName*)handle)->counter)); 344 345 return; 346 } /* end PR_SubtractFromCounter() */ 347 348 /* 349 ** 350 */ 351 PR_IMPLEMENT(PRUint32) 352 PR_GetCounter(PRCounterHandle handle) { 353 PR_LOG( 354 lm, PR_LOG_DEBUG, 355 ("PR_Counter: GetCounter: %p, %ld", handle, ((RName*)handle)->counter)); 356 357 return (((RName*)handle)->counter); 358 } /* end PR_GetCounter() */ 359 360 /* 361 ** 362 */ 363 PR_IMPLEMENT(void) 364 PR_SetCounter(PRCounterHandle handle, PRUint32 value) { 365 ((RName*)handle)->counter = value; 366 367 PR_LOG( 368 lm, PR_LOG_DEBUG, 369 ("PR_Counter: SetCounter: %p, %ld", handle, ((RName*)handle)->counter)); 370 371 return; 372 } /* end PR_SetCounter() */ 373 374 /* 375 ** 376 */ 377 PR_IMPLEMENT(PRCounterHandle) 378 PR_FindNextCounterQname(PRCounterHandle handle) { 379 QName* qnp = (QName*)handle; 380 381 if (PR_CLIST_IS_EMPTY(&qNameList)) { 382 qnp = NULL; 383 } else if (qnp == NULL) { 384 qnp = (QName*)PR_LIST_HEAD(&qNameList); 385 } else if (PR_NEXT_LINK(&qnp->link) == &qNameList) { 386 qnp = NULL; 387 } else { 388 qnp = (QName*)PR_NEXT_LINK(&qnp->link); 389 } 390 391 PR_LOG(lm, PR_LOG_DEBUG, 392 ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", handle, qnp)); 393 394 return ((PRCounterHandle)qnp); 395 } /* end PR_FindNextCounterQname() */ 396 397 /* 398 ** 399 */ 400 PR_IMPLEMENT(PRCounterHandle) 401 PR_FindNextCounterRname(PRCounterHandle rhandle, PRCounterHandle qhandle) { 402 RName* rnp = (RName*)rhandle; 403 QName* qnp = (QName*)qhandle; 404 405 if (PR_CLIST_IS_EMPTY(&qnp->rNameList)) { 406 rnp = NULL; 407 } else if (rnp == NULL) { 408 rnp = (RName*)PR_LIST_HEAD(&qnp->rNameList); 409 } else if (PR_NEXT_LINK(&rnp->link) == &qnp->rNameList) { 410 rnp = NULL; 411 } else { 412 rnp = (RName*)PR_NEXT_LINK(&rnp->link); 413 } 414 415 PR_LOG(lm, PR_LOG_DEBUG, 416 ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 417 rhandle, qhandle, rnp)); 418 419 return ((PRCounterHandle)rnp); 420 } /* end PR_FindNextCounterRname() */