Browse Source

Merge branch 'subsystems'

Nick Mathewson 5 years ago
parent
commit
bf4f55a13d
72 changed files with 1013 additions and 163 deletions
  1. 2 0
      .gitignore
  2. 2 0
      Makefile.am
  3. 6 0
      changes/subsystems
  4. 4 42
      src/app/config/config.c
  5. 0 2
      src/app/config/config.h
  6. 1 0
      src/app/config/statefile.c
  7. 7 75
      src/app/main/main.c
  8. 202 0
      src/app/main/subsysmgr.c
  9. 24 0
      src/app/main/subsysmgr.h
  10. 40 0
      src/app/main/subsystem_list.c
  11. 3 0
      src/core/include.am
  12. 1 0
      src/feature/control/control.c
  13. 1 0
      src/feature/dirauth/shared_random_state.c
  14. 1 0
      src/feature/relay/router.c
  15. 2 0
      src/include.am
  16. 1 0
      src/lib/compress/.may_include
  17. 20 1
      src/lib/compress/compress.c
  18. 1 1
      src/lib/compress/compress.h
  19. 14 0
      src/lib/compress/compress_sys.h
  20. 1 0
      src/lib/compress/include.am
  21. 1 0
      src/lib/crypt_ops/.may_include
  22. 47 0
      src/lib/crypt_ops/crypto_init.c
  23. 14 0
      src/lib/crypt_ops/crypto_sys.h
  24. 1 0
      src/lib/crypt_ops/include.am
  25. 2 0
      src/lib/err/.may_include
  26. 5 3
      src/lib/err/include.am
  27. 10 0
      src/lib/err/torerr.c
  28. 1 0
      src/lib/err/torerr.h
  29. 40 0
      src/lib/err/torerr_sys.c
  30. 14 0
      src/lib/err/torerr_sys.h
  31. 2 2
      src/lib/log/.may_include
  32. 2 8
      src/lib/log/include.am
  33. 2 1
      src/lib/log/log.c
  34. 35 0
      src/lib/log/log_sys.c
  35. 14 0
      src/lib/log/log_sys.h
  36. 1 0
      src/lib/net/.may_include
  37. 2 0
      src/lib/net/include.am
  38. 44 0
      src/lib/net/network_sys.c
  39. 14 0
      src/lib/net/network_sys.h
  40. 1 0
      src/lib/process/.may_include
  41. 4 2
      src/lib/process/include.am
  42. 64 0
      src/lib/process/winprocess_sys.c
  43. 14 0
      src/lib/process/winprocess_sys.h
  44. 1 0
      src/lib/subsys/.may_include
  45. 3 0
      src/lib/subsys/include.am
  46. 95 0
      src/lib/subsys/subsys.h
  47. 1 0
      src/lib/thread/.may_include
  48. 16 0
      src/lib/thread/compat_threads.c
  49. 3 2
      src/lib/thread/include.am
  50. 14 0
      src/lib/thread/thread_sys.h
  51. 1 0
      src/lib/time/.may_include
  52. 2 0
      src/lib/time/include.am
  53. 26 0
      src/lib/time/time_sys.c
  54. 14 0
      src/lib/time/time_sys.h
  55. 1 0
      src/lib/tls/.may_include
  56. 1 0
      src/lib/tls/include.am
  57. 14 0
      src/lib/tls/tortls.c
  58. 14 0
      src/lib/tls/tortls_sys.h
  59. 3 0
      src/lib/version/.may_include
  60. 1 1
      src/lib/version/git_revision.c
  61. 0 0
      src/lib/version/git_revision.h
  62. 25 0
      src/lib/version/include.am
  63. 12 0
      src/lib/version/torversion.h
  64. 50 0
      src/lib/version/version.c
  65. 1 0
      src/lib/wallclock/.may_include
  66. 16 0
      src/lib/wallclock/approx_time.c
  67. 2 1
      src/lib/wallclock/include.am
  68. 14 0
      src/lib/wallclock/wallclock_sys.h
  69. 1 0
      src/rust/build.rs
  70. 4 3
      src/test/bench.c
  71. 5 5
      src/test/fuzz/fuzzing_common.c
  72. 6 14
      src/test/testing_common.c

+ 2 - 0
.gitignore

@@ -210,6 +210,8 @@ uptime-*.json
 /src/lib/libtor-tls.a
 /src/lib/libtor-tls-testing.a
 /src/lib/libtor-trace.a
+/src/lib/libtor-version.a
+/src/lib/libtor-version-testing.a
 /src/lib/libtor-wallclock.a
 /src/lib/libtor-wallclock-testing.a
 

+ 2 - 0
Makefile.am

@@ -62,6 +62,7 @@ TOR_UTIL_LIBS = \
 	src/lib/libtor-malloc.a \
 	src/lib/libtor-wallclock.a \
 	src/lib/libtor-err.a \
+	src/lib/libtor-version.a \
 	src/lib/libtor-intmath.a \
 	src/lib/libtor-ctime.a
 
@@ -91,6 +92,7 @@ TOR_UTIL_TESTING_LIBS = \
 	src/lib/libtor-malloc-testing.a \
 	src/lib/libtor-wallclock-testing.a \
 	src/lib/libtor-err-testing.a \
+	src/lib/libtor-version-testing.a \
 	src/lib/libtor-intmath.a \
 	src/lib/libtor-ctime-testing.a
 endif

+ 6 - 0
changes/subsystems

@@ -0,0 +1,6 @@
+  o Major features (refactoring):
+    - Tor now uses an explicit list of its own subsystems when initializing
+      and shutting down.  Previously, these systems were managed implicitly
+      though various places throughout the codebase.  (There still some
+      subsystems using the old system.)
+      Closes ticket 28330.

+ 4 - 42
src/app/config/config.c

@@ -64,6 +64,7 @@
 #include "app/config/confparse.h"
 #include "app/config/statefile.h"
 #include "app/main/main.h"
+#include "app/main/subsysmgr.h"
 #include "core/mainloop/connection.h"
 #include "core/mainloop/cpuworker.h"
 #include "core/mainloop/mainloop.h"
@@ -112,9 +113,9 @@
 #include "lib/crypt_ops/crypto_rand.h"
 #include "lib/crypt_ops/crypto_util.h"
 #include "lib/encoding/confline.h"
-#include "lib/log/git_revision.h"
 #include "lib/net/resolve.h"
 #include "lib/sandbox/sandbox.h"
+#include "lib/version/torversion.h"
 
 #ifdef ENABLE_NSS
 #include "lib/crypt_ops/crypto_nss_mgt.h"
@@ -972,42 +973,6 @@ set_options(or_options_t *new_val, char **msg)
   return 0;
 }
 
-/** The version of this Tor process, as parsed. */
-static char *the_tor_version = NULL;
-/** A shorter version of this Tor process's version, for export in our router
- *  descriptor.  (Does not include the git version, if any.) */
-static char *the_short_tor_version = NULL;
-
-/** Return the current Tor version. */
-const char *
-get_version(void)
-{
-  if (the_tor_version == NULL) {
-    if (strlen(tor_git_revision)) {
-      tor_asprintf(&the_tor_version, "%s (git-%s)", get_short_version(),
-                   tor_git_revision);
-    } else {
-      the_tor_version = tor_strdup(get_short_version());
-    }
-  }
-  return the_tor_version;
-}
-
-/** Return the current Tor version, without any git tag. */
-const char *
-get_short_version(void)
-{
-
-  if (the_short_tor_version == NULL) {
-#ifdef TOR_BUILD_TAG
-    tor_asprintf(&the_short_tor_version, "%s (%s)", VERSION, TOR_BUILD_TAG);
-#else
-    the_short_tor_version = tor_strdup(VERSION);
-#endif
-  }
-  return the_short_tor_version;
-}
-
 /** Release additional memory allocated in options
  */
 STATIC void
