[sr-dev] git:tirpi/cfg_framework_multivalue: cfg framework: group handle can be moved runtime

Miklos Tirpak miklos at iptel.org
Mon Oct 4 16:29:42 CEST 2010


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

Author: Miklos Tirpak <miklos at iptel.org>
Committer: Miklos Tirpak <miklos at iptel.org>
Date:   Mon Oct  4 15:26:58 2010 +0200

cfg framework: group handle can be moved runtime

Added support for moving the group handles between the default
configuration and different group instances runtime. The handles are
reset when cfg_update() is called the next time, or it can be
reset explicitely.

---

 cfg/cfg_struct.c |   97 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 cfg/cfg_struct.h |   52 +++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+), 1 deletions(-)

diff --git a/cfg/cfg_struct.c b/cfg/cfg_struct.c
index 358e4eb..30bd101 100644
--- a/cfg/cfg_struct.c
+++ b/cfg/cfg_struct.c
@@ -32,6 +32,7 @@
 #include "../mem/shm_mem.h"
 #include "../ut.h"
 #include "../locking.h"
+#include "../bit_scan.h"
 #include "cfg_ctx.h"
 #include "cfg_script.h"
 #include "cfg_select.h"
@@ -42,7 +43,7 @@ cfg_block_t	**cfg_global = NULL;	/* pointer to the active cfg block */
 cfg_block_t	*cfg_local = NULL;	/* per-process pointer to the active cfg block.
 					Updated only when the child process
 					finishes working on the SIP message */
-static int	cfg_block_size = 0;	/* size of the cfg block including the meta-data (constant) */
+int		cfg_block_size = 0;	/* size of the cfg block including the meta-data (constant) */
 gen_lock_t	*cfg_global_lock = 0;	/* protects *cfg_global */
 gen_lock_t	*cfg_writer_lock = 0;	/* This lock makes sure that two processes do not
 					try to clone *cfg_global at the same time.
@@ -55,6 +56,7 @@ cfg_child_cb_t	**cfg_child_cb_first = NULL;	/* first item of the per-child proce
 						callback list */
 cfg_child_cb_t	**cfg_child_cb_last = NULL;	/* last item of the above list */
 cfg_child_cb_t	*cfg_child_cb = NULL;	/* pointer to the previously executed cb */	
+int		cfg_ginst_count = 0;	/* number of group instances set within the child process */
 
 
 /* forward declarations */
@@ -1057,3 +1059,96 @@ error:
 	shm_free(new_array);
 	return -1;
 }
