diff options
Diffstat (limited to 'src/lib/subsys')
-rw-r--r-- | src/lib/subsys/.may_include | 1 | ||||
-rw-r--r-- | src/lib/subsys/include.am | 4 | ||||
-rw-r--r-- | src/lib/subsys/initialization.md | 75 | ||||
-rw-r--r-- | src/lib/subsys/lib_subsys.md | 32 | ||||
-rw-r--r-- | src/lib/subsys/subsys.h | 218 |
5 files changed, 330 insertions, 0 deletions
diff --git a/src/lib/subsys/.may_include b/src/lib/subsys/.may_include new file mode 100644 index 0000000000..2b06e8519c --- /dev/null +++ b/src/lib/subsys/.may_include @@ -0,0 +1 @@ +orconfig.h diff --git a/src/lib/subsys/include.am b/src/lib/subsys/include.am new file mode 100644 index 0000000000..c9ab54ca73 --- /dev/null +++ b/src/lib/subsys/include.am @@ -0,0 +1,4 @@ + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/lib/subsys/subsys.h diff --git a/src/lib/subsys/initialization.md b/src/lib/subsys/initialization.md new file mode 100644 index 0000000000..012ab7000d --- /dev/null +++ b/src/lib/subsys/initialization.md @@ -0,0 +1,75 @@ + +@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/lib_subsys.md b/src/lib/subsys/lib_subsys.md new file mode 100644 index 0000000000..764d25d1b6 --- /dev/null +++ b/src/lib/subsys/lib_subsys.md @@ -0,0 +1,32 @@ +@dir /lib/subsys +@brief lib/subsys: Types for declaring a "subsystem". + +## Subsystems in Tor + +A subsystem is a module with support for initialization, shutdown, +configuration, and so on. + +Many parts of Tor can be initialized, cleaned up, and configured somewhat +independently through a table-driven mechanism. Each such part is called a +"subsystem". + +To declare a subsystem, make a global `const` instance of the `subsys_fns_t` +type, filling in the function pointer fields that you require with ones +corresponding to your subsystem. Any function pointers left as "NULL" will +be a no-op. Each system must have a name and a "level", which corresponds to +the order in which it is initialized. (See `app/main/subsystem_list.c` for a +list of current subsystems and their levels.) + +Then, insert your subsystem in the list in `app/main/subsystem_list.c`. It +will need to occupy a position corresponding to its level. + +At this point, your subsystem will be handled like the others: it will get +initialized at startup, torn down at exit, and so on. + +Historical note: Not all of Tor's code is currently handled as +subsystems. As you work with older code, you may see some parts of the code +that are initialized from `tor_init()` or `run_tor_main_loop()` or +`tor_run_main()`; and torn down from `tor_cleanup()`. We aim to migrate +these to subsystems over time; please don't add any new code that follows +this pattern. + diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h new file mode 100644 index 0000000000..62c0de026d --- /dev/null +++ b/src/lib/subsys/subsys.h @@ -0,0 +1,218 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file subsys.h + * @brief Types used to declare a subsystem. + **/ + +#ifndef TOR_SUBSYS_T +#define TOR_SUBSYS_T + +#include <stdbool.h> + +struct pubsub_connector_t; +struct config_format_t; + +/** + * A subsystem is a part of Tor that is initialized, shut down, configured, + * and connected to other parts of Tor. + * + * 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, 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 { + /** + * The name of this subsystem. It should be a programmer-readable + * identifier. + **/ + const char *name; + + /** + * The file in which the subsystem object is declared. Used for debugging. + **/ + const char *location; + + /** + * Whether this subsystem is supported -- that is, whether it is compiled + * into Tor. For most subsystems, this should be true. + **/ + bool supported; + + /** + * The 'initialization level' for the subsystem. It should run from -100 + * through +100. The subsystems are initialized from lowest level to + * highest, and shut down from highest level to lowest. + **/ + int level; + + /** + * Initialize any global components of this subsystem. + * + * This function MAY rely on any lower-level subsystem being initialized. + * + * This function MUST NOT rely on any runtime configuration information; + * 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 instead. (Not yet designed)) + * + * This function MUST NOT have any parts that can fail. + **/ + int (*initialize)(void); + + /** + * 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); + + /** + * 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; + + /** + * Receive an options object as defined by options_format. Return 0 + * on success, -1 on failure. + * + * It is safe to store the pointer to the object until set_options() + * 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 + * branch. */ + + /** + * Receive a state object as defined by state_format. Return 0 on success, + * -1 on failure. + * + * 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 *); + + /** + * Update any information that needs to be stored in the provided state + * object (as defined by state_format). Return 0 on success, -1 on failure. + * + * The object provided here will be the same one as provided earlier to + * set_state(). This method is called when we are about to save the state + * to disk. + **/ + int (*flush_state)(void *); +} subsys_fns_t; + +#ifndef COCCI +/** + * Macro to declare a subsystem's location. + **/ +#define SUBSYS_DECLARE_LOCATION() \ + .location = __FILE__ +#endif /* !defined(COCCI) */ + +/** + * Lowest allowed subsystem level. + **/ +#define MIN_SUBSYS_LEVEL -100 +/** + * Highest allowed subsystem level. + **/ +#define MAX_SUBSYS_LEVEL 100 + +/** + * All tor "libraries" (in src/libs) should have a subsystem level equal to or + * less than this value. + */ +#define SUBSYS_LEVEL_LIBS -10 + +#endif /* !defined(TOR_SUBSYS_T) */ |