@@ -1067,9 +1032,6 @@ config_free_all(void)
   tor_free(torrc_defaults_fname);
   tor_free(global_dirfrontpagecontents);
 
-  tor_free(the_short_tor_version);
-  tor_free(the_tor_version);
-
   cleanup_protocol_warning_severity_level();
 
   have_parsed_cmdline = 0;
@@ -1432,10 +1394,10 @@ options_act_reversible(const or_options_t *old_options, char **msg)
    * processes. */
   if (running_tor && options->RunAsDaemon) {
     if (! start_daemon_has_been_called())
-      crypto_prefork();
+      subsystems_prefork();
     /* No need to roll back, since you can't change the value. */
     if (start_daemon())
-      crypto_postfork();
+      subsystems_postfork();
   }
 
 #ifdef HAVE_SYSTEMD

+ 0 - 2
src/app/config/config.h

@@ -41,8 +41,6 @@ const char *escaped_safe_str_client(const char *address);
 const char *escaped_safe_str(const char *address);
 void init_protocol_warning_severity_level(void);
 int get_protocol_warning_severity_level(void);
-const char *get_version(void);
-const char *get_short_version(void);
 
 /** An error from options_trial_assign() or options_init_from_string(). */
 typedef enum setopt_err_t {

+ 1 - 0
src/app/config/statefile.c

@@ -45,6 +45,7 @@
 #include "app/config/statefile.h"
 #include "lib/encoding/confline.h"
 #include "lib/net/resolve.h"
+#include "lib/version/torversion.h"
 
 #include "app/config/or_state_st.h"
 

+ 7 - 75
src/app/main/main.c

@@ -15,6 +15,7 @@
 #include "app/config/statefile.h"
 #include "app/main/main.h"
 #include "app/main/ntmain.h"
+#include "app/main/subsysmgr.h"
 #include "core/mainloop/connection.h"
 #include "core/mainloop/cpuworker.h"
 #include "core/mainloop/mainloop.h"
@@ -69,7 +70,6 @@
 #include "lib/container/buffers.h"
 #include "lib/crypt_ops/crypto_rand.h"
 #include "lib/crypt_ops/crypto_s2k.h"
-#include "lib/err/backtrace.h"
 #include "lib/geoip/geoip.h"
 
 #include "lib/process/waitpid.h"
@@ -84,6 +84,7 @@
 #include "lib/encoding/confline.h"
 #include "lib/evloop/timers.h"
 #include "lib/crypt_ops/crypto_init.h"
+#include "lib/version/torversion.h"
 
 #include <event2/event.h>
 
@@ -427,18 +428,6 @@ dumpstats(int severity)
   rend_service_dump_stats(severity);
 }
 
-/** Called by exit() as we shut down the process.
- */
-static void
-exit_function(void)
-{
-  /* NOTE: If we ever daemonize, this gets called immediately.  That's
-   * okay for now, because we only use this on Windows.  */
-#ifdef _WIN32
-  WSACleanup();
-#endif
-}
-
 #ifdef _WIN32
 #define UNIX_ONLY 0
 #else
@@ -547,12 +536,6 @@ tor_init(int argc, char *argv[])
   tor_snprintf(progname, sizeof(progname), "Tor %s", get_version());
   log_set_application_name(progname);
 
-  /* Set up the crypto nice and early */
-  if (crypto_early_init() < 0) {
-    log_err(LD_GENERAL, "Unable to initialize the crypto subsystem!");
-    return -1;
-  }
-
   /* Initialize the history structures. */
   rep_hist_init();
   /* Initialize the service cache. */
@@ -632,12 +615,6 @@ tor_init(int argc, char *argv[])
   rust_log_welcome_string();
 #endif /* defined(HAVE_RUST) */
 
-  if (network_init()<0) {
-    log_err(LD_BUG,"Error initializing network; exiting.");
-    return -1;
-  }
-  atexit(exit_function);
-
   int init_rv = options_init_from_torrc(argc,argv);
   if (init_rv < 0) {
     log_err(LD_CONFIG,"Reading config failed--see warnings above.");
@@ -784,7 +761,6 @@ tor_free_all(int postfork)
   routerparse_free_all();
   ext_orport_free_all();
   control_free_all();
-  tor_free_getaddrinfo_cache();
   protover_free_all();
   bridges_free_all();
   consdiffmgr_free_all();
@@ -802,7 +778,6 @@ tor_free_all(int postfork)
     policies_free_all();
   }
   if (!postfork) {
-    tor_tls_free_all();
 #ifndef _WIN32
     tor_getpwnam(NULL);
 #endif
@@ -815,12 +790,12 @@ tor_free_all(int postfork)
     release_lockfile();
   }
   tor_libevent_free_all();
+
+  subsystems_shutdown();
+
   /* Stuff in util.c and address.c*/
   if (!postfork) {
-    escaped(NULL);
     esc_router_info(NULL);
-    clean_up_backtrace_handler();
-    logs_free_all(); /* free log strings. do this last so logs keep working. */
   }
 }
 
@@ -879,7 +854,6 @@ tor_cleanup(void)
                       later, if it makes shutdown unacceptably slow.  But for
                       now, leave it here: it's helped us catch bugs in the
                       past. */
-  crypto_global_cleanup();
 }
 
 /** Read/create keys as needed, and echo our fingerprint to stdout. */
