Module: sip-router Branch: master Commit: a5583e0ccff1eda9c38041df9d15a8b21e3ebb0c URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a5583e0c...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Tue Aug 24 21:14:50 2010 +0200
core: counters can be used before forking
Counters can now be incremented (not only registered) before counters_prefork_init(). This enables using them also from mod_init() or the fixup functions (not recommended but needed for "indirect" calls). Fixes crashes when modules call a counter using function from mod_init() or a fixup. E.g.: xlog(s) does a dns lookup from mod_init. If the lookup fails the dns code will try to increment the new dns.failed_dns_request counter.
Reported-by: Michal Matyska michal.matyska iptel org
---
counters.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- counters.h | 5 +++- pt.c | 1 + 3 files changed, 65 insertions(+), 10 deletions(-)
diff --git a/counters.c b/counters.c index dd8ddf7..56bcd2f 100644 --- a/counters.c +++ b/counters.c @@ -23,6 +23,7 @@ * History: * -------- * 2010-08-06 initial version (andrei) + * 2010-08-24 counters can be used (inc,add) before prefork_init (andrei) */
#include "counters.h" @@ -47,6 +48,11 @@
/* leave space for one flag */ #define MAX_COUNTER_ID 32767 +/* size (number of entries) of the temporary array used for keeping stats + pre-prefork init. Note: if more counters are registered then this size, + the array will be dynamically increased (doubled each time). The value + here is meant only to optimize startup/memory fragmentation. */ +#define PREINIT_CNTS_VALS_SIZE 128
struct counter_record { str group; @@ -85,7 +91,7 @@ static int grp_no; /* number of groups */ counter_array_t* _cnts_vals; int _cnts_row_len; /* number of elements per row */ static int cnts_no; /* number of registered counters */ -static int cnts_max_rows; /* set to process number */ +static int cnts_max_rows; /* set to 0 if not yet fully init */
@@ -101,6 +107,8 @@ int init_counters() goto error; str_hash_init(&grp_hash_table); cnts_no = 1; /* start at 1 (0 used only for invalid counters) */ + cnts_max_rows = 0; /* 0 initially, !=0 after full init + (counters_prefork_init()) */ grp_no = 0; cnt_id2record_size = CNT_ID2RECORD_SIZE; cnt_id2record = pkg_malloc(sizeof(*cnt_id2record) * cnt_id2record_size); @@ -127,7 +135,12 @@ void destroy_counters() struct str_hash_entry* e; struct str_hash_entry* bak; if (_cnts_vals) { - shm_free(_cnts_vals); + if (cnts_max_rows) + /* fully init => it is in shm */ + shm_free(_cnts_vals); + else + /* partially init (before prefork) => pkg */ + pkg_free(_cnts_vals); _cnts_vals = 0; } if (cnts_hash_table.table) { @@ -160,6 +173,7 @@ void destroy_counters() grp_sorted_max_size = 0; cnts_no = 0; _cnts_row_len = 0; + cnts_max_rows = 0; grp_no = 0; }
@@ -171,7 +185,9 @@ void destroy_counters() */ int counters_prefork_init(int max_process_no) { + counter_array_t* old; int size, row_size; + counter_handle_t h; /* round cnts_no so that cnts_no * sizeof(counter) it's a CACHELINE_PAD multiple */ /* round-up row_size to a CACHELINE_PAD multiple if needed */ @@ -183,11 +199,20 @@ int counters_prefork_init(int max_process_no) /* get updated cnts_no (row length) */ _cnts_row_len = row_size / sizeof(*_cnts_vals); size = max_process_no * row_size; + /* replace the temporary pre-fork pkg array (with only 1 row) with + the final shm version (with max_process_no rows) */ + old = _cnts_vals; _cnts_vals = shm_malloc(max_process_no * row_size); if (_cnts_vals == 0) return -1; memset(_cnts_vals, 0, max_process_no * row_size); cnts_max_rows = max_process_no; + /* copy prefork values into the newly shm array */ + if (old) { + for (h.id = 0; h.id < cnts_no; h.id++) + counter_pprocess_val(process_no, h) = old[h.id].v; + pkg_free(old); + } return 0; }
@@ -286,7 +311,9 @@ static struct counter_record* cnt_hash_add( struct counter_record* cnt_rec; struct grp_record* grp_rec; struct counter_record** p; + counter_array_t* v; int doc_len; + int n; e = 0; if (cnts_no >= MAX_COUNTER_ID) @@ -323,7 +350,31 @@ static struct counter_record* cnt_hash_add( cnt_rec->doc.s[0] = 0; e->key = cnt_rec->name; e->flags = 0; - /* add it a pointer to it in the records array */ + /* check to see if it fits in the prefork tmp. vals array. + This array contains only one "row", is allocated in pkg and + is used only until counters_prefork_init() (after that the + array is replaced with a shm version with all the needed rows). + */ + if (cnt_rec->h.id >= _cnts_row_len || _cnts_vals == 0) { + /* array to small or not yet allocated => reallocate/allocate it + (min size PREINIT_CNTS_VALS_SIZE, max MAX_COUNTER_ID) + */ + n = (cnt_rec->h.id < PREINIT_CNTS_VALS_SIZE) ? + PREINIT_CNTS_VALS_SIZE : + ((2 * (cnt_rec->h.id + (cnt_rec->h.id == 0)) < MAX_COUNTER_ID)? + (2 * (cnt_rec->h.id + (cnt_rec->h.id == 0))) : + MAX_COUNTER_ID + 1); + v = pkg_realloc(_cnts_vals, n * sizeof(*_cnts_vals)); + if (v == 0) + /* realloc/malloc error */ + goto error; + _cnts_vals = v; + /* zero newly allocated memory */ + memset(&_cnts_vals[_cnts_row_len], 0, + (n - _cnts_row_len) * sizeof(*_cnts_vals)); + _cnts_row_len = n; /* record new length */ + } + /* add a pointer to it in the records array */ if (cnt_id2record_size <= cnt_rec->h.id) { /* must increase the array */ p = pkg_realloc(cnt_id2record, @@ -438,7 +489,7 @@ int counter_register( counter_handle_t* handle, const char* group, str n; struct counter_record* cnt_rec;
- if (unlikely(_cnts_vals)) { + if (unlikely(cnts_max_rows)) { /* too late */ BUG("late attempt to register counter: %s.%s\n", group, name); goto error; @@ -554,7 +605,7 @@ counter_val_t counter_get_raw_val(counter_handle_t handle) BUG("counters not fully initialized yet\n"); return 0; } - if (unlikely(handle.id >= cnts_no || handle.id < 0)) { + if (unlikely(handle.id >= cnts_no || (short)handle.id < 0)) { BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1); return 0; } @@ -597,7 +648,7 @@ void counter_reset(counter_handle_t handle) { int r;
- if (unlikely(_cnts_vals == 0)) { + if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) { /* not init yet */ BUG("counters not fully initialized yet\n"); return; @@ -622,7 +673,7 @@ void counter_reset(counter_handle_t handle) */ char* counter_get_name(counter_handle_t handle) { - if (unlikely(_cnts_vals == 0)) { + if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) { /* not init yet */ BUG("counters not fully initialized yet\n"); goto error; @@ -645,7 +696,7 @@ error: */ char* counter_get_group(counter_handle_t handle) { - if (unlikely(_cnts_vals == 0)) { + if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) { /* not init yet */ BUG("counters not fully initialized yet\n"); goto error; @@ -668,7 +719,7 @@ error: */ char* counter_get_doc(counter_handle_t handle) { - if (unlikely(_cnts_vals == 0)) { + if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) { /* not init yet */ BUG("counters not fully initialized yet\n"); goto error; diff --git a/counters.h b/counters.h index ca09ab4..6081ae0 100644 --- a/counters.h +++ b/counters.h @@ -109,7 +109,10 @@ char* counter_get_name(counter_handle_t handle); char* counter_get_group(counter_handle_t handle); char* counter_get_doc(counter_handle_t handle);
-/** gets the per process value of counter h for process p_no. */ +/** gets the per process value of counter h for process p_no. + * Note that if used before counter_prefork_init() process_no is 0 + * and _cnts_vals will point into a temporary one "row" array. + */ #define counter_pprocess_val(p_no, h) \ _cnts_vals[(p_no) * _cnts_row_len + (h).id].v
diff --git a/pt.c b/pt.c index 994f998..68842e6 100644 --- a/pt.c +++ b/pt.c @@ -47,6 +47,7 @@ #if defined PKG_MALLOC || defined SHM_MEM #include "cfg_core.h" #endif +#include "daemonize.h"
#include <stdio.h> #include <time.h> /* time(), used to initialize random numbers */