diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 556f87963401c772feacbfc392989bf0baa79fc7..e1261ee17d55062924ea3f4476176b308f953a19 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -40,6 +40,7 @@ set(llcommon_SOURCE_FILES
     llbase64.cpp
     llbitpack.cpp
     llcallbacklist.cpp
+    llcleanup.cpp
     llcommon.cpp
     llcommonutils.cpp
     llcoros.cpp
@@ -66,6 +67,7 @@ set(llcommon_SOURCE_FILES
     llframetimer.cpp
     llheartbeat.cpp
     llinitparam.cpp
+    llinitdestroyclass.cpp
     llinstancetracker.cpp
     llleap.cpp
     llleaplistener.cpp
@@ -134,6 +136,7 @@ set(llcommon_HEADER_FILES
     llbitpack.h
     llboost.h
     llcallbacklist.h
+    llcleanup.h
     llcommon.h
     llcommonutils.h
     llcoros.h
diff --git a/indra/llcommon/llcleanup.cpp b/indra/llcommon/llcleanup.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f45f4925ced1db3c1828fa001408045ed6e7a07d
--- /dev/null
+++ b/indra/llcommon/llcleanup.cpp
@@ -0,0 +1,28 @@
+/**
+ * @file   llcleanup.cpp
+ * @author Nat Goodspeed
+ * @date   2016-08-30
+ * @brief  Implementation for llcleanup.
+ * 
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llcleanup.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llerror.h"
+
+void log_subsystem_cleanup(const char* file, int line, const char* function,
+                           const char* classname)
+{
+    LL_INFOS("Cleanup") << file << "(" << line << "): calling " 
+                        << classname << "::cleanupClass() in "
+                        << function << LL_ENDL;
+}
diff --git a/indra/llcommon/llcleanup.h b/indra/llcommon/llcleanup.h
index 8eda9a7fb35205c912958af865834dcad043d05f..a319171b5f1891d06969585c9f9a75e02ef7149c 100644
--- a/indra/llcommon/llcleanup.h
+++ b/indra/llcommon/llcleanup.h
@@ -12,7 +12,7 @@
 #if ! defined(LL_LLCLEANUP_H)
 #define LL_LLCLEANUP_H
 
-#include "llerror.h"
+#include <boost/current_function.hpp>
 
 // Instead of directly calling SomeClass::cleanupClass(), use
 // SUBSYSTEM_CLEANUP(SomeClass);
@@ -21,10 +21,13 @@
 // shutdown schemes.
 #define SUBSYSTEM_CLEANUP(CLASSNAME)                                    \
     do {                                                                \
-        LL_INFOS("Cleanup") << "Calling " #CLASSNAME "::cleanupClass()" << LL_ENDL; \
+        log_subsystem_cleanup(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, #CLASSNAME); \
         CLASSNAME::cleanupClass();                                      \
     } while (0)
 // Use ancient do { ... } while (0) macro trick to permit a block of
 // statements with the same syntax as a single statement.
 
+void log_subsystem_cleanup(const char* file, int line, const char* function,
+                           const char* classname);
+
 #endif /* ! defined(LL_LLCLEANUP_H) */
diff --git a/indra/llcommon/llinitdestroyclass.cpp b/indra/llcommon/llinitdestroyclass.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e6382a79249bf445638ca712a84a5cebeadc2f09
--- /dev/null
+++ b/indra/llcommon/llinitdestroyclass.cpp
@@ -0,0 +1,30 @@
+/**
+ * @file   llinitdestroyclass.cpp
+ * @author Nat Goodspeed
+ * @date   2016-08-30
+ * @brief  Implementation for llinitdestroyclass.
+ * 
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llinitdestroyclass.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llerror.h"
+
+void LLCallbackRegistry::fireCallbacks() const
+{
+	for (FuncList::const_iterator fi = mCallbacks.begin(), fe = mCallbacks.end();
+		 fi != fe; ++fi)
+	{
+		LL_INFOS("LLInitDestroyClass") << "calling " << fi->first << "()" << LL_ENDL;
+		fi->second();
+	}
+}
diff --git a/indra/llcommon/llinitdestroyclass.h b/indra/llcommon/llinitdestroyclass.h
index 49bcefc33d73c6167d65396ecc52efa422aaabfb..9c662114752d78ad78b6722f927d9e401739a44f 100644
--- a/indra/llcommon/llinitdestroyclass.h
+++ b/indra/llcommon/llinitdestroyclass.h
@@ -36,34 +36,35 @@
 #if ! defined(LL_LLINITDESTROYCLASS_H)
 #define LL_LLINITDESTROYCLASS_H
 
-#include "llerror.h"
 #include "llsingleton.h"
 #include <boost/function.hpp>
-#include <boost/signals2/signal.hpp>
 #include <typeinfo>
+#include <vector>
+#include <utility>                  // std::pair
 
 /**
  * LLCallbackRegistry is an implementation detail base class for
- * LLInitClassList and LLDestroyClassList. It's a very thin wrapper around a
- * Boost.Signals2 signal object.
+ * LLInitClassList and LLDestroyClassList. It accumulates the initClass() or
+ * destroyClass() callbacks for registered classes.
  */
 class LLCallbackRegistry
 {
 public:
-	typedef boost::signals2::signal<void()> callback_signal_t;
-	
-	void registerCallback(const callback_signal_t::slot_type& slot)
-	{
-		mCallbacks.connect(slot);
-	}
+	typedef boost::function<void()> func_t;
 
-	void fireCallbacks()
+	void registerCallback(const std::string& name, const func_t& func)
 	{
-		mCallbacks();
+		mCallbacks.push_back(FuncList::value_type(name, func));
 	}
 
+	void fireCallbacks() const;
+
 private:
-	callback_signal_t mCallbacks;
+	// Arguably this should be a boost::signals2::signal, which is, after all,
+	// a sequence of callables. We manage it by hand so we can log a name for
+	// each registered function we call.
+	typedef std::vector< std::pair<std::string, func_t> > FuncList;
+	FuncList mCallbacks;
 };
 
 /**
@@ -108,9 +109,9 @@ template<typename T>
 class LLRegisterWith
 {
 public:
-	LLRegisterWith(boost::function<void ()> func)
+	LLRegisterWith(const std::string& name, const LLCallbackRegistry::func_t& func)
 	{
-		T::instance().registerCallback(func);
+		T::instance().registerCallback(name, func);
 	}
 
 	// this avoids a MSVC bug where non-referenced static members are "optimized" away
@@ -141,15 +142,6 @@ class LLInitClass
 	// When this static member is initialized, the subclass initClass() method
 	// is registered on LLInitClassList. See sRegister definition below.
 	static LLRegisterWith<LLInitClassList> sRegister;
-private:
-
-	// Provide a default initClass() method in case subclass misspells (or
-	// omits) initClass(). This turns a potential build error into a fatal
-	// runtime error.
-	static void initClass()
-	{
-		LL_ERRS() << "No static initClass() method defined for " << typeid(T).name() << LL_ENDL;
-	}
 };
 
 /**
@@ -171,20 +163,17 @@ class LLDestroyClass
 	// method is registered on LLInitClassList. See sRegister definition
 	// below.
 	static LLRegisterWith<LLDestroyClassList> sRegister;
-private:
-
-	// Provide a default destroyClass() method in case subclass misspells (or
-	// omits) destroyClass(). This turns a potential build error into a fatal
-	// runtime error.
-	static void destroyClass()
-	{
-		LL_ERRS() << "No static destroyClass() method defined for " << typeid(T).name() << LL_ENDL;
-	}
 };
 
 // Here's where LLInitClass<T> specifies the subclass initClass() method.
-template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister(&T::initClass);
+template <typename T>
+LLRegisterWith<LLInitClassList>
+LLInitClass<T>::sRegister(std::string(typeid(T).name()) + "::initClass",
+						  &T::initClass);
 // Here's where LLDestroyClass<T> specifies the subclass destroyClass() method.
-template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(&T::destroyClass);
+template <typename T>
+LLRegisterWith<LLDestroyClassList>
+LLDestroyClass<T>::sRegister(std::string(typeid(T).name()) + "::destroyClass",
+							 &T::destroyClass);
 
 #endif /* ! defined(LL_LLINITDESTROYCLASS_H) */