@@ -1275,7 +1249,6 @@ static int
 run_tor_main_loop(void)
 {
   handle_signals();
-  monotime_init();
   timers_initialize();
   initialize_mainloop_events();
 
@@ -1387,54 +1360,13 @@ tor_run_main(const tor_main_configuration_t *tor_cfg)
 {
   int result = 0;
 
-#ifdef _WIN32
-#ifndef HeapEnableTerminationOnCorruption
-#define HeapEnableTerminationOnCorruption 1
-#endif
-  /* On heap corruption, just give up; don't try to play along. */
-  HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
-
-  /* SetProcessDEPPolicy is only supported on 32-bit Windows.
-   * (On 64-bit Windows it always fails, and some compilers don't like the
-   * PSETDEP cast.)
-   * 32-bit Windows defines _WIN32.
-   * 64-bit Windows defines _WIN32 and _WIN64. */
-#ifndef _WIN64
-  /* Call SetProcessDEPPolicy to permanently enable DEP.
-     The function will not resolve on earlier versions of Windows,
-     and failure is not dangerous. */
-  HMODULE hMod = GetModuleHandleA("Kernel32.dll");
-  if (hMod) {
-    typedef BOOL (WINAPI *PSETDEP)(DWORD);
-    PSETDEP setdeppolicy = (PSETDEP)GetProcAddress(hMod,
-                           "SetProcessDEPPolicy");
-    if (setdeppolicy) {
-      /* PROCESS_DEP_ENABLE | PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION */
-      setdeppolicy(3);
-    }
-  }
-#endif /* !defined(_WIN64) */
-#endif /* defined(_WIN32) */
-
-  {
-    int bt_err = configure_backtrace_handler(get_version());
-    if (bt_err < 0) {
-      log_warn(LD_BUG, "Unable to install backtrace handler: %s",
-               strerror(-bt_err));
-    }
-  }
-
 #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
   event_set_mem_functions(tor_malloc_, tor_realloc_, tor_free_);
 #endif
 
-  init_protocol_warning_severity_level();
+  subsystems_init();
 
-  update_approx_time(time(NULL));
-  tor_threads_init();
-  tor_compress_init();
-  init_logging(0);
-  monotime_init();
+  init_protocol_warning_severity_level();
 
   int argc = tor_cfg->argc + tor_cfg->argc_owned;
   char **argv = tor_calloc(argc, sizeof(char*));

+ 202 - 0
src/app/main/subsysmgr.c

@@ -0,0 +1,202 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "app/main/subsysmgr.h"
+#include "lib/err/torerr.h"
+
+#include "lib/log/log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * True iff we have checked tor_subsystems for consistency.
+ **/
+static bool subsystem_array_validated = false;
+
+/**
+ * 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];
+
+/**
+ * Exit with a raw assertion if the subsystems list is inconsistent;
+ * initialize the subsystem_initialized array.
+ **/
+static void
+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));
+
+  int last_level = MIN_SUBSYS_LEVEL;
+
+  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+    const subsys_fns_t *sys = tor_subsystems[i];
+    if (sys->level < MIN_SUBSYS_LEVEL || sys->level > MAX_SUBSYS_LEVEL) {
+      fprintf(stderr, "BUG: Subsystem %s (at %u) has an invalid level %d. "
+              "It is supposed to be between %d and %d (inclusive).\n",
+              sys->name, i, sys->level, MIN_SUBSYS_LEVEL, MAX_SUBSYS_LEVEL);
+      raw_assert_unreached_msg("There is a bug in subsystem_list.c");
+    }
+    if (sys->level < last_level) {
+      fprintf(stderr, "BUG: Subsystem %s (at #%u) is in the wrong position. "
+              "Its level is %d; but the previous subsystem's level was %d.\n",
+              sys->name, i, sys->level, last_level);
+      raw_assert_unreached_msg("There is a bug in subsystem_list.c");
+    }
+    last_level = sys->level;
+  }
+
+  subsystem_array_validated = true;
+}
+
+/**
+ * Initialize all the subsystems; exit on failure.
+ **/
+int
+subsystems_init(void)
+{
+  return subsystems_init_upto(MAX_SUBSYS_LEVEL);
+}
+
+/**
+ * Initialize all the subsystems whose level is less than or equal to
+ * <b>target_level</b>; exit on failure.
+ **/
+int
+subsystems_init_upto(int target_level)
+{
+  check_and_setup();
+
+  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+    const subsys_fns_t *sys = tor_subsystems[i];
+    if (!sys->supported)
+      continue;
+    if (sys->level > target_level)
+      break;
+    if (sys_initialized[i])
+      continue;
+    int r = 0;
+    if (sys->initialize) {
+      // Note that the logging subsystem is designed so that it does no harm
+      // to log a message in an uninitialized state.  These messages will be
+      // discarded for now, however.
+      log_debug(LD_GENERAL, "Initializing %s", sys->name);
+      r = sys->initialize();
+    }
+    if (r < 0) {
+      fprintf(stderr, "BUG: subsystem %s (at %u) initialization failed.\n",
+              sys->name, i);
+      raw_assert_unreached_msg("A subsystem couldn't be initialized.");
+    }
+    sys_initialized[i] = true;
+  }
+
+  return 0;
+}
+
+/**
+ * Shut down all the subsystems.
+ **/
+void
+subsystems_shutdown(void)
+{
+  subsystems_shutdown_downto(MIN_SUBSYS_LEVEL - 1);
+}
+
+/**
+ * Shut down all the subsystems whose level is above <b>target_level</b>.
+ **/
+void
+subsystems_shutdown_downto(int target_level)
+{
+  check_and_setup();
+
+  for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) {
+    const subsys_fns_t *sys = tor_subsystems[i];
+    if (!sys->supported)
+      continue;
+    if (sys->level <= target_level)
+      break;
+    if (! sys_initialized[i])
+      continue;
+    if (sys->shutdown) {
+      log_debug(LD_GENERAL, "Shutting down %s", sys->name);
+      sys->shutdown();
+    }
+    sys_initialized[i] = false;
+  }
+}
+
+/**
+ * Run pre-fork code on all subsystems that declare any
+ **/
+void
+subsystems_prefork(void)
+{
+  check_and_setup();
+
+  for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) {
+    const subsys_fns_t *sys = tor_subsystems[i];
+    if (!sys->supported)
+      continue;
+    if (! sys_initialized[i])
+      continue;
+    if (sys->prefork) {
+      log_debug(LD_GENERAL, "Pre-fork: %s", sys->name);
+      sys->prefork();
+    }
+  }
+}
+
+/**
+ * Run post-fork code on all subsystems that declare any
+ **/
+void
+subsystems_postfork(void)
+{
+  check_and_setup();
+
+  for (unsigned i = 0; i < n_tor_subsystems; ++i) {
+    const subsys_fns_t *sys = tor_subsystems[i];
+    if (!sys->supported)
+      continue;
+    if (! sys_initialized[i])
+      continue;
+    if (sys->postfork) {
+      log_debug(LD_GENERAL, "Post-fork: %s", sys->name);
+      sys->postfork();
+    }
+  }
+}
+
+/**
+ * Run thread-cleanup code on all subsystems that declare any
+ **/
+void
+subsystems_thread_cleanup(void)
+{
+  check_and_setup();
+
+  for (int i = (int)n_tor_subsystems - 1; i >= 0; --i) {
+    const subsys_fns_t *sys = tor_subsystems[i];
+    if (!sys->supported)
+      continue;
+    if (! sys_initialized[i])
+      continue;
+    if (sys->thread_cleanup) {
+      log_debug(LD_GENERAL, "Thread cleanup: %s", sys->name);
+      sys->thread_cleanup();
+    }
+  }
+}

+ 24 - 0
src/app/main/subsysmgr.h

@@ -0,0 +1,24 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_SUBSYSMGR_T
+#define TOR_SUBSYSMGR_T
+
+#include "lib/subsys/subsys.h"
+
+extern const struct subsys_fns_t *tor_subsystems[];
+extern const unsigned n_tor_subsystems;
+
+int subsystems_init(void);
+int subsystems_init_upto(int level);
+
+void subsystems_shutdown(void);
+void subsystems_shutdown_downto(int level);
+
+void subsystems_prefork(void);
+void subsystems_postfork(void);
+void subsystems_thread_cleanup(void);
+
+#endif

+ 40 - 0
src/app/main/subsystem_list.c

@@ -0,0 +1,40 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "app/main/subsysmgr.h"
+#include "lib/cc/compat_compiler.h"
+#include "lib/cc/torint.h"
+
+#include "lib/compress/compress_sys.h"
+#include "lib/crypt_ops/crypto_sys.h"
+#include "lib/err/torerr_sys.h"
+#include "lib/log/log_sys.h"
+#include "lib/net/network_sys.h"
+#include "lib/process/winprocess_sys.h"
+#include "lib/thread/thread_sys.h"
+#include "lib/time/time_sys.h"
+#include "lib/tls/tortls_sys.h"
+#include "lib/wallclock/wallclock_sys.h"
+
+#include <stddef.h>
+
+/**
+ * Global list of the subsystems in Tor, in the order of their initialization.
+ **/
+const subsys_fns_t *tor_subsystems[] = {
+  &sys_winprocess, /* -100 */
+  &sys_torerr,
+  &sys_wallclock,
+  &sys_threads,
+  &sys_logging,
+  &sys_time,
+  &sys_network,
+  &sys_compress,
+  &sys_crypto,
+  &sys_tortls,
+};
+
+const unsigned n_tor_subsystems = ARRAY_LENGTH(tor_subsystems);

+ 3 - 0
src/core/include.am

@@ -11,6 +11,8 @@ LIBTOR_APP_A_SOURCES = 				\
 	src/app/config/confparse.c		\
 	src/app/config/statefile.c		\
 	src/app/main/main.c			\
+	src/app/main/subsystem_list.c		\
+	src/app/main/subsysmgr.c		\
 	src/core/crypto/hs_ntor.c		\
 	src/core/crypto/onion_crypto.c		\
 	src/core/crypto/onion_fast.c		\
