Module: sip-router
Branch: master
Commit: ceef844014b6e4d93e319a3ff8ecf70983bdc30f
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=ceef844…
Author: Miklos Tirpak <miklos(a)iptel.org>
Committer: Miklos Tirpak <miklos(a)iptel.org>
Date: Fri Sep 11 12:08:13 2009 +0200
cfg framework: CFG_CB_ONLY_ONCE flag
CFG_CB_ONLY_ONCE flag indicates that the per-child
process callback is called only once after the changes
to the global config have been committed.
(The first child process that updates its local
config calls the callback, and no other child
process does so.)
The per-child process cb is intended to be used to
update the config variables that are stored outside
of the cfg framework. By default this callback is called
by all the child processes separately, this can be change
with this flag.
---
cfg/cfg.h | 2 ++
cfg/cfg_ctx.c | 6 ++++--
cfg/cfg_struct.c | 22 ++++++++++++++++++++--
cfg/cfg_struct.h | 17 ++++++++++++++---
4 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/cfg/cfg.h b/cfg/cfg.h
index ca511a5..4a77233 100644
--- a/cfg/cfg.h
+++ b/cfg/cfg.h
@@ -55,6 +55,8 @@
#define CFG_ATOMIC (1U<<(2*CFG_INPUT_SHIFT))
/* variable is read-only */
#define CFG_READONLY (1U<<(2*CFG_INPUT_SHIFT+1))
+/* per-child process callback needs to be called only once */
+#define CFG_CB_ONLY_ONCE (1U<<(2*CFG_INPUT_SHIFT+2))
typedef int (*cfg_on_change)(void *, str *, str *, void **);
typedef void (*cfg_on_set_child)(str *, str *);
diff --git a/cfg/cfg_ctx.c b/cfg/cfg_ctx.c
index ef3661c..a504588 100644
--- a/cfg/cfg_ctx.c
+++ b/cfg/cfg_ctx.c
@@ -317,7 +317,8 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
s2.s = var->def->name;
s2.len = var->name_len;
child_cb = cfg_child_cb_new(&s, &s2,
- var->def->on_set_child_cb);
+ var->def->on_set_child_cb,
+ var->def->type);
if (!child_cb) {
LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
goto error0;
@@ -749,7 +750,8 @@ int cfg_commit(cfg_ctx_t *ctx)
s2.s = changed->var->def->name;
s2.len = changed->var->name_len;
child_cb = cfg_child_cb_new(&s, &s2,
- changed->var->def->on_set_child_cb);
+ changed->var->def->on_set_child_cb,
+ changed->var->def->type);
if (!child_cb) goto error0;
if (child_cb_last)
diff --git a/cfg/cfg_struct.c b/cfg/cfg_struct.c
index c90b12e..ad613ee 100644
--- a/cfg/cfg_struct.c
+++ b/cfg/cfg_struct.c
@@ -319,7 +319,7 @@ int sr_cfg_init(void)
This stucture will be the entry point for the child processes, and
will be freed later, when none of the processes refers to it */
*cfg_child_cb_first = *cfg_child_cb_last =
- cfg_child_cb_new(NULL, NULL, NULL);
+ cfg_child_cb_new(NULL, NULL, NULL, 0);
if (!*cfg_child_cb_first) goto error;
@@ -591,7 +591,9 @@ void cfg_install_global(cfg_block_t *block, char **replaced,
}
/* creates a structure for a per-child process callback */
-cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name, cfg_on_set_child cb)
+cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name,
+ cfg_on_set_child cb,
+ unsigned int type)
{
cfg_child_cb_t *cb_struct;
@@ -612,6 +614,22 @@ cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name,
cfg_on_set_child cb)
cb_struct->cb = cb;
atomic_set(&cb_struct->refcnt, 0);
+ if (type & CFG_CB_ONLY_ONCE) {
+ /* The callback needs to be executed only once.
+ * Set the cb_count value to 1, so the first child
+ * process that executes the callback will decrement
+ * it to 0, and no other children will execute the
+ * callback again.
+ */
+ atomic_set(&cb_struct->cb_count, 1);
+ } else {
+ /* Set the cb_count to a high value, i.e. max signed integer,
+ * so all the child processes will execute the callback,
+ * the counter will never reach 0.
+ */
+ atomic_set(&cb_struct->cb_count, (1U<<(sizeof(int)*8-1))-1);
+ }
+
return cb_struct;
}
diff --git a/cfg/cfg_struct.h b/cfg/cfg_struct.h
index f0c2253..e7ac4e3 100644
--- a/cfg/cfg_struct.h
+++ b/cfg/cfg_struct.h
@@ -98,6 +98,12 @@ typedef struct _cfg_block {
typedef struct _cfg_child_cb {
atomic_t refcnt; /* number of child processes
referring to the element */
+ atomic_t cb_count; /* This counter is used to track
+ * how many times the callback needs
+ * to be executed.
+ * >0 the cb needs to be executed
+ * <=0 the cb no longer needs to be executed
+ */
str gname, name; /* name of the variable that has changed */
cfg_on_set_child cb; /* callback function that has to be called */
@@ -247,8 +253,11 @@ static inline void cfg_update_local(void)
CFG_UNLOCK();
}
}
- /* execute the callback */
- cfg_child_cb->cb(&cfg_child_cb->gname, &cfg_child_cb->name);
+ if (atomic_add(&cfg_child_cb->cb_count, -1) >= 0) /* the new value is
returned
+ by atomic_add() */
+ /* execute the callback */
+ cfg_child_cb->cb(&cfg_child_cb->gname, &cfg_child_cb->name);
+ /* else the callback no longer needs to be executed */
}
}
@@ -296,7 +305,9 @@ void cfg_install_global(cfg_block_t *block, char **replaced,
cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last);
/* creates a structure for a per-child process callback */
-cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name, cfg_on_set_child cb);
+cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name,
+ cfg_on_set_child cb,
+ unsigned int type);
/* free the memory allocated for a child cb list */
void cfg_child_cb_free(cfg_child_cb_t *child_cb_first);