+
+/* Move the group handle to the specified group instance pointed by dst_ginst.
+ * src_ginst shall point to the active group instance.
+ * Both parameters can be NULL meaning that the src/dst config is the default, 
+ * not an additional group instance.
+ * The function executes all the per-child process callbacks which are different
+ * in the two instaces.
+ */
+void cfg_move_handle(cfg_group_t *group, cfg_group_inst_t *src_ginst, cfg_group_inst_t *dst_ginst)
+{
+	cfg_mapping_t		*var;
+	unsigned int		bitmap;
+	int			i, pos;
+	str			gname, vname;
+
+	if (src_ginst == dst_ginst)
+		return;	/* nothing to do */
+
+	/* move the handle to the variables of the dst group instance,
+	or to the local config if no dst group instance is specified */
+	*(group->handle) = dst_ginst ?
+				dst_ginst->vars
+				: CFG_GROUP_DATA(cfg_local, group);
+
+	/* call the per child process callback of those variables
+	that have different value in the two group instances */
+	/* TODO: performance optimization: this entire loop can be
+	skipped if the group does not have any variable with
+	per-child process callback. Use some flag in the group
+	structure for this purpose. */
+	gname.s = group->name;
+	gname.len = group->name_len;
+	for (i = 0; i < CFG_MAX_VAR_NUM/(sizeof(int)*8); i++) {
+		bitmap = ((src_ginst) ? src_ginst->set[i] : 0U)
+			| ((dst_ginst) ? dst_ginst->set[i] : 0U);
+		while (bitmap) {
+			pos = bit_scan_forward32(bitmap);
+			var = &group->mapping[pos + i*sizeof(int)*8];
+			if (var->def->on_set_child_cb) {
+				vname.s = var->def->name;
+				vname.len = var->name_len;
+				var->def->on_set_child_cb(&gname, &vname);
+			}
+			bitmap -= (1U << pos);
+		}
+	}
+	/* keep track of how many group instences are set in the child process */
+	if (!src_ginst && dst_ginst)
+		cfg_ginst_count++;
+	else if (!dst_ginst)
+		cfg_ginst_count--;
+#ifdef EXTRA_DEBUG
+	if (cfg_ginst_count < 0)
+		LOG(L_ERR, "ERROR: cfg_select(): BUG, cfg_ginst_count is negative: %d. group=%.*s\n",
+			cfg_ginst_count, group->name_len, group->name);
+#endif
+	return;
+}
+
+/* Move the group handle to the specified group instance. */
+int cfg_select(cfg_group_t *group, unsigned int id)
+{
+	cfg_group_inst_t	*ginst;
+
+	if (!(ginst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
+				group->size,
+				id))
+	) {
+		LOG(L_ERR, "ERROR: cfg_select(): group instance '%.*s[%u]' does not exist\n",
+				group->name_len, group->name, id);
+		return -1;
+	}
+
+	cfg_move_handle(group,
+			CFG_HANDLE_TO_GINST(*(group->handle)), /* the active group instance */
+			ginst);
+
+	LOG(L_DBG, "DEBUG: cfg_select(): group instance '%.*s[%u]' has been selected\n",
+			group->name_len, group->name, id);
+	return 0;
+}
+
+/* Reset the group handle to the default, local configuration */
+int cfg_reset(cfg_group_t *group)
+{
+	cfg_move_handle(group,
+			CFG_HANDLE_TO_GINST(*(group->handle)), /* the active group instance */
+			NULL);
+
+	LOG(L_DBG, "DEBUG: cfg_reset(): default group '%.*s' has been selected\n",
+			group->name_len, group->name);
+	return 0;
+}
diff --git a/cfg/cfg_struct.h b/cfg/cfg_struct.h
index 545554c..0c62a3d 100644
--- a/cfg/cfg_struct.h
+++ b/cfg/cfg_struct.h
@@ -163,12 +163,14 @@ typedef struct _cfg_child_cb {
 extern cfg_group_t	*cfg_group;
 extern cfg_block_t	**cfg_global;
 extern cfg_block_t	*cfg_local;
+extern int		cfg_block_size;
 extern gen_lock_t	*cfg_global_lock;
 extern gen_lock_t	*cfg_writer_lock;
 extern int		cfg_shmized;
 extern cfg_child_cb_t	**cfg_child_cb_first;
 extern cfg_child_cb_t	**cfg_child_cb_last;
 extern cfg_child_cb_t	*cfg_child_cb;
+extern int		cfg_ginst_count;
 
 /* magic value for cfg_child_cb for processes that do not want to
    execute per-child callbacks */
@@ -196,6 +198,15 @@ extern cfg_child_cb_t	*cfg_child_cb;
 #define CFG_VAR_TEST_AND_SET(group_inst, var) \
 	bit_test_and_set((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
 
+/* Return the group instance pointer from a handle,
+ * or NULL if the handle points to the default configuration block */
+#define CFG_HANDLE_TO_GINST(h) \
+	( (((unsigned char*)(h) < cfg_local->vars) \
+		|| ((unsigned char*)(h) > cfg_local->vars + cfg_block_size) \
+	) ? \
+		(cfg_group_inst_t*)((char*)(h) - (unsigned long)&((cfg_group_inst_t *)0)->vars) \
+		: NULL )
+
 /* initiate the cfg framework */
 int sr_cfg_init(void);
 
@@ -268,6 +279,16 @@ static inline void cfg_block_free(cfg_block_t *block)
 	shm_free(block);
 }
 
+/* Move the group handle to the specified group instance pointed by dst_ginst.
+ * src_ginst shall point to the active group instance.
+ * Both parameters can be NULL meaning that the src/dst config is the default, 
+ * not an additional group instance.
+ * The function executes all the per-child process callbacks which are different
+ * in the two instaces.
+ */
+void cfg_move_handle(cfg_group_t *group, cfg_group_inst_t *src_ginst, cfg_group_inst_t *dst_ginst);
+
+
 /* lock and unlock the global cfg block -- used only at the
  * very last step when the block is replaced */
 #define CFG_LOCK()	lock_get(cfg_global_lock);
@@ -352,6 +373,29 @@ static inline void cfg_update_local(int no_cbs)
 	}
 }
 
+/* Reset all the group handles to the default, local configuration */
+static inline void cfg_reset_handles(void)
+{
+	cfg_group_t	*group;
+
+	if (!cfg_local)
+		return;
+
+	for (	group = cfg_group;
+		group && cfg_ginst_count; /* cfg_ginst_count is decreased every time
+					a group handle is reset. When it reaches 0,
+					needless to continue the loop */
+		group = group->next
+	) {
+		if (((unsigned char*)*(group->handle) < cfg_local->vars)
+			|| ((unsigned char*)*(group->handle) > cfg_local->vars + cfg_block_size)
+		)
+			cfg_move_handle(group,
+					CFG_HANDLE_TO_GINST(*(group->handle)),
+					NULL);
+	}
+}
+
 /* sets the local cfg block to the active block
  * 
  * If your module forks a new process that implements
@@ -361,6 +405,8 @@ static inline void cfg_update_local(int no_cbs)
  */
 #define cfg_update() \
 	do { \
+		if (unlikely(cfg_ginst_count)) \
+			cfg_reset_handles(); \
 		if (unlikely(cfg_local != *cfg_global)) \
 			cfg_update_local(0); \
 	} while(0)
@@ -446,4 +492,10 @@ void cfg_child_cb_free(cfg_child_cb_t *child_cb_first);
 int new_add_var(str *group_name, unsigned int group_id, str *var_name,
 				void *val, unsigned int type);
 
+/* Move the group handle to the specified group instance. */
+int cfg_select(cfg_group_t *group, unsigned int id);
+
+/* Reset the group handle to the default, local configuration */
+int cfg_reset(cfg_group_t *group);
+
 #endif /* _CFG_STRUCT_H */




More information about the sr-dev mailing list