summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-11-15 09:10:11 -0500
committerNick Mathewson <nickm@torproject.org>2019-11-15 09:10:11 -0500
commit97b5ff2b1d6ec59aea66cc262cf2545c98eefc5b (patch)
tree647666ffd0b20b0cba476f9fcb330355299ef078
parent7aaa4ae3031aff2d84a24abb4522f77b91e4ea53 (diff)
parent8746fedce4a440cccde2b4683d7aa72e7c0b0c89 (diff)
downloadtor-97b5ff2b1d6ec59aea66cc262cf2545c98eefc5b.tar.gz
tor-97b5ff2b1d6ec59aea66cc262cf2545c98eefc5b.zip
Merge branch 'ticket32211'
-rw-r--r--Doxyfile.in2
-rw-r--r--src/lib/subsys/initialization.dox77
-rw-r--r--src/lib/subsys/subsys.h63
-rw-r--r--src/mainpage.dox2
4 files changed, 140 insertions, 4 deletions
diff --git a/Doxyfile.in b/Doxyfile.in
index 5dbe4500eb..a551759576 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -258,6 +258,8 @@ ALIASES =
ALIASES += refdir{1}="\ref src/\1 \"\1\""
+ALIASES += ticket{1}="[ticket \1](https://bugs.torproject.org/\1)"
+
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
diff --git a/src/lib/subsys/initialization.dox b/src/lib/subsys/initialization.dox
new file mode 100644
index 0000000000..561cd17bab
--- /dev/null
+++ b/src/lib/subsys/initialization.dox
@@ -0,0 +1,77 @@
+/**
+
+@page initialization Initialization and shutdown
+
+@tableofcontents
+
+@section overview Overview
+
+Tor has a single entry point: tor_run_main() in main.c. All the ways of
+starting a Tor process (ntmain.c, tor_main.c, and tor_api.c) work by invoking tor_run_main().
+
+The tor_run_main() function normally exits (@ref init_exceptwhen "1") by
+returning: not by calling abort() or exit(). Before it returns, it calls
+tor_cleanup() in shutdown.c.
+
+Conceptually, there are several stages in running Tor.
+
+1. First, we initialize those modules that do not depend on the
+ configuration. This happens in the first half of tor_run_main(), and the
+ first half of tor_init(). (@ref init_pending_refactor "2")
+
+2. Second, we parse the command line and our configuration, and configure
+ systems that depend on our configuration or state. This configuration
+ happens midway through tor_init(), which invokes
+ options_init_from_torrc(). We then initialize more systems from the
+ second half of tor_init().
+
+3. At this point we may exit early if we have been asked to do something
+ requiring no further initialization, like printing our version number or
+ creating a new signing key. Otherwise, we proceed to run_tor_main_loop(),
+ which initializes some network-specific parts of Tor, grabs some
+ daemon-only resources (like the data directory lock) and starts Tor itself
+ running.
+
+
+> @anchor init_exceptwhen 1. tor_run_main() _can_ terminate with a call to
+> abort() or exit(), but only when crashing due to a bug, or when forking to
+> run as a daemon.
+
+> @anchor init_pending_refactor 2. The pieces of code that I'm describing as
+> "the first part of tor_init()" and so on deserve to be functions with their
+> own name. I'd like to refactor them, but before I do so, there is some
+> slight reorganization that needs to happen. Notably, the
+> nt_service_parse_options() call ought logically to be later in our
+> initialization sequence. See @ticket{32447} for our refactoring progress.
+
+
+@section subsys Subsystems and initialization
+
+Our current convention is to use the subsystem mechanism to initialize and
+clean up pieces of Tor. The more recently updated pieces of Tor will use
+this mechanism. For examples, see e.g. time_sys.c or log_sys.c.
+
+In simplest terms, a **subsytem** is a logically separate part of Tor that
+can be initialized, shut down, managed, and configured somewhat independently
+of the rest of the program.
+
+The subsys_fns_t type describes a subsystem and a set of functions that
+initialize it, desconstruct it, and so on. To define a subsystem, we declare
+a `const` instance of subsys_fns_t. See the documentation for subsys_fns_t
+for a full list of these functions.
+
+After defining a subsytem, it must be inserted in subsystem_list.c. At that
+point, table-driven mechanisms in subsysmgr.c will invoke its functions when
+appropriate.
+
+@subsection vsconfig Initialization versus configuration
+
+We note that the initialization phase of Tor occurs before any configuration
+is read from disk -- and therefore before any other files are read from
+disk. Therefore, any behavior that depends on Tor's configuration or state
+must occur _after_ the initialization process, during configuration.
+
+
+
+
+**/
diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h
index 29a90c049d..324f4f2947 100644
--- a/src/lib/subsys/subsys.h
+++ b/src/lib/subsys/subsys.h
@@ -23,8 +23,16 @@ struct config_format_t;
* All callbacks are optional -- if a callback is set to NULL, the subsystem
* manager will treat it as a no-op.
*
- * You should use c99 named-field initializers with this structure: we
- * will be adding more fields, often in the middle of the structure.
+ * You should use c99 named-field initializers with this structure, for
+ * readability and safety. (There are a lot of functions here, all of them
+ * optional, and many of them with similar signatures.)
+ *
+ * See @ref initialization for more information about initialization and
+ * shutdown in Tor.
+ *
+ * To make a new subsystem, you declare a const instance of this type, and
+ * include it on the list in subsystem_list.c. The code that manages these
+ * subsystems is in subsysmgr.c.
**/
typedef struct subsys_fns_t {
/**
@@ -55,7 +63,7 @@ typedef struct subsys_fns_t {
* it is only for global state or pre-configuration state.
*
* (If you need to do any setup that depends on configuration, you'll need
- * to declare a configuration callback. (Not yet designed))
+ * to declare a configuration callback instead. (Not yet designed))
*
* This function MUST NOT have any parts that can fail.
**/
@@ -63,22 +71,49 @@ typedef struct subsys_fns_t {
/**
* Connect a subsystem to the message dispatch system.
+ *
+ * This function should use the macros in @refdir{lib/pubsub} to register a
+ * set of messages that this subsystem may publish, and may subscribe to.
+ *
+ * See pubsub_macros.h for more information, and for examples.
**/
int (*add_pubsub)(struct pubsub_connector_t *);
/**
* Perform any necessary pre-fork cleanup. This function may not fail.
+ *
+ * On Windows (and any other platforms without fork()), this function will
+ * never be invoked. Otherwise it is used when we are about to start
+ * running as a background daemon, or when we are about to run a unit test
+ * in a subprocess. Unlike the subsys_fns_t.postfork callback, it is run
+ * from the parent process.
+ *
+ * Note that we do not invoke this function when the child process's only
+ * purpose is to call exec() and run another program.
*/
void (*prefork)(void);
/**
* Perform any necessary post-fork setup. This function may not fail.
+ *
+ * On Windows (and any other platforms without fork()), this function will
+ * never be invoked. Otherwise it is used when we are about to start
+ * running as a background daemon, or when we are about to run a unit test
+ * in a subprocess. Unlike the subsys_fns_t.prefork callback, it is run
+ * from the child process.
+ *
+ * Note that we do not invoke this function when the child process's only
+ * purpose is to call exec() and run another program.
*/
void (*postfork)(void);
/**
* Free any thread-local resources held by this subsystem. Called before
* the thread exits.
+ *
+ * This function is not allowed to fail.
+ *
+ * \bug Note that this callback is currently buggy: See \ticket{32103}.
*/
void (*thread_cleanup)(void);
@@ -86,18 +121,28 @@ typedef struct subsys_fns_t {
* Free all resources held by this subsystem.
*
* This function is not allowed to fail.
+ *
+ * Subsystems are shut down when Tor is about to exit or return control to
+ * an embedding program. This callback must return the process to a state
+ * such that subsys_fns_t.init will succeed if invoked again.
**/
void (*shutdown)(void);
/**
* A config_format_t describing all of the torrc fields owned by this
* subsystem.
+ *
+ * This object, if present, is registered in a confmgr_t for Tor's options,
+ * and used to parse option fields from the command line and torrc file.
**/
const struct config_format_t *options_format;
/**
* A config_format_t describing all of the DataDir/state fields owned by
* this subsystem.
+ *
+ * This object, if present, is registered in a confmgr_t for Tor's state,
+ * and used to parse state fields from the DataDir/state file.
**/
const struct config_format_t *state_format;
@@ -106,7 +151,11 @@ typedef struct subsys_fns_t {
* on success, -1 on failure.
*
* It is safe to store the pointer to the object until set_options()
- * is called again. */
+ * is called again.
+ *
+ * This function is only called after all the validation code defined
+ * by subsys_fns_t.options_format has passed.
+ **/
int (*set_options)(void *);
/* XXXX Add an implementation for options_act_reversible() later in this
@@ -118,6 +167,12 @@ typedef struct subsys_fns_t {
*
* It is safe to store the pointer to the object; set_state() is only
* called on startup.
+ *
+ * This function is only called after all the validation code defined
+ * by subsys_fns_t.state_format has passed.
+ *
+ * This function will only be called once per invocation of Tor, since
+ * Tor does not reload its state while it is running.
**/
int (*set_state)(void *);
diff --git a/src/mainpage.dox b/src/mainpage.dox
index 1da074951a..e3b17cf16b 100644
--- a/src/mainpage.dox
+++ b/src/mainpage.dox
@@ -30,6 +30,8 @@ Tor repository.
@subpage intro
+@subpage initialization
+
@subpage dataflow
@subpage certificates