@@ -191,6 +193,7 @@ noinst_HEADERS +=					\
 	src/app/config/statefile.h			\
 	src/app/main/main.h				\
 	src/app/main/ntmain.h				\
+	src/app/main/subsysmgr.h			\
 	src/core/crypto/hs_ntor.h			\
 	src/core/crypto/onion_crypto.h	        	\
 	src/core/crypto/onion_fast.h			\

+ 1 - 0
src/feature/control/control.c

@@ -92,6 +92,7 @@
 #include "lib/crypt_ops/crypto_util.h"
 #include "lib/encoding/confline.h"
 #include "lib/evloop/compat_libevent.h"
+#include "lib/version/torversion.h"
 
 #include "feature/dircache/cached_dir_st.h"
 #include "feature/control/control_connection_st.h"

+ 1 - 0
src/feature/dirauth/shared_random_state.c

@@ -22,6 +22,7 @@
 #include "feature/dirauth/shared_random_state.h"
 #include "feature/dircommon/voting_schedule.h"
 #include "lib/encoding/confline.h"
+#include "lib/version/torversion.h"
 
 #include "app/config/or_state_st.h"
 

+ 1 - 0
src/feature/relay/router.c

@@ -49,6 +49,7 @@
 #include "lib/encoding/confline.h"
 #include "lib/osinfo/uname.h"
 #include "lib/tls/tortls.h"
+#include "lib/version/torversion.h"
 
 #include "feature/dirauth/authmode.h"
 

+ 2 - 0
src/include.am

@@ -25,6 +25,7 @@ include src/lib/osinfo/include.am
 include src/lib/process/include.am
 include src/lib/sandbox/include.am
 include src/lib/string/include.am
+include src/lib/subsys/include.am
 include src/lib/smartlist_core/include.am
 include src/lib/term/include.am
 include src/lib/testsupport/include.am
@@ -32,6 +33,7 @@ include src/lib/thread/include.am
 include src/lib/time/include.am
 include src/lib/tls/include.am
 include src/lib/trace/include.am
+include src/lib/version/include.am
 include src/lib/wallclock/include.am
 include src/trunnel/include.am
 

+ 1 - 0
src/lib/compress/.may_include

@@ -8,5 +8,6 @@ lib/intmath/*.h
 lib/log/*.h
 lib/malloc/*.h
 lib/string/*.h
+lib/subsys/*.h
 lib/testsupport/*.h
 lib/thread/*.h

+ 20 - 1
src/lib/compress/compress.c

@@ -29,10 +29,12 @@
 #include "lib/compress/compress.h"
 #include "lib/compress/compress_lzma.h"
 #include "lib/compress/compress_none.h"
+#include "lib/compress/compress_sys.h"
 #include "lib/compress/compress_zlib.h"
 #include "lib/compress/compress_zstd.h"
 #include "lib/intmath/cmp.h"
 #include "lib/malloc/malloc.h"
+#include "lib/subsys/subsys.h"
 #include "lib/thread/threads.h"
 
 /** Total number of bytes allocated for compression state overhead. */
@@ -660,7 +662,7 @@ tor_compress_state_size(const tor_compress_state_t *state)
 }
 
 /** Initialize all compression modules. */
-void
+int
 tor_compress_init(void)
 {
   atomic_counter_init(&total_compress_allocation);
@@ -668,6 +670,8 @@ tor_compress_init(void)
   tor_zlib_init();
   tor_lzma_init();
   tor_zstd_init();
+
+  return 0;
 }
 
 /** Warn if we had any problems while setting up our compression libraries.
@@ -677,5 +681,20 @@ tor_compress_init(void)
 void
 tor_compress_log_init_warnings(void)
 {
+  // XXXX can we move this into tor_compress_init() after all?  log.c queues
+  // XXXX log messages at startup.
   tor_zstd_warn_if_version_mismatched();
 }
+
+static int
+subsys_compress_initialize(void)
+{
+  return tor_compress_init();
+}
+
+const subsys_fns_t sys_compress = {
+  .name = "compress",
+  .supported = true,
+  .level = -70,
+  .initialize = subsys_compress_initialize,
+};

+ 1 - 1
src/lib/compress/compress.h

@@ -89,7 +89,7 @@ void tor_compress_free_(tor_compress_state_t *state);
 
 size_t tor_compress_state_size(const tor_compress_state_t *state);
 
-void tor_compress_init(void);
+int tor_compress_init(void);
 void tor_compress_log_init_warnings(void);
 
 struct buf_t;

+ 14 - 0
src/lib/compress/compress_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file compress_sys.h
+ * \brief Declare subsystem object for the compress module
+ **/
+
+#ifndef TOR_COMPRESS_SYS_H
+#define TOR_COMPRESS_SYS_H
+
+extern const struct subsys_fns_t sys_compress;
+
+#endif /* !defined(TOR_COMPRESS_SYS_H) */

+ 1 - 0
src/lib/compress/include.am

@@ -22,5 +22,6 @@ noinst_HEADERS	+=				\
 	src/lib/compress/compress.h		\
 	src/lib/compress/compress_lzma.h	\
 	src/lib/compress/compress_none.h	\
+	src/lib/compress/compress_sys.h		\
 	src/lib/compress/compress_zlib.h	\
 	src/lib/compress/compress_zstd.h

+ 1 - 0
src/lib/crypt_ops/.may_include

@@ -12,6 +12,7 @@ lib/malloc/*.h
 lib/intmath/*.h
 lib/sandbox/*.h
 lib/string/*.h
+lib/subsys/*.h
 lib/testsupport/testsupport.h
 lib/thread/*.h
 lib/log/*.h

+ 47 - 0
src/lib/crypt_ops/crypto_init.c

@@ -20,6 +20,9 @@
 #include "lib/crypt_ops/crypto_openssl_mgt.h"
 #include "lib/crypt_ops/crypto_nss_mgt.h"
 #include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_sys.h"
+
+#include "lib/subsys/subsys.h"
 
 #include "siphash.h"
 
@@ -202,3 +205,47 @@ tor_is_using_nss(void)
   return 0;
 #endif
 }
+
+static int
+subsys_crypto_initialize(void)
+{
+  if (crypto_early_init() < 0)
+    return -1;
+  crypto_dh_init();
+  return 0;
+}
+
+static void
+subsys_crypto_shutdown(void)
+{
+  crypto_global_cleanup();
+}
+
+static void
+subsys_crypto_prefork(void)
+{
+  crypto_prefork();
+}
+
+static void
+subsys_crypto_postfork(void)
+{
+  crypto_postfork();
+}
+
+static void
+subsys_crypto_thread_cleanup(void)
+{
+  crypto_thread_cleanup();
+}
+
+const struct subsys_fns_t sys_crypto = {
+  .name = "crypto",
+  .supported = true,
+  .level = -60,
+  .initialize = subsys_crypto_initialize,
+  .shutdown = subsys_crypto_shutdown,
+  .prefork = subsys_crypto_prefork,
+  .postfork = subsys_crypto_postfork,
+  .thread_cleanup = subsys_crypto_thread_cleanup,
+};

+ 14 - 0
src/lib/crypt_ops/crypto_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_crypto.h
+ * \brief Declare subsystem object for the crypto module.
+ **/
+
+#ifndef TOR_CRYPTO_SYS_H
+#define TOR_CRYPTO_SYS_H
+
+extern const struct subsys_fns_t sys_crypto;
+
+#endif /* !defined(TOR_CRYPTO_SYS_H) */

+ 1 - 0
src/lib/crypt_ops/include.am

@@ -66,5 +66,6 @@ noinst_HEADERS +=					\
 	src/lib/crypt_ops/crypto_rand.h			\
 	src/lib/crypt_ops/crypto_rsa.h			\
 	src/lib/crypt_ops/crypto_s2k.h			\
