diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index e1261ee17d55062924ea3f4476176b308f953a19..ff20de4f0815946124a3b02ade939a8243cdd0e9 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -43,6 +43,7 @@ set(llcommon_SOURCE_FILES
     llcleanup.cpp
     llcommon.cpp
     llcommonutils.cpp
+    llcoro_get_id.cpp
     llcoros.cpp
     llcrc.cpp
     llcriticaldamp.cpp
@@ -139,6 +140,7 @@ set(llcommon_HEADER_FILES
     llcleanup.h
     llcommon.h
     llcommonutils.h
+    llcoro_get_id.h
     llcoros.h
     llcrc.h
     llcriticaldamp.h
diff --git a/indra/llcommon/llcoro_get_id.cpp b/indra/llcommon/llcoro_get_id.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..24ed1fe0c9f3b4e7208126fe0b55d1105b003f49
--- /dev/null
+++ b/indra/llcommon/llcoro_get_id.cpp
@@ -0,0 +1,32 @@
+/**
+ * @file   llcoro_get_id.cpp
+ * @author Nat Goodspeed
+ * @date   2016-09-03
+ * @brief  Implementation for llcoro_get_id.
+ * 
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llcoro_get_id.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llcoros.h"
+
+namespace llcoro
+{
+
+id get_id()
+{
+    // An instance of Current can convert to LLCoros::CoroData*, which can
+    // implicitly convert to void*, which is an llcoro::id.
+    return LLCoros::Current();
+}
+
+} // llcoro
diff --git a/indra/llcommon/llcoro_get_id.h b/indra/llcommon/llcoro_get_id.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c1dca6f191a92a156fc6f0127007133f03b826a
--- /dev/null
+++ b/indra/llcommon/llcoro_get_id.h
@@ -0,0 +1,30 @@
+/**
+ * @file   llcoro_get_id.h
+ * @author Nat Goodspeed
+ * @date   2016-09-03
+ * @brief  Supplement the functionality in llcoro.h.
+ *
+ *         This is broken out as a separate header file to resolve
+ *         circularity: LLCoros isa LLSingleton, yet LLSingleton machinery
+ *         requires llcoro::get_id().
+ *
+ *         Be very suspicious of anyone else #including this header.
+ * 
+ * $LicenseInfo:firstyear=2016&license=viewerlgpl$
+ * Copyright (c) 2016, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLCORO_GET_ID_H)
+#define LL_LLCORO_GET_ID_H
+
+namespace llcoro
+{
+
+/// Get an opaque, distinct token for the running coroutine (or main).
+typedef void* id;
+id get_id();
+
+} // llcoro
+
+#endif /* ! defined(LL_LLCORO_GET_ID_H) */
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index 93e5ea8b9f5042cc2b246252521204d5ea36a014..5b6c6e5198ca809f88e494a67257f097472d91ad 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -38,6 +38,7 @@
 #include <boost/noncopyable.hpp>
 #include <string>
 #include <stdexcept>
+#include "llcoro_get_id.h"          // for friend declaration
 
 // forward-declare helper class
 namespace llcoro
@@ -146,10 +147,6 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
      */
     std::string getName() const;
 
-    /// Get an opaque, distinct token for the running coroutine (or main).
-    typedef void* id;
-    static id get_id() { return Current(); }
-
     /// for delayed initialization
     void setStackSize(S32 stacksize);
 
@@ -181,6 +178,7 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
     LLCoros();
     friend class LLSingleton<LLCoros>;
     friend class llcoro::Suspending;
+    friend llcoro::id llcoro::get_id();
     std::string generateDistinctName(const std::string& prefix) const;
     bool cleanup(const LLSD&);
     struct CoroData;