[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