[sr-dev] git:master: cfg framework: CFG_CB_ONLY_ONCE flag

Miklos Tirpak miklos at iptel.org
Fri Sep 11 12:12:44 CEST 2009


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

Author: Miklos Tirpak <miklos at iptel.org>
Committer: Miklos Tirpak <miklos at 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);




More information about the sr-dev mailing list