[sr-dev] git:master: core: counters can be used before forking

Andrei Pelinescu-Onciul andrei at iptel.org
Tue Aug 24 21:29:20 CEST 2010


Module: sip-router
Branch: master
Commit: a5583e0ccff1eda9c38041df9d15a8b21e3ebb0c
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a5583e0ccff1eda9c38041df9d15a8b21e3ebb0c

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at 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 */




More information about the sr-dev mailing list