group_name, def[i].name);
goto error;
}
+
+ if (def[i].type & CFG_ATOMIC) {
+ if (CFG_VAR_MASK(def[i].type) != CFG_VAR_INT) {
+ LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: atomic change is allowed "
+ "only for integer types\n",
+ group_name, def[i].name);
+ goto error;
+ }
+ if (def[i].on_set_child_cb) {
+ LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: per-child process callback "
+ "does not work together with atomic change\n",
+ group_name, def[i].name);
+ goto error;
+ }
+ }
}
/* minor validation */
#include "../str.h"
+/* variable type */
#define CFG_VAR_INT 1U
#define CFG_VAR_STRING 2U
#define CFG_VAR_STR 3U
#define CFG_VAR_POINTER 4U
+/* number of bits required for the variable type */
#define CFG_INPUT_SHIFT 3
+/* input type */
#define CFG_INPUT_INT (CFG_VAR_INT << CFG_INPUT_SHIFT)
#define CFG_INPUT_STRING (CFG_VAR_STRING << CFG_INPUT_SHIFT)
#define CFG_INPUT_STR (CFG_VAR_STR << CFG_INPUT_SHIFT)
-#define CFG_VAR_MASK(x) ((x)&(CFG_INPUT_INT-1))
-#define CFG_INPUT_MASK(x) ((x)&(~(CFG_INPUT_INT-1)))
+#define CFG_VAR_MASK(x) ((x)&((1U<<CFG_INPUT_SHIFT)-1))
+#define CFG_INPUT_MASK(x) ((x)&((1U<<(2*CFG_INPUT_SHIFT))-(1U<<CFG_INPUT_SHIFT)))
+
+/* atomic change is allowed */
+#define CFG_ATOMIC (1U<<(2*CFG_INPUT_SHIFT))
typedef int (*cfg_on_change)(void *, str *, void **);
typedef void (*cfg_on_set_child)(str *);
while the new one is prepared */
CFG_WRITER_LOCK();
- /* clone the memory block, and prepare the modification */
- if (!(block = cfg_clone_global())) goto error;
+ if (var->def->type & CFG_ATOMIC) {
+ /* atomic change is allowed, we can rewrite the value
+ directly in the global config */
+ p = (*cfg_global)->vars+group->offset+var->offset;
- p = block->vars+group->offset+var->offset;
+ } else {
+ /* clone the memory block, and prepare the modification */
+ if (!(block = cfg_clone_global())) goto error;
+
+ p = block->vars+group->offset+var->offset;
+ }
} else {
/* we are allowed to rewrite the value on-the-fly
The handle either points to group->vars, or to the
replaced[1] = NULL;
}
/* replace the global config with the new one */
- cfg_install_global(block, replaced, child_cb, child_cb);
+ if (block) cfg_install_global(block, replaced, child_cb, child_cb);
CFG_WRITER_UNLOCK();
} else {
/* cfg_set() may be called more than once before forking */
void *core_cfg = &default_core_cfg;
cfg_def_t core_cfg_def[] = {
- {"debug", CFG_VAR_INT, 0, 0, 0, 0, "debug level"},
+ {"debug", CFG_VAR_INT|CFG_ATOMIC, 0, 0, 0, 0, "debug level"},
#ifdef USE_DST_BLACKLIST
/* blacklist */
{"use_dst_blacklist", CFG_VAR_INT, 0, 1, use_dst_blacklist_fixup, 0,
- name that will be used by the drivers to refer to the variable
- flag indicating the variable and the input type, that is accepted
- by the fixup function
+ by the fixup function, and additional optional settings
Valid variable types are:
- CFG_VAR_INT = int
- CFG_INPUT_STRING = char*
- CFG_INPUT_STR = str*
+ Optional settings:
+ - CFG_ATOMIC Indicates that atomic change is allowed:
+ the variable can be changed at any time,
+ there is no need to wait for the SIP
+ message processing to finish.
+ It can be used only with CFG_VAR_INT type,
+ and per-child process callback is not allowed
+
- minimum value for integers (optional)
- maximum value for integers (optional)
- fixup function (optional) that is called when the variable is going to be