+	src/lib/crypt_ops/crypto_sys.h			\
 	src/lib/crypt_ops/crypto_util.h                 \
 	src/lib/crypt_ops/digestset.h

+ 2 - 0
src/lib/err/.may_include

@@ -1,3 +1,5 @@
 orconfig.h
 lib/cc/*.h
 lib/err/*.h
+lib/subsys/*.h
+lib/version/*.h

+ 5 - 3
src/lib/err/include.am

@@ -6,8 +6,9 @@ noinst_LIBRARIES += src/lib/libtor-err-testing.a
 endif
 
 src_lib_libtor_err_a_SOURCES =			\
-	src/lib/err/backtrace.c				\
-	src/lib/err/torerr.c
+	src/lib/err/backtrace.c			\
+	src/lib/err/torerr.c			\
+	src/lib/err/torerr_sys.c
 
 src_lib_libtor_err_testing_a_SOURCES = \
 	$(src_lib_libtor_err_a_SOURCES)
@@ -16,4 +17,5 @@ src_lib_libtor_err_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
 noinst_HEADERS +=					\
 	src/lib/err/backtrace.h				\
-	src/lib/err/torerr.h
+	src/lib/err/torerr.h				\
+	src/lib/err/torerr_sys.h

+ 10 - 0
src/lib/err/torerr.c

@@ -122,6 +122,16 @@ tor_log_set_sigsafe_err_fds(const int *fds, int n)
   n_sigsafe_log_fds = n;
 }
 
+/**
+ * Reset the list of emergency error fds to its default.
+ */
+void
+tor_log_reset_sigsafe_err_fds(void)
+{
+  int fds[] = { STDERR_FILENO };
+  tor_log_set_sigsafe_err_fds(fds, 1);
+}
+
 /**
  * Set the granularity (in ms) to use when reporting fatal errors outside
  * the logging system.

+ 1 - 0
src/lib/err/torerr.h

@@ -39,6 +39,7 @@ void tor_raw_assertion_failed_msg_(const char *file, int line,
 void tor_log_err_sigsafe(const char *m, ...);
 int tor_log_get_sigsafe_err_fds(const int **out);
 void tor_log_set_sigsafe_err_fds(const int *fds, int n);
+void tor_log_reset_sigsafe_err_fds(void);
 void tor_log_sigsafe_err_set_granularity(int ms);
 
 int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len);

+ 40 - 0
src/lib/err/torerr_sys.c

@@ -0,0 +1,40 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file torerr_sys.c
+ * \brief Subsystem object for the error handling subsystem.
+ **/
+
+#include "orconfig.h"
+#include "lib/err/backtrace.h"
+#include "lib/err/torerr.h"
+#include "lib/err/torerr_sys.h"
+#include "lib/subsys/subsys.h"
+#include "lib/version/torversion.h"
+
+#include <stddef.h>
+
+static int
+subsys_torerr_initialize(void)
+{
+  if (configure_backtrace_handler(get_version()) < 0)
+    return -1;
+  tor_log_reset_sigsafe_err_fds();
+
+  return 0;
+}
+static void
+subsys_torerr_shutdown(void)
+{
+  tor_log_reset_sigsafe_err_fds();
+  clean_up_backtrace_handler();
+}
+
+const subsys_fns_t sys_torerr = {
+  .name = "err",
+  .level = -100,
+  .supported = true,
+  .initialize = subsys_torerr_initialize,
+  .shutdown = subsys_torerr_shutdown
+};

+ 14 - 0
src/lib/err/torerr_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file torerr_sys.h
+ * \brief Declare subsystem object for torerr.c
+ **/
+
+#ifndef TOR_TORERR_SYS_H
+#define TOR_TORERR_SYS_H
+
+extern const struct subsys_fns_t sys_torerr;
+
+#endif /* !defined(TOR_TORERR_SYS_H) */

+ 2 - 2
src/lib/log/.may_include

@@ -9,7 +9,7 @@ lib/lock/*.h
 lib/log/*.h
 lib/malloc/*.h
 lib/string/*.h
+lib/subsys/*.h
 lib/testsupport/*.h
+lib/version/*.h
 lib/wallclock/*.h
-
-micro-revision.i

+ 2 - 8
src/lib/log/include.am

@@ -7,9 +7,9 @@ endif
 
 src_lib_libtor_log_a_SOURCES =			\
 	src/lib/log/escape.c			\
-        src/lib/log/git_revision.c              \
 	src/lib/log/ratelim.c			\
 	src/lib/log/log.c			\
+	src/lib/log/log_sys.c			\
 	src/lib/log/util_bug.c
 
 if WIN32
@@ -21,16 +21,10 @@ src_lib_libtor_log_testing_a_SOURCES = \
 src_lib_libtor_log_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
 src_lib_libtor_log_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
-# Declare that these object files depend on micro-revision.i.  Without this
-# rule, we could try to build them before micro-revision.i was created.
-src/lib/log/git_revision.$(OBJEXT) \
-  src/lib/log/src_lib_libtor_log_testing_a-git_revision.$(OBJEXT): \
-	micro-revision.i
-
 noinst_HEADERS +=					\
 	src/lib/log/escape.h				\
-        src/lib/log/git_revision.h                      \
 	src/lib/log/ratelim.h				\
 	src/lib/log/log.h				\
+	src/lib/log/log_sys.h				\
 	src/lib/log/util_bug.h				\
 	src/lib/log/win32err.h

+ 2 - 1
src/lib/log/log.c

@@ -32,7 +32,8 @@
 
 #define LOG_PRIVATE
 #include "lib/log/log.h"
-#include "lib/log/git_revision.h"
+#include "lib/log/log_sys.h"
+#include "lib/version/git_revision.h"
 #include "lib/log/ratelim.h"
 #include "lib/lock/compat_mutex.h"
 #include "lib/smartlist_core/smartlist_core.h"

+ 35 - 0
src/lib/log/log_sys.c

@@ -0,0 +1,35 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_sys.c
+ * \brief Setup and tear down the logging module.
+ **/
+
+#include "orconfig.h"
+#include "lib/subsys/subsys.h"
+#include "lib/log/escape.h"
+#include "lib/log/log.h"
+#include "lib/log/log_sys.h"
+
+static int
+subsys_logging_initialize(void)
+{
+  init_logging(0);
+  return 0;
+}
+
+static void
+subsys_logging_shutdown(void)
+{
+  logs_free_all();
+  escaped(NULL);
+}
+
+const subsys_fns_t sys_logging = {
+  .name = "log",
+  .supported = true,
+  .level = -90,
+  .initialize = subsys_logging_initialize,
+  .shutdown = subsys_logging_shutdown,
+};

+ 14 - 0
src/lib/log/log_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_sys.h
+ * \brief Declare subsystem object for the logging module.
+ **/
+
+#ifndef TOR_LOG_SYS_H
+#define TOR_LOG_SYS_H
+
+extern const struct subsys_fns_t sys_logging;
+
+#endif /* !defined(TOR_LOG_SYS_H) */

+ 1 - 0
src/lib/net/.may_include

