Browse code

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.

Miklos Tirpak authored on 11/09/2009 10:08:13
Showing 4 changed files
... ...
@@ -55,6 +55,8 @@
55 55
 #define CFG_ATOMIC		(1U<<(2*CFG_INPUT_SHIFT))
56 56
 /* variable is read-only */
57 57
 #define CFG_READONLY		(1U<<(2*CFG_INPUT_SHIFT+1))
58
+/* per-child process callback needs to be called only once */
59
+#define CFG_CB_ONLY_ONCE	(1U<<(2*CFG_INPUT_SHIFT+2))
58 60
 
59 61
 typedef int (*cfg_on_change)(void *, str *, str *, void **);
60 62
 typedef void (*cfg_on_set_child)(str *, str *);
... ...
@@ -317,7 +317,8 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
317 317
 		s2.s = var->def->name;
318 318
 		s2.len = var->name_len;
319 319
 		child_cb = cfg_child_cb_new(&s, &s2,
320
-					var->def->on_set_child_cb);
320
+					var->def->on_set_child_cb,
321
+					var->def->type);
321 322
 		if (!child_cb) {
322 323
 			LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
323 324
 			goto error0;
... ...
@@ -749,7 +750,8 @@ int cfg_commit(cfg_ctx_t *ctx)
749 749
 			s2.s = changed->var->def->name;
750 750
 			s2.len = changed->var->name_len;
751 751
 			child_cb = cfg_child_cb_new(&s, &s2,
752
-					changed->var->def->on_set_child_cb);
752
+					changed->var->def->on_set_child_cb,
753
+					changed->var->def->type);
753 754
 			if (!child_cb) goto error0;
754 755
 
755 756
 			if (child_cb_last)
... ...
@@ -319,7 +319,7 @@ int sr_cfg_init(void)
319 319
 	This stucture will be the entry point for the child processes, and
320 320
 	will be freed later, when none of the processes refers to it */
321 321
 	*cfg_child_cb_first = *cfg_child_cb_last =
322
-		cfg_child_cb_new(NULL, NULL, NULL);
322
+		cfg_child_cb_new(NULL, NULL, NULL, 0);
323 323
 
324 324
 	if (!*cfg_child_cb_first) goto error;
325 325
 
... ...
@@ -591,7 +591,9 @@ void cfg_install_global(cfg_block_t *block, char **replaced,
591 591
 }
592 592
 
593 593
 /* creates a structure for a per-child process callback */
594
-cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name, cfg_on_set_child cb)
594
+cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name,
595
+			cfg_on_set_child cb,
596
+			unsigned int type)
595 597
 {
596 598
 	cfg_child_cb_t	*cb_struct;
597 599
 
... ...
@@ -612,6 +614,22 @@ cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name, cfg_on_set_child cb)
612 612
 	cb_struct->cb = cb;
613 613
 	atomic_set(&cb_struct->refcnt, 0);
614 614
 
615
+	if (type & CFG_CB_ONLY_ONCE) {
616
+		/* The callback needs to be executed only once.
617
+		 * Set the cb_count value to 1, so the first child
618
+		 * process that executes the callback will decrement
619
+		 * it to 0, and no other children will execute the
620
+		 * callback again.
621
+		 */
622
+		atomic_set(&cb_struct->cb_count, 1);
623
+	} else {
624
+		/* Set the cb_count to a high value, i.e. max signed integer,
625
+		 * so all the child processes will execute the callback,
626
+		 * the counter will never reach 0.
627
+		 */
628
+		atomic_set(&cb_struct->cb_count, (1U<<(sizeof(int)*8-1))-1);
629
+	}
630
+
615 631
 	return cb_struct;
616 632
 }
617 633
 
... ...
@@ -98,6 +98,12 @@ typedef struct _cfg_block {
98 98
 typedef struct _cfg_child_cb {
99 99
 	atomic_t		refcnt; /* number of child processes
100 100
 					referring to the element */
101
+	atomic_t		cb_count;	/* This counter is used to track
102
+						 * how many times the callback needs
103
+						 * to be executed.
104
+						 * >0 the cb needs to be executed
105
+						 * <=0 the cb no longer needs to be executed
106
+						 */
101 107
 	str			gname, name;	/* name of the variable that has changed */
102 108
 	cfg_on_set_child	cb;	/* callback function that has to be called */
103 109
 
... ...
@@ -247,8 +253,11 @@ static inline void cfg_update_local(void)
247 247
 				CFG_UNLOCK();
248 248
 			}
249 249
 		}
250
-		/* execute the callback */
251
-		cfg_child_cb->cb(&cfg_child_cb->gname, &cfg_child_cb->name);
250
+		if (atomic_add(&cfg_child_cb->cb_count, -1) >= 0) /* the new value is returned
251
+								by atomic_add() */
252
+			/* execute the callback */
253
+			cfg_child_cb->cb(&cfg_child_cb->gname, &cfg_child_cb->name);
254
+		/* else the callback no longer needs to be executed */
252 255
 	}
253 256
 }
254 257
 
... ...
@@ -296,7 +305,9 @@ void cfg_install_global(cfg_block_t *block, char **replaced,
296 296
 			cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last);
297 297
 
298 298
 /* creates a structure for a per-child process callback */
299
-cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name, cfg_on_set_child cb);
299
+cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name,
300
+			cfg_on_set_child cb,
301
+			unsigned int type);
300 302
 
301 303
 /* free the memory allocated for a child cb list */
302 304
 void cfg_child_cb_free(cfg_child_cb_t *child_cb_first);