• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • Directories
  • File List
  • Globals

counters.c

Go to the documentation of this file.
00001 /* 
00002  * Copyright (C) 2010 iptelorg GmbH
00003  *
00004  * Permission to use, copy, modify, and distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00023 /*
00024  * History:
00025  * --------
00026  *  2010-08-06  initial version (andrei)
00027  *  2010-08-24  counters can be used (inc,add) before prefork_init (andrei)
00028 */
00029 
00030 #include "counters.h"
00031 #include "str_hash.h"
00032 #include "str.h"
00033 #include "compiler_opt.h"
00034 #include "mem/mem.h"
00035 #include "mem/shm_mem.h"
00036 
00037 
00038 #define CNT_HASH_SIZE   64
00039 /* group hash size (rpc use) */
00040 #define GRP_HASH_SIZE   16
00041 /* initial sorted groups array size (rpc use) */
00042 #define GRP_SORTED_SIZE 16
00043 /* intial counter id 2 record array size */
00044 #define CNT_ID2RECORD_SIZE      64
00045 
00046 #define CACHELINE_PAD 128
00047 
00048 
00049 
00050 /* leave space for one flag */
00051 #define MAX_COUNTER_ID 32767
00052 /* size (number of entries) of the temporary array used for keeping stats
00053    pre-prefork init.  Note: if more counters are registered then this size,
00054    the array will be dynamically increased (doubled each time). The value
00055    here is meant only to optimize startup/memory fragmentation. */
00056 #define PREINIT_CNTS_VALS_SIZE 128
00057 
00058 struct counter_record {
00059         str group;
00060         str name;
00061         counter_handle_t h;
00062         unsigned short flags;
00063         void* cbk_param;
00064         counter_cbk_f cbk;
00065         struct counter_record* grp_next; /* next in group */
00066         str doc;
00067 };
00068 
00069 
00070 struct grp_record {
00071         str group;
00072         struct counter_record* first;
00073 };
00074 
00075 
00076 
00078 static struct str_hash_table cnts_hash_table;
00080 struct counter_record** cnt_id2record;
00081 static int cnt_id2record_size;
00083 static struct str_hash_table grp_hash_table;
00085 static struct grp_record** grp_sorted;
00086 static int grp_sorted_max_size;
00087 static int grp_sorted_crt_size;
00088 static int grp_no; /* number of groups */
00089 
00092 counter_array_t* _cnts_vals;
00093 int _cnts_row_len; /* number of elements per row */
00094 static int cnts_no; /* number of registered counters */
00095 static int cnts_max_rows; /* set to 0 if not yet fully init */
00096 
00097 
00098 
00102 int init_counters()
00103 {
00104         if (str_hash_alloc(&cnts_hash_table, CNT_HASH_SIZE) < 0)
00105                 goto error;
00106         str_hash_init(&cnts_hash_table);
00107         if (str_hash_alloc(&grp_hash_table, GRP_HASH_SIZE) < 0)
00108                 goto error;
00109         str_hash_init(&grp_hash_table);
00110         cnts_no = 1; /* start at 1 (0 used only for invalid counters) */
00111         cnts_max_rows = 0; /* 0 initially, !=0 after full init
00112                                                   (counters_prefork_init()) */
00113         grp_no = 0;
00114         cnt_id2record_size = CNT_ID2RECORD_SIZE;
00115         cnt_id2record = pkg_malloc(sizeof(*cnt_id2record) * cnt_id2record_size);
00116         if (cnt_id2record == 0)
00117                 goto error;
00118         memset(cnt_id2record, 0, sizeof(*cnt_id2record) * cnt_id2record_size);
00119         grp_sorted_max_size = GRP_SORTED_SIZE;
00120         grp_sorted_crt_size = 0;
00121         grp_sorted = pkg_malloc(sizeof(*grp_sorted) * grp_sorted_max_size);
00122         if (grp_sorted == 0)
00123                 goto error;
00124         memset(grp_sorted, 0, sizeof(*grp_sorted) * grp_sorted_max_size);
00125         return 0;
00126 error:
00127         destroy_counters();
00128         return -1;
00129 }
00130 
00131 
00132 
00133 void destroy_counters()
00134 {
00135         int r;
00136         struct str_hash_entry* e;
00137         struct str_hash_entry* bak;
00138         if (_cnts_vals) {
00139                 if (cnts_max_rows)
00140                         /* fully init => it is in shm */
00141                         shm_free(_cnts_vals);
00142                 else
00143                         /* partially init (before prefork) => pkg */
00144                         pkg_free(_cnts_vals);
00145                 _cnts_vals = 0;
00146         }
00147         if (cnts_hash_table.table) {
00148                 for (r=0; r< cnts_hash_table.size; r++) {
00149                         clist_foreach_safe(&cnts_hash_table.table[r], e, bak, next) {
00150                                 pkg_free(e);
00151                         }
00152                 }
00153                 pkg_free(cnts_hash_table.table);
00154         }
00155         if (grp_hash_table.table) {
00156                 for (r=0; r< grp_hash_table.size; r++) {
00157                         clist_foreach_safe(&grp_hash_table.table[r], e, bak, next) {
00158                                 pkg_free(e);
00159                         }
00160                 }
00161                 pkg_free(grp_hash_table.table);
00162         }
00163         if (cnt_id2record)
00164                 pkg_free(cnt_id2record);
00165         if (grp_sorted)
00166                 pkg_free(grp_sorted);
00167         cnts_hash_table.table = 0;
00168         cnts_hash_table.size = 0;
00169         cnt_id2record = 0;
00170         grp_sorted = 0;
00171         grp_hash_table.table = 0;
00172         grp_hash_table.size = 0;
00173         grp_sorted_crt_size = 0;
00174         grp_sorted_max_size = 0;
00175         cnts_no = 0;
00176         _cnts_row_len = 0;
00177         cnts_max_rows = 0;
00178         grp_no = 0;
00179 }
00180 
00181 
00182 
00187 int counters_prefork_init(int max_process_no)
00188 {
00189         counter_array_t* old;
00190         int size, row_size;
00191         counter_handle_t h;
00192         /* round cnts_no so that cnts_no * sizeof(counter) it's a CACHELINE_PAD
00193            multiple */
00194         /* round-up row_size to a CACHELINE_PAD multiple  if needed */
00195         row_size = ((sizeof(*_cnts_vals) * cnts_no - 1) / CACHELINE_PAD + 1) *
00196                 CACHELINE_PAD;
00197         /* round-up the resulted row_siue to a sizeof(*_cnts_vals) multiple */
00198         row_size = ((row_size -1) / sizeof(*_cnts_vals) + 1) *
00199                                 sizeof(*_cnts_vals);
00200         /* get updated cnts_no (row length) */
00201         _cnts_row_len = row_size / sizeof(*_cnts_vals);
00202         size = max_process_no * row_size;
00203         /* replace the temporary pre-fork pkg array (with only 1 row) with
00204            the final shm version (with max_process_no rows) */
00205         old = _cnts_vals;
00206         _cnts_vals = shm_malloc(size);
00207         if (_cnts_vals == 0)
00208                 return -1;
00209         memset(_cnts_vals, 0, size);
00210         cnts_max_rows = max_process_no;
00211         /* copy prefork values into the newly shm array */
00212         if (old) {
00213                 for (h.id = 0; h.id < cnts_no; h.id++)
00214                         counter_pprocess_val(process_no, h) = old[h.id].v;
00215                 pkg_free(old);
00216         }
00217         return 0;
00218 }
00219 
00220 
00221 
00225 static struct grp_record* grp_hash_add(str* group)
00226 {
00227         struct str_hash_entry* g;
00228         struct grp_record* grp_rec;
00229         struct grp_record** r;
00230 
00231         /* grp_rec copied at &g->u.data */
00232         g = pkg_malloc(sizeof(struct str_hash_entry) - sizeof(g->u.data) +
00233                                         sizeof(*grp_rec) + group->len + 1);
00234         if (g == 0)
00235                 goto error;
00236         grp_rec = (struct grp_record*)&g->u.data[0];
00237         grp_rec->group.s = (char*)(grp_rec + 1);
00238         grp_rec->group.len = group->len;
00239         grp_rec->first = 0;
00240         memcpy(grp_rec->group.s, group->s, group->len + 1);
00241         g->key = grp_rec->group;
00242         g->flags = 0;
00243         /* insert group into the sorted group array */
00244         if (grp_sorted_max_size <= grp_sorted_crt_size) {
00245                 /* must increase the array */
00246                 r = pkg_realloc(grp_sorted, 2 * grp_sorted_max_size *
00247                                                 sizeof(*grp_sorted));
00248                 if (r == 0)
00249                         goto error;
00250                 grp_sorted= r;
00251                 grp_sorted_max_size *= 2;
00252                 memset(&grp_sorted[grp_sorted_crt_size], 0,
00253                                 (grp_sorted_max_size - grp_sorted_crt_size) *
00254                                 sizeof(*grp_sorted));
00255         }
00256         for (r = grp_sorted; r < (grp_sorted + grp_sorted_crt_size); r++)
00257                 if (strcmp(grp_rec->group.s, (*r)->group.s) < 0)
00258                         break;
00259         if (r != (grp_sorted + grp_sorted_crt_size))
00260                 memmove(r+1, r, (int)(long)((char*)(grp_sorted + grp_sorted_crt_size) -
00261                                                 (char*)r));
00262         grp_sorted_crt_size++;
00263         *r = grp_rec;
00264         /* insert into the hash only on success */
00265         str_hash_add(&grp_hash_table, g);
00266         return grp_rec;
00267 error:
00268         if (g)
00269                 pkg_free(g);
00270         return 0;
00271 }
00272 
00273 
00274 
00278 static struct grp_record* grp_hash_lookup(str* group)
00279 {
00280         struct str_hash_entry* e;
00281         e = str_hash_get(&grp_hash_table, group->s, group->len);
00282         return e?(struct grp_record*)&e->u.data[0]:0;
00283 }
00284 
00285 
00286 
00291 static struct grp_record* grp_hash_get_create(str* group)
00292 {
00293         struct grp_record* ret;
00294 
00295         ret = grp_hash_lookup(group);
00296         if (ret)
00297                 return ret;
00298         return grp_hash_add(group);
00299 }
00300 
00301 
00302 
00306 static struct counter_record* cnt_hash_add(
00307                                                         str* group, str* name,
00308                                                         int flags, counter_cbk_f cbk,
00309                                                         void* param, const char* doc)
00310 {
00311         struct str_hash_entry* e;
00312         struct counter_record* cnt_rec;
00313         struct grp_record* grp_rec;
00314         struct counter_record** p;
00315         counter_array_t* v;
00316         int doc_len;
00317         int n;
00318         
00319         e = 0;
00320         if (cnts_no >= MAX_COUNTER_ID)
00321                 /* too many counters */
00322                 goto error;
00323         grp_rec = grp_hash_get_create(group);
00324         if (grp_rec == 0)
00325                 /* non existing group an no new one could be created */
00326                 goto error;
00327         doc_len = doc?strlen(doc):0;
00328         /* cnt_rec copied at &e->u.data[0] */
00329         e = pkg_malloc(sizeof(struct str_hash_entry) - sizeof(e->u.data) +
00330                                         sizeof(*cnt_rec) + name->len + 1 + group->len + 1 +
00331                                         doc_len + 1);
00332         if (e == 0)
00333                 goto error;
00334         cnt_rec = (struct counter_record*)&e->u.data[0];
00335         cnt_rec->group.s = (char*)(cnt_rec + 1);
00336         cnt_rec->group.len = group->len;
00337         cnt_rec->name.s = cnt_rec->group.s + group->len + 1;
00338         cnt_rec->name.len = name->len;
00339         cnt_rec->doc.s = cnt_rec->name.s + name->len +1;
00340         cnt_rec->doc.len = doc_len;
00341         cnt_rec->h.id = cnts_no++;
00342         cnt_rec->flags = flags;
00343         cnt_rec->cbk_param = param;
00344         cnt_rec->cbk = cbk;
00345         cnt_rec->grp_next = 0;
00346         memcpy(cnt_rec->group.s, group->s, group->len + 1);
00347         memcpy(cnt_rec->name.s, name->s, name->len + 1);
00348         if (doc)
00349                 memcpy(cnt_rec->doc.s, doc, doc_len + 1);
00350         else
00351                 cnt_rec->doc.s[0] = 0;
00352         e->key = cnt_rec->name;
00353         e->flags = 0;
00354         /* check to see if it fits in the prefork tmp. vals array.
00355            This array contains only one "row", is allocated in pkg and
00356            is used only until counters_prefork_init() (after that the
00357            array is replaced with a shm version with all the needed rows).
00358          */
00359         if (cnt_rec->h.id >= _cnts_row_len || _cnts_vals == 0) {
00360                 /* array to small or not yet allocated => reallocate/allocate it
00361                    (min size PREINIT_CNTS_VALS_SIZE, max MAX_COUNTER_ID)
00362                  */
00363                 n = (cnt_rec->h.id < PREINIT_CNTS_VALS_SIZE) ?
00364                                 PREINIT_CNTS_VALS_SIZE :
00365                                 ((2 * (cnt_rec->h.id + (cnt_rec->h.id == 0)) < MAX_COUNTER_ID)?
00366                                         (2 * (cnt_rec->h.id + (cnt_rec->h.id == 0))) :
00367                                         MAX_COUNTER_ID + 1);
00368                 v = pkg_realloc(_cnts_vals, n * sizeof(*_cnts_vals));
00369                 if (v == 0)
00370                         /* realloc/malloc error */
00371                         goto error;
00372                 _cnts_vals = v;
00373                 /* zero newly allocated memory */
00374                 memset(&_cnts_vals[_cnts_row_len], 0,
00375                                 (n - _cnts_row_len) * sizeof(*_cnts_vals));
00376                 _cnts_row_len = n; /* record new length */
00377         }
00378         /* add a pointer to it in the records array */
00379         if (cnt_id2record_size <= cnt_rec->h.id) {
00380                 /* must increase the array */
00381                 p = pkg_realloc(cnt_id2record,
00382                                                 2 * cnt_id2record_size * sizeof(*cnt_id2record));
00383                 if (p == 0)
00384                         goto error;
00385                 cnt_id2record = p;
00386                 cnt_id2record_size *= 2;
00387                 memset(&cnt_id2record[cnt_rec->h.id], 0,
00388                                 (cnt_id2record_size - cnt_rec->h.id) * sizeof(*cnt_id2record));
00389         }
00390         cnt_id2record[cnt_rec->h.id] = cnt_rec;
00391         /* add into the hash */
00392         str_hash_add(&cnts_hash_table, e);
00393         /* insert it sorted in the per group list */
00394         for (p = &grp_rec->first; *p; p = &((*p)->grp_next))
00395                 if (strcmp(cnt_rec->name.s, (*p)->name.s) < 0)
00396                         break;
00397         cnt_rec->grp_next = *p;
00398         *p = cnt_rec;
00399         return cnt_rec;
00400 error:
00401         if (e)
00402                 pkg_free(e);
00403         return 0;
00404 }
00405 
00406 
00407 
00414 static struct counter_record* cnt_hash_lookup(str* group, str* name)
00415 {
00416         struct str_hash_entry* e;
00417         struct str_hash_entry* first;
00418         struct counter_record* cnt_rec;
00419         e = str_hash_get(&cnts_hash_table, name->s, name->len);
00420         /* fast path */
00421         if (likely(e)) {
00422                 cnt_rec = (struct counter_record*)&e->u.data[0];
00423                 if (likely( group->len == 0 ||
00424                                 (cnt_rec->group.len == group->len &&
00425                                 memcmp(cnt_rec->group.s, group->s, group->len) == 0)))
00426                 return cnt_rec;
00427         } else
00428                 return 0;
00429         /* search between records with same name, but different groups */
00430         first = e;
00431         do {
00432                 cnt_rec = (struct counter_record*)&e->u.data[0];
00433                 if (cnt_rec->group.len == group->len &&
00434                         cnt_rec->name.len  == name->len &&
00435                         memcmp(cnt_rec->group.s, group->s, group->len) == 0 &&
00436                         memcmp(cnt_rec->name.s, name->s, name->len) == 0)
00437                         /* found */
00438                         return cnt_rec;
00439                 e = e->next;
00440         } while(e != first);
00441         return 0;
00442 }
00443 
00444 
00445 
00450 static struct counter_record* cnt_hash_get_create(
00451                                                                 str* group, str* name,
00452                                                                 int flags,
00453                                                                 counter_cbk_f cbk,
00454                                                                 void* param, const char* doc)
00455 {
00456         struct counter_record* ret;
00457 
00458         ret = cnt_hash_lookup(group, name);
00459         if (ret)
00460                 return ret;
00461         return cnt_hash_add(group, name, flags, cbk, param, doc);
00462 }
00463 
00464 
00465 
00483 int counter_register(   counter_handle_t* handle, const char* group,
00484                                                 const char* name, int flags,
00485                                                 counter_cbk_f cbk, void* cbk_param,
00486                                                 const char* doc,
00487                                                 int reg_flags)
00488 {
00489         str grp;
00490         str n;
00491         struct counter_record* cnt_rec;
00492 
00493         if (unlikely(cnts_max_rows)) {
00494                 /* too late */
00495                 BUG("late attempt to register counter: %s.%s\n", group, name);
00496                 goto error;
00497         }
00498         n.s = (char*)name;
00499         n.len = strlen(name);
00500         if (unlikely(group == 0 || *group == 0)) {
00501                 BUG("attempt to register counter %s without a group\n", name);
00502                 goto error;
00503         }
00504         grp.s = (char*)group;
00505         grp.len = strlen(group);
00506         cnt_rec = cnt_hash_lookup(&grp, &n);
00507         if (cnt_rec) {
00508                 if (reg_flags & 1)
00509                         goto found;
00510                 else {
00511                         if (handle) handle->id = 0;
00512                         return -2;
00513                 }
00514         } else
00515                 cnt_rec = cnt_hash_get_create(&grp, &n, flags, cbk, cbk_param, doc);
00516         if (unlikely(cnt_rec == 0))
00517                 goto error;
00518 found:
00519         if (handle) *handle = cnt_rec->h;
00520         return 0;
00521 error:
00522         if (handle) handle->id = 0;
00523         return -1;
00524 }
00525 
00526 
00527 
00536 int counter_lookup_str(counter_handle_t* handle, str* group, str* name)
00537 {
00538         struct counter_record* cnt_rec;
00539 
00540         cnt_rec = cnt_hash_lookup(group, name);
00541         if (likely(cnt_rec)) {
00542                 *handle = cnt_rec->h;
00543                 return 0;
00544         }
00545         handle->id = 0;
00546         return -1;
00547 }
00548 
00549 
00550 
00559 int counter_lookup(counter_handle_t* handle,
00560                                         const char* group, const char* name)
00561 {
00562         str grp;
00563         str n;
00564 
00565         n.s = (char*)name;
00566         n.len = strlen(name);
00567         grp.s = (char*)group;
00568         grp.len = group?strlen(group):0;
00569         return counter_lookup_str(handle, &grp, &n);
00570 }
00571 
00572 
00573 
00579 int counter_register_array(const char* group, counter_def_t* defs)
00580 {
00581         int r;
00582         
00583         for (r=0; defs[r].name; r++)
00584                 if (counter_register(   defs[r].handle,
00585                                                                 group, defs[r].name, defs[r].flags,
00586                                                                 defs[r].get_cbk, defs[r].get_cbk_param,
00587                                                                 defs[r].descr, 0) <0)
00588                         return -(r+1); /* return - (idx of bad counter + 1) */
00589         return 0;
00590 }
00591 
00592 
00593 
00599 counter_val_t counter_get_raw_val(counter_handle_t handle)
00600 {
00601         int r;
00602         counter_val_t ret;
00603 
00604         if (unlikely(_cnts_vals == 0)) {
00605                 /* not init yet */
00606                 BUG("counters not fully initialized yet\n");
00607                 return 0;
00608         }
00609         if (unlikely(handle.id >= cnts_no || (short)handle.id < 0)) {
00610                 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00611                 return 0;
00612         }
00613         ret = 0;
00614         for (r = 0; r < cnts_max_rows; r++)
00615                 ret += counter_pprocess_val(r, handle);
00616         return ret;
00617 }
00618 
00619 
00620 
00625 counter_val_t counter_get_val(counter_handle_t handle)
00626 {
00627         struct counter_record* cnt_rec;
00628 
00629         if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00630                 /* not init yet */
00631                 BUG("counters not fully initialized yet\n");
00632                 return 0;
00633         }
00634         cnt_rec = cnt_id2record[handle.id];
00635         if (unlikely(cnt_rec->cbk))
00636                 return cnt_rec->cbk(handle, cnt_rec->cbk_param);
00637         return counter_get_raw_val(handle);
00638 }
00639 
00640 
00641 
00648 void counter_reset(counter_handle_t handle)
00649 {
00650         int r;
00651 
00652         if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00653                 /* not init yet */
00654                 BUG("counters not fully initialized yet\n");
00655                 return;
00656         }
00657         if (unlikely(handle.id >= cnts_no)) {
00658                 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00659                 return;
00660         }
00661         if (unlikely(cnt_id2record[handle.id]->flags & CNT_F_NO_RESET))
00662                 return;
00663         for (r=0; r < cnts_max_rows; r++)
00664                 counter_pprocess_val(r, handle) = 0;
00665         return;
00666 }
00667 
00668 
00669 
00675 char* counter_get_name(counter_handle_t handle)
00676 {
00677         if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00678                 /* not init yet */
00679                 BUG("counters not fully initialized yet\n");
00680                 goto error;
00681         }
00682         if (unlikely(handle.id >= cnts_no)) {
00683                 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00684                 goto error;
00685         }
00686         return cnt_id2record[handle.id]->name.s;
00687 error:
00688         return 0;
00689 }
00690 
00691 
00692 
00698 char* counter_get_group(counter_handle_t handle)
00699 {
00700         if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00701                 /* not init yet */
00702                 BUG("counters not fully initialized yet\n");
00703                 goto error;
00704         }
00705         if (unlikely(handle.id >= cnts_no)) {
00706                 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00707                 goto error;
00708         }
00709         return cnt_id2record[handle.id]->group.s;
00710 error:
00711         return 0;
00712 }
00713 
00714 
00715 
00721 char* counter_get_doc(counter_handle_t handle)
00722 {
00723         if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00724                 /* not init yet */
00725                 BUG("counters not fully initialized yet\n");
00726                 goto error;
00727         }
00728         if (unlikely(handle.id >= cnts_no)) {
00729                 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00730                 goto error;
00731         }
00732         return cnt_id2record[handle.id]->doc.s;
00733 error:
00734         return 0;
00735 }
00736 
00737 
00738 
00745 void counter_iterate_grp_names(void (*cbk)(void* p, str* grp_name), void* p)
00746 {
00747         int r;
00748 
00749         for (r=0; r < grp_sorted_crt_size; r++)
00750                 cbk(p, &grp_sorted[r]->group);
00751 }
00752 
00753 
00754 
00762 void counter_iterate_grp_var_names(     const char* group,
00763                                                                         void (*cbk)(void* p, str* var_name),
00764                                                                         void* p)
00765 {
00766         struct counter_record* r;
00767         struct grp_record* g;
00768         str grp;
00769         
00770         grp.s = (char*)group;
00771         grp.len = strlen(group);
00772         g = grp_hash_lookup(&grp);
00773         if (g)
00774                 for (r = g->first; r; r = r->grp_next)
00775                         cbk(p, &r->name);
00776 }
00777 
00778 
00779 
00787 void counter_iterate_grp_vars(const char* group,
00788                                                           void (*cbk)(void* p, str* g, str* n,
00789                                                                                         counter_handle_t h),
00790                                                           void *p)
00791 {
00792         struct counter_record* r;
00793         struct grp_record* g;
00794         str grp;
00795         
00796         grp.s = (char*)group;
00797         grp.len = strlen(group);
00798         g = grp_hash_lookup(&grp);
00799         if (g)
00800                 for (r = g->first; r; r = r->grp_next)
00801                         cbk(p, &r->group, &r->name, r->h);
00802 }
00803 
00804 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */

Generated on Tue May 22 2012 13:10:04 for SIP Router by  doxygen 1.7.1