@@ -11,5 +11,6 @@ lib/lock/*.h
 lib/log/*.h
 lib/net/*.h
 lib/string/*.h
+lib/subsys/*.h
 lib/testsupport/*.h
 lib/malloc/*.h

+ 2 - 0
src/lib/net/include.am

@@ -11,6 +11,7 @@ src_lib_libtor_net_a_SOURCES =			\
 	src/lib/net/buffers_net.c		\
 	src/lib/net/gethostname.c		\
 	src/lib/net/inaddr.c			\
+	src/lib/net/network_sys.c		\
 	src/lib/net/resolve.c			\
 	src/lib/net/socket.c			\
 	src/lib/net/socketpair.c
@@ -28,6 +29,7 @@ noinst_HEADERS +=				\
 	src/lib/net/inaddr.h			\
 	src/lib/net/inaddr_st.h			\
 	src/lib/net/nettypes.h			\
+	src/lib/net/network_sys.h		\
 	src/lib/net/resolve.h			\
 	src/lib/net/socket.h			\
 	src/lib/net/socketpair.h		\

+ 44 - 0
src/lib/net/network_sys.c

@@ -0,0 +1,44 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file network_sys.c
+ * \brief Subsystem object for networking setup.
+ **/
+
+#include "orconfig.h"
+#include "lib/subsys/subsys.h"
+#include "lib/net/network_sys.h"
+#include "lib/net/resolve.h"
+#include "lib/net/socket.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+static int
+subsys_network_initialize(void)
+{
+  if (network_init() < 0)
+    return -1;
+
+  return 0;
+}
+
+static void
+subsys_network_shutdown(void)
+{
+#ifdef _WIN32
+  WSACleanup();
+#endif
+  tor_free_getaddrinfo_cache();
+}
+
+const subsys_fns_t sys_network = {
+  .name = "network",
+  .level = -90,
+  .supported = true,
+  .initialize = subsys_network_initialize,
+  .shutdown = subsys_network_shutdown,
+};

+ 14 - 0
src/lib/net/network_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_network.h
+ * \brief Declare subsystem object for the network module.
+ **/
+
+#ifndef TOR_NETWORK_SYS_H
+#define TOR_NETWORK_SYS_H
+
+extern const struct subsys_fns_t sys_network;
+
+#endif /* !defined(TOR_NETWORK_SYS_H) */

+ 1 - 0
src/lib/process/.may_include

@@ -11,6 +11,7 @@ lib/malloc/*.h
 lib/net/*.h
 lib/process/*.h
 lib/string/*.h
+lib/subsys/*.h
 lib/testsupport/*.h
 lib/thread/*.h
 

+ 4 - 2
src/lib/process/include.am

@@ -12,7 +12,8 @@ src_lib_libtor_process_a_SOURCES =		\
 	src/lib/process/restrict.c		\
 	src/lib/process/setuid.c		\
 	src/lib/process/subprocess.c		\
-	src/lib/process/waitpid.c
+	src/lib/process/waitpid.c		\
+	src/lib/process/winprocess_sys.c
 
 src_lib_libtor_process_testing_a_SOURCES = \
 	$(src_lib_libtor_process_a_SOURCES)
@@ -26,4 +27,5 @@ noinst_HEADERS +=				\
 	src/lib/process/restrict.h		\
 	src/lib/process/setuid.h		\
 	src/lib/process/subprocess.h		\
-	src/lib/process/waitpid.h
+	src/lib/process/waitpid.h		\
+	src/lib/process/winprocess_sys.h

+ 64 - 0
src/lib/process/winprocess_sys.c

@@ -0,0 +1,64 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file winprocess_sys.c
+ * \brief Subsystem object for windows process setup.
+ **/
+
+#include "orconfig.h"
+#include "lib/subsys/subsys.h"
+#include "lib/process/winprocess_sys.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef _WIN32
+#include <windows.h>
+
+#define WINPROCESS_SYS_ENABLED true
+
+static int
+subsys_winprocess_initialize(void)
+{
+#ifndef HeapEnableTerminationOnCorruption
+#define HeapEnableTerminationOnCorruption 1
+#endif
+
+  /* On heap corruption, just give up; don't try to play along. */
+  HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
+
+  /* SetProcessDEPPolicy is only supported on 32-bit Windows.
+   * (On 64-bit Windows it always fails, and some compilers don't like the
+   * PSETDEP cast.)
+   * 32-bit Windows defines _WIN32.
+   * 64-bit Windows defines _WIN32 and _WIN64. */
+#ifndef _WIN64
+  /* Call SetProcessDEPPolicy to permanently enable DEP.
+     The function will not resolve on earlier versions of Windows,
+     and failure is not dangerous. */
+  HMODULE hMod = GetModuleHandleA("Kernel32.dll");
+  if (hMod) {
+    typedef BOOL (WINAPI *PSETDEP)(DWORD);
+    PSETDEP setdeppolicy = (PSETDEP)GetProcAddress(hMod,
+                           "SetProcessDEPPolicy");
+    if (setdeppolicy) {
+      /* PROCESS_DEP_ENABLE | PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION */
+      setdeppolicy(3);
+    }
+  }
+#endif /* !defined(_WIN64) */
+
+  return 0;
+}
+#else  /* !defined(_WIN32) */
+#define WINPROCESS_SYS_ENABLED false
+#define subsys_winprocess_initialize NULL
+#endif /* defined(_WIN32) */
+
+const subsys_fns_t sys_winprocess = {
+  .name = "winprocess",
+  .level = -100,
+  .supported = WINPROCESS_SYS_ENABLED,
+  .initialize = subsys_winprocess_initialize,
+};

+ 14 - 0
src/lib/process/winprocess_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file winprocess_sys.h
+ * \brief Declare subsystem object for winprocess.c
+ **/
+
+#ifndef TOR_WINPROCESS_SYS_H
+#define TOR_WINPROCESS_SYS_H
+
+extern const struct subsys_fns_t sys_winprocess;
+
+#endif /* !defined(TOR_WINPROCESS_SYS_H) */

+ 1 - 0
src/lib/subsys/.may_include

@@ -0,0 +1 @@
+orconfig.h

+ 3 - 0
src/lib/subsys/include.am

@@ -0,0 +1,3 @@
+
+noinst_HEADERS += \
+	src/lib/subsys/subsys.h

+ 95 - 0
src/lib/subsys/subsys.h

@@ -0,0 +1,95 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_SUBSYS_T
+#define TOR_SUBSYS_T
+
+#include <stdbool.h>
+
+struct dispatch_connector_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: we
+ * will be adding more fields, often in the middle of the structure.
+ **/
+typedef struct subsys_fns_t {
+  /**
+   * The name of this subsystem.  It should be a programmer-readable
+   * identifier.
+   **/
+  const char *name;
+
+  /**
+   * 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. (Not yet designed))
+   *
+   * This function MUST NOT have any parts that can fail.
+   **/
+  int (*initialize)(void);
+
+  /**
+   * Connect a subsystem to the message dispatch system.
+   **/
+  int (*add_pubsub)(struct dispatch_connector_t *);
+
+  /**
+   * Perform any necessary pre-fork cleanup.  This function may not fail.
+   */
+  void (*prefork)(void);
+
+  /**
+   * Perform any necessary post-fork setup. This function may not fail.
+   */
+  void (*postfork)(void);
+
+  /**
+   * Free any thread-local resources held by this subsystem. Called before
+   * the thread exits.
+   */
+  void (*thread_cleanup)(void);
+
+  /**
+   * Free all resources held by this subsystem.
+   *
+   * This function is not allowed to fail.
+   **/
+  void (*shutdown)(void);
+
+} subsys_fns_t;
+
+#define MIN_SUBSYS_LEVEL -100
+#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

+ 1 - 0
src/lib/thread/.may_include

@@ -2,6 +2,7 @@ orconfig.h
 lib/cc/*.h
 lib/lock/*.h
 lib/log/*.h
+lib/subsys/*.h
 lib/testsupport/*.h
 lib/thread/*.h
 lib/wallclock/*.h

+ 16 - 0
src/lib/thread/compat_threads.c

@@ -14,9 +14,11 @@
 #include "orconfig.h"
 #include <stdlib.h>
 #include "lib/thread/threads.h"
+#include "lib/thread/thread_sys.h"
 
 #include "lib/log/log.h"
 #include "lib/log/util_bug.h"
+#include "lib/subsys/subsys.h"
 
 #include <string.h>
 
@@ -109,3 +111,17 @@ atomic_counter_exchange(atomic_counter_t *counter, size_t newval)
   return oldval;
 }
 #endif /* !defined(HAVE_WORKING_STDATOMIC) */
