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=b062f42f...
Author: Miklos Tirpak miklos@iptel.org Committer: Miklos Tirpak miklos@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 */