tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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() */