+
+static int
+subsys_threads_initialize(void)
+{
+  tor_threads_init();
+  return 0;
+}
+
+const subsys_fns_t sys_threads = {
+  .name = "threads",
+  .supported = true,
+  .level = -95,
+  .initialize = subsys_threads_initialize,
+};

+ 3 - 2
src/lib/thread/include.am

@@ -23,5 +23,6 @@ src_lib_libtor_thread_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
 src_lib_libtor_thread_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
 noinst_HEADERS +=					\
-	src/lib/thread/threads.h			\
-	src/lib/thread/numcpus.h
+	src/lib/thread/numcpus.h			\
+	src/lib/thread/thread_sys.h			\
+	src/lib/thread/threads.h

+ 14 - 0
src/lib/thread/thread_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file threads_sys.h
+ * \brief Declare subsystem object for threads library
+ **/
+
+#ifndef TOR_THREADS_SYS_H
+#define TOR_THREADS_SYS_H
+
+extern const struct subsys_fns_t sys_threads;
+
+#endif /* !defined(TOR_THREADS_SYS_H) */

+ 1 - 0
src/lib/time/.may_include

@@ -4,6 +4,7 @@ lib/cc/*.h
 lib/err/*.h
 lib/intmath/*.h
 lib/log/*.h
+lib/subsys/*.h
 lib/time/*.h
 lib/wallclock/*.h
 

+ 2 - 0
src/lib/time/include.am

@@ -7,6 +7,7 @@ endif
 
 src_lib_libtor_time_a_SOURCES =	\
 		src/lib/time/compat_time.c	\
+		src/lib/time/time_sys.c		\
 		src/lib/time/tvdiff.c
 
 src_lib_libtor_time_testing_a_SOURCES = \
@@ -16,4 +17,5 @@ src_lib_libtor_time_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
 noinst_HEADERS +=				\
 		src/lib/time/compat_time.h	\
+		src/lib/time/time_sys.h		\
 		src/lib/time/tvdiff.h

+ 26 - 0
src/lib/time/time_sys.c

@@ -0,0 +1,26 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file time_sys.c
+ * \brief Subsystem object for monotime setup.
+ **/
+
+#include "orconfig.h"
+#include "lib/subsys/subsys.h"
+#include "lib/time/time_sys.h"
+#include "lib/time/compat_time.h"
+
+static int
+subsys_time_initialize(void)
+{
+  monotime_init();
+  return 0;
+}
+
+const subsys_fns_t sys_time = {
+  .name = "time",
+  .level = -90,
+  .supported = true,
+  .initialize = subsys_time_initialize,
+};

+ 14 - 0
src/lib/time/time_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_time.h
+ * \brief Declare subsystem object for the time module.
+ **/
+
+#ifndef TOR_TIME_SYS_H
+#define TOR_TIME_SYS_H
+
+extern const struct subsys_fns_t sys_time;
+
+#endif /* !defined(TOR_TIME_SYS_H) */

+ 1 - 0
src/lib/tls/.may_include

@@ -11,6 +11,7 @@ lib/log/*.h
 lib/malloc/*.h
 lib/net/*.h
 lib/string/*.h
+lib/subsys/*.h
 lib/testsupport/testsupport.h
 lib/tls/*.h
 

+ 1 - 0
src/lib/tls/include.am

@@ -36,5 +36,6 @@ noinst_HEADERS +=				\
 	src/lib/tls/tortls.h			\
 	src/lib/tls/tortls_internal.h		\
 	src/lib/tls/tortls_st.h			\
+	src/lib/tls/tortls_sys.h		\
 	src/lib/tls/x509.h			\
 	src/lib/tls/x509_internal.h

+ 14 - 0
src/lib/tls/tortls.c

@@ -7,6 +7,7 @@
 #define TOR_X509_PRIVATE
 #include "lib/tls/x509.h"
 #include "lib/tls/x509_internal.h"
+#include "lib/tls/tortls_sys.h"
 #include "lib/tls/tortls.h"
 #include "lib/tls/tortls_st.h"
 #include "lib/tls/tortls_internal.h"
@@ -15,6 +16,7 @@
 #include "lib/crypt_ops/crypto_rsa.h"
 #include "lib/crypt_ops/crypto_rand.h"
 #include "lib/net/socket.h"
+#include "lib/subsys/subsys.h"
 
 #ifdef _WIN32
   #include <winsock2.h>
@@ -440,3 +442,15 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity)
 
   return rv;
 }
+
+static void
+subsys_tortls_shutdown(void)
+{
+  tor_tls_free_all();
+}
+
+const subsys_fns_t sys_tortls = {
+  .name = "tortls",
+  .level = -50,
+  .shutdown = subsys_tortls_shutdown
+};

+ 14 - 0
src/lib/tls/tortls_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tortls_sys.h
+ * \brief Declare subsystem object for the tortls module
+ **/
+
+#ifndef TOR_TORTLS_SYS_H
+#define TOR_TORTLS_SYS_H
+
+extern const struct subsys_fns_t sys_tortls;
+
+#endif /* !defined(TOR_TORTLS_SYS_H) */

+ 3 - 0
src/lib/version/.may_include

@@ -0,0 +1,3 @@
+orconfig.h
+micro-revision.i
+lib/version/*.h

+ 1 - 1
src/lib/log/git_revision.c → src/lib/version/git_revision.c

@@ -4,7 +4,7 @@
 /* See LICENSE for licensing information */
 
 #include "orconfig.h"
-#include "lib/log/git_revision.h"
+#include "lib/version/git_revision.h"
 
 /** String describing which Tor Git repository version the source was
  * built from.  This string is generated by a bit of shell kludging in

+ 0 - 0
src/lib/log/git_revision.h → src/lib/version/git_revision.h


+ 25 - 0
src/lib/version/include.am

@@ -0,0 +1,25 @@
+
+noinst_LIBRARIES += src/lib/libtor-version.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-version-testing.a
+endif
+
+src_lib_libtor_version_a_SOURCES =			\
+	src/lib/version/git_revision.c			\
+	src/lib/version/version.c
+
+src_lib_libtor_version_testing_a_SOURCES = \
+	$(src_lib_libtor_version_a_SOURCES)
+src_lib_libtor_version_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_version_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+# Declare that these object files depend on micro-revision.i.  Without this
+# rule, we could try to build them before micro-revision.i was created.
+src/lib/version/git_revision.$(OBJEXT) \
+  src/lib/version/src_lib_libtor_version_testing_a-git_revision.$(OBJEXT): \
+	micro-revision.i
+
+noinst_HEADERS +=					\
+	src/lib/version/git_revision.h			\
+	src/lib/version/torversion.h

+ 12 - 0
src/lib/version/torversion.h

@@ -0,0 +1,12 @@
+/* Copyright 2001-2004 Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_VERSION_H
+#define TOR_VERSION_H
+
+const char *get_version(void);
+const char *get_short_version(void);
+
+#endif /* !defined(TOR_VERSION_H) */

+ 50 - 0
src/lib/version/version.c

