summaryrefslogtreecommitdiff
path: root/src/app/main/subsysmgr.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-11-07 08:59:42 -0500
committerNick Mathewson <nickm@torproject.org>2019-11-07 08:59:42 -0500
commitf6c9ca3a1d1c29a293915612e26cdbfeb050c192 (patch)
treeb210ebcead649d0a22c6e09c11b726da15a01f7c /src/app/main/subsysmgr.c
parent582cee723a86e44f140a5057152df06659c36e71 (diff)
parentde7053b8967db64ae2a871d11b12afbcb9b1f8a6 (diff)
downloadtor-f6c9ca3a1d1c29a293915612e26cdbfeb050c192.tar.gz
tor-f6c9ca3a1d1c29a293915612e26cdbfeb050c192.zip
Merge branch 'config_subsys_v4'
Diffstat (limited to 'src/app/main/subsysmgr.c')
-rw-r--r--src/app/main/subsysmgr.c226
1 files changed, 215 insertions, 11 deletions
diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c
index 1f4bc840f2..8be4a7d75c 100644
--- a/src/app/main/subsysmgr.c
+++ b/src/app/main/subsysmgr.c
@@ -14,10 +14,12 @@
#include "orconfig.h"
#include "app/main/subsysmgr.h"
+#include "lib/confmgt/confmgt.h"
#include "lib/dispatch/dispatch_naming.h"
#include "lib/dispatch/msgtypes.h"
#include "lib/err/torerr.h"
#include "lib/log/log.h"
+#include "lib/log/util_bug.h"
#include "lib/malloc/malloc.h"
#include "lib/pubsub/pubsub_build.h"
#include "lib/pubsub/pubsub_connect.h"
@@ -31,12 +33,42 @@
**/
static bool subsystem_array_validated = false;
+/** Index value indicating that a subsystem has no options/state object, and
+ * so that object does not have an index. */
+#define IDX_NONE (-1)
+
+/**
+ * Runtime status of a single subsystem.
+ **/
+typedef struct subsys_status_t {
+ /** True if the given subsystem is initialized. */
+ bool initialized;
+ /** Index for this subsystem's options object, or IDX_NONE for none. */
+ int options_idx;
+ /** Index for this subsystem's state object, or IDX_NONE for none. */
+ int state_idx;
+} subsys_status_t;
+
+/** An overestimate of the number of subsystems. */
+#define N_SYS_STATUS 128
/**
* True if a given subsystem is initialized. Expand this array if there
* are more than this number of subsystems. (We'd rather not
* dynamically allocate in this module.)
**/
-static bool sys_initialized[128];
+static subsys_status_t sys_status[N_SYS_STATUS];
+
+/** Set <b>status</b> to a default (not set-up) state. */
+static void
+subsys_status_clear(subsys_status_t *status)
+{
+ if (!status)
+ return;
+ memset(status, 0, sizeof(*status));
+ status->initialized = false;
+ status->state_idx = IDX_NONE;
+ status->options_idx = IDX_NONE;
+}
/**
* Exit with a raw assertion if the subsystems list is inconsistent;
@@ -48,8 +80,8 @@ check_and_setup(void)
if (subsystem_array_validated)
return;
- raw_assert(ARRAY_LENGTH(sys_initialized) >= n_tor_subsystems);
- memset(sys_initialized, 0, sizeof(sys_initialized));
+ raw_assert(ARRAY_LENGTH(sys_status) >= n_tor_subsystems);
+ memset(sys_status, 0, sizeof(sys_status));
int last_level = MIN_SUBSYS_LEVEL;
@@ -67,6 +99,8 @@ check_and_setup(void)
sys->name, i, sys->level, last_level);
raw_assert_unreached_msg("There is a bug in subsystem_list.c");
}
+ subsys_status_clear(&sys_status[i]);
+
last_level = sys->level;
}
@@ -97,7 +131,7 @@ subsystems_init_upto(int target_level)
continue;
if (sys->level > target_level)
break;
- if (sys_initialized[i])
+ if (sys_status[i].initialized)
continue;
int r = 0;
if (sys->initialize) {
@@ -112,7 +146,7 @@ subsystems_init_upto(int target_level)
sys->name, i);
raw_assert_unreached_msg("A subsystem couldn't be initialized.");
}
- sys_initialized[i] = true;
+ sys_status[i].initialized = true;
}
return 0;
@@ -132,7 +166,7 @@ subsystems_add_pubsub_upto(pubsub_builder_t *builder,
continue;
if (sys->level > target_level)
break;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
int r = 0;
if (sys->add_pubsub) {
@@ -186,13 +220,13 @@ subsystems_shutdown_downto(int target_level)
continue;
if (sys->level <= target_level)
break;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->shutdown) {
log_debug(LD_GENERAL, "Shutting down %s", sys->name);
sys->shutdown();
}
- sys_initialized[i] = false;
+ subsys_status_clear(&sys_status[i]);
}
}
@@ -208,7 +242,7 @@ subsystems_prefork(void)
const subsys_fns_t *sys = tor_subsystems[i];
if (!sys->supported)
continue;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->prefork) {
log_debug(LD_GENERAL, "Pre-fork: %s", sys->name);
@@ -229,7 +263,7 @@ subsystems_postfork(void)
const subsys_fns_t *sys = tor_subsystems[i];
if (!sys->supported)
continue;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->postfork) {
log_debug(LD_GENERAL, "Post-fork: %s", sys->name);
@@ -250,7 +284,7 @@ subsystems_thread_cleanup(void)
const subsys_fns_t *sys = tor_subsystems[i];
if (!sys->supported)
continue;
- if (! sys_initialized[i])
+ if (! sys_status[i].initialized)
continue;
if (sys->thread_cleanup) {
log_debug(LD_GENERAL, "Thread cleanup: %s", sys->name);
@@ -258,3 +292,173 @@ subsystems_thread_cleanup(void)
}
}
}
+
+/**
+ * Register all subsystem-declared options formats in <b>mgr</b>.
+ *
+ * Return 0 on success, -1 on failure.
+ **/
+int
+subsystems_register_options_formats(config_mgr_t *mgr)
+{
+ tor_assert(mgr);
+ check_and_setup();
+
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys->options_format) {
+ int options_idx = config_mgr_add_format(mgr, sys->options_format);
+ sys_status[i].options_idx = options_idx;
+ log_debug(LD_CONFIG, "Added options format for %s with index %d",
+ sys->name, options_idx);
+ }
+ }
+ return 0;
+}
+
+/**
+ * Register all subsystem-declared state formats in <b>mgr</b>.
+ *
+ * Return 0 on success, -1 on failure.
+ **/
+int
+subsystems_register_state_formats(config_mgr_t *mgr)
+{
+ tor_assert(mgr);
+ check_and_setup();
+
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys->state_format) {
+ int state_idx = config_mgr_add_format(mgr, sys->state_format);
+ sys_status[i].state_idx = state_idx;
+ log_debug(LD_CONFIG, "Added state format for %s with index %d",
+ sys->name, state_idx);
+ }
+ }
+ return 0;
+}
+
+#ifdef TOR_UNIT_TESTS
+/**
+ * Helper: look up the index for <b>sys</b>. Return -1 if the subsystem
+ * is not recognized.
+ **/
+static int
+subsys_get_idx(const subsys_fns_t *sys)
+{
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ if (sys == tor_subsystems[i])
+ return (int)i;
+ }
+ return -1;
+}
+
+/**
+ * Return the current state-manager's index for any state held by the
+ * subsystem <b>sys</b>. If <b>sys</b> has no options, return -1.
+ *
+ * Using raw indices can be error-prone: only do this from the unit
+ * tests. If you need a way to access another subsystem's configuration,
+ * that subsystem should provide access functions.
+ **/
+int
+subsystems_get_options_idx(const subsys_fns_t *sys)
+{
+ int i = subsys_get_idx(sys);
+ tor_assert(i >= 0);
+ return sys_status[i].options_idx;
+}
+
+/**
+ * Return the current state-manager's index for any state held by the
+ * subsystem <b>sys</b>. If <b>sys</b> has no state, return -1.
+ *
+ * Using raw indices can be error-prone: only do this from the unit
+ * tests. If you need a way to access another subsystem's state
+ * that subsystem should provide access functions.
+ **/
+int
+subsystems_get_state_idx(const subsys_fns_t *sys)
+{
+ int i = subsys_get_idx(sys);
+ tor_assert(i >= 0);
+ return sys_status[i].state_idx;
+}
+#endif
+
+/**
+ * Call all appropriate set_options() methods to tell the various subsystems
+ * about a new set of torrc options. Return 0 on success, -1 on
+ * nonrecoverable failure.
+ **/
+int
+subsystems_set_options(const config_mgr_t *mgr, struct or_options_t *options)
+{
+ /* XXXX This does not yet handle reversible option assignment; I'll
+ * do that later in this branch. */
+
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys_status[i].options_idx >= 0 && sys->set_options) {
+ void *obj = config_mgr_get_obj_mutable(mgr, options,
+ sys_status[i].options_idx);
+ int rv = sys->set_options(obj);
+ if (rv < 0) {
+ log_err(LD_CONFIG, "Error when handling option for %s; "
+ "cannot proceed.", sys->name);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Call all appropriate set_state() methods to tell the various subsystems
+ * about an initial DataDir/state file. Return 0 on success, -1 on
+ * nonrecoverable failure.
+ **/
+int
+subsystems_set_state(const config_mgr_t *mgr, struct or_state_t *state)
+{
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys_status[i].state_idx >= 0 && sys->set_state) {
+ void *obj = config_mgr_get_obj_mutable(mgr, state,
+ sys_status[i].state_idx);
+ int rv = sys->set_state(obj);
+ if (rv < 0) {
+ log_err(LD_CONFIG, "Error when handling state for %s; "
+ "cannot proceed.", sys->name);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Call all appropriate flush_state() methods to tell the various subsystems
+ * to update the state objects in <b>state</b>. Return 0 on success,
+ * -1 on failure.
+ **/
+int
+subsystems_flush_state(const config_mgr_t *mgr, struct or_state_t *state)
+{
+ int result = 0;
+ for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ if (sys_status[i].state_idx >= 0 && sys->flush_state) {
+ void *obj = config_mgr_get_obj_mutable(mgr, state,
+ sys_status[i].state_idx);
+ int rv = sys->flush_state(obj);
+ if (rv < 0) {
+ log_warn(LD_CONFIG, "Error when flushing state to state object for %s",
+ sys->name);
+ result = -1;
+ }
+ }
+ }
+ return result;
+}