@@ -0,0 +1,50 @@
+/* Copyright 2001-2004 Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "lib/version/torversion.h"
+#include "lib/version/git_revision.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/** A shorter version of this Tor process's version, for export in our router
+ *  descriptor.  (Does not include the git version, if any.) */
+static const char the_short_tor_version[] =
+  VERSION
+#ifdef TOR_BUILD_TAG
+  " ("TOR_BUILD_TAG")"
+#endif
+  "";
+
+#define MAX_VERSION_LEN 128
+
+/** The version of this Tor process, possibly including git version */
+static char the_tor_version[MAX_VERSION_LEN] = "";
+
+/** Return the current Tor version. */
+const char *
+get_version(void)
+{
+  if (the_tor_version[0] == 0) {
+    if (strlen(tor_git_revision)) {
+      snprintf(the_tor_version, sizeof(the_tor_version),
+               "%s (git-%s)", the_short_tor_version, tor_git_revision);
+    } else {
+      snprintf(the_tor_version, sizeof(the_tor_version),
+               "%s", the_short_tor_version);
+    }
+    the_tor_version[sizeof(the_tor_version)-1] = 0;
+  }
+
+  return the_tor_version;
+}
+
+/** Return the current Tor version, without any git tag. */
+const char *
+get_short_version(void)
+{
+  return the_short_tor_version;
+}

+ 1 - 0
src/lib/wallclock/.may_include

@@ -3,4 +3,5 @@ lib/cc/*.h
 lib/err/*.h
 lib/wallclock/*.h
 lib/string/*.h
+lib/subsys/*.h
 lib/testsupport/*.h

+ 16 - 0
src/lib/wallclock/approx_time.c

@@ -9,7 +9,9 @@
  **/
 
 #include "orconfig.h"
+#include "lib/subsys/subsys.h"
 #include "lib/wallclock/approx_time.h"
+#include "lib/wallclock/wallclock_sys.h"
 
 /* =====
  * Cached time
@@ -41,3 +43,17 @@ update_approx_time(time_t now)
   cached_approx_time = now;
 }
 #endif /* !defined(TIME_IS_FAST) */
+
+static int
+subsys_wallclock_initialize(void)
+{
+  update_approx_time(time(NULL));
+  return 0;
+}
+
+const subsys_fns_t sys_wallclock = {
+  .name = "wallclock",
+  .supported = true,
+  .level = -99,
+  .initialize = subsys_wallclock_initialize,
+};

+ 2 - 1
src/lib/wallclock/include.am

@@ -19,4 +19,5 @@ noinst_HEADERS +=					\
 	src/lib/wallclock/approx_time.h			\
 	src/lib/wallclock/timeval.h			\
 	src/lib/wallclock/time_to_tm.h			\
-	src/lib/wallclock/tor_gettimeofday.h
+	src/lib/wallclock/tor_gettimeofday.h		\
+	src/lib/wallclock/wallclock_sys.h

+ 14 - 0
src/lib/wallclock/wallclock_sys.h

@@ -0,0 +1,14 @@
+/* Copyright (c) 2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file wallclock_sys.h
+ * \brief Declare subsystem object for the wallclock module.
+ **/
+
+#ifndef TOR_WALLCLOCK_SYS_H
+#define TOR_WALLCLOCK_SYS_H
+
+extern const struct subsys_fns_t sys_wallclock;
+
+#endif /* !defined(TOR_WALLCLOCK_SYS_H) */

+ 1 - 0
src/rust/build.rs

@@ -162,6 +162,7 @@ pub fn main() {
             cfg.component("tor-malloc");
             cfg.component("tor-wallclock");
             cfg.component("tor-err-testing");
+            cfg.component("tor-version-testing");
             cfg.component("tor-intmath-testing");
             cfg.component("tor-ctime-testing");
             cfg.component("curve25519_donna");

+ 4 - 3
src/test/bench.c

@@ -24,6 +24,7 @@
 
 #include "core/or/circuitlist.h"
 #include "app/config/config.h"
+#include "app/main/subsysmgr.h"
 #include "lib/crypt_ops/crypto_curve25519.h"
 #include "lib/crypt_ops/crypto_dh.h"
 #include "core/crypto/onion_ntor.h"
@@ -690,9 +691,10 @@ main(int argc, const char **argv)
   char *errmsg;
   or_options_t *options;
 
-  tor_threads_init();
+  subsystems_init_upto(SUBSYS_LEVEL_LIBS);
+  flush_log_messages_from_startup();
+
   tor_compress_init();
-  init_logging(1);
 
   if (argc == 4 && !strcmp(argv[1], "diff")) {
     const int N = 200;
@@ -739,7 +741,6 @@ main(int argc, const char **argv)
 
   init_protocol_warning_severity_level();
   options = options_new();
-  init_logging(1);
   options->command = CMD_RUN_UNITTESTS;
   options->DataDirectory = tor_strdup("");
   options->KeyDirectory = tor_strdup("");

+ 5 - 5
src/test/fuzz/fuzzing_common.c

@@ -3,12 +3,14 @@
 #define CRYPTO_ED25519_PRIVATE
 #include "orconfig.h"
 #include "core/or/or.h"
+#include "app/main/subsysmgr.h"
 #include "lib/err/backtrace.h"
 #include "app/config/config.h"
 #include "test/fuzz/fuzzing.h"
 #include "lib/compress/compress.h"
 #include "lib/crypt_ops/crypto_ed25519.h"
 #include "lib/crypt_ops/crypto_init.h"
+#include "lib/version/torversion.h"
 
 static or_options_t *mock_options = NULL;
 static const or_options_t *
@@ -94,12 +96,10 @@ disable_signature_checking(void)
 static void
 global_init(void)
 {
-  tor_threads_init();
-  tor_compress_init();
+  subsystems_init_upto(SUBSYS_LEVEL_LIBS);
+  flush_log_messages_from_startup();
 
-  /* Initialise logging first */
-  init_logging(1);
-  configure_backtrace_handler(get_version());
+  tor_compress_init();
 
   if (crypto_global_init(0, NULL, NULL) < 0)
     abort();

+ 6 - 14
src/test/testing_common.c

@@ -25,6 +25,8 @@
 #include "lib/compress/compress.h"
 #include "lib/evloop/compat_libevent.h"
 #include "lib/crypt_ops/crypto_init.h"
+#include "lib/version/torversion.h"
+#include "app/main/subsysmgr.h"
 
 #include <stdio.h>
 #ifdef HAVE_FCNTL_H
@@ -230,12 +232,12 @@ void
 tinytest_prefork(void)
 {
   free_pregenerated_keys();
-  crypto_prefork();
+  subsystems_prefork();
 }
 void
 tinytest_postfork(void)
 {
-  crypto_postfork();
+  subsystems_postfork();
   init_pregenerated_keys();
 }
 
@@ -250,24 +252,15 @@ main(int c, const char **v)
   int loglevel = LOG_ERR;
   int accel_crypto = 0;
 
-  /* We must initialise logs before we call tor_assert() */
-  init_logging(1);
+  subsystems_init_upto(SUBSYS_LEVEL_LIBS);
 
-  update_approx_time(time(NULL));
   options = options_new();
-  tor_threads_init();
-  tor_compress_init();
-
-  network_init();
-
-  monotime_init();
 
   struct tor_libevent_cfg cfg;
   memset(&cfg, 0, sizeof(cfg));
   tor_libevent_initialize(&cfg);
 
   control_initialize_event_queue();
-  configure_backtrace_handler(get_version());
 
   for (i_out = i = 1; i < c; ++i) {
     if (!strcmp(v[i], "--warn")) {
@@ -294,6 +287,7 @@ main(int c, const char **v)
     s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
     add_stream_log(&s, "", fileno(stdout));
   }
+  flush_log_messages_from_startup();
   init_protocol_warning_severity_level();
 
   options->command = CMD_RUN_UNITTESTS;
@@ -334,8 +328,6 @@ main(int c, const char **v)
 
   free_pregenerated_keys();
 
-  crypto_global_cleanup();
-
   if (have_failed)
     return 1;
   else