split out the implementation of the log functions

Before, things (ie mutex, queues, etc) that the logging code used
couldn't depend on the implementations of the log functions they use.
diff --git a/aos/common/logging/logging.h b/aos/common/logging/logging.h
index 6de118b..c71ee46 100644
--- a/aos/common/logging/logging.h
+++ b/aos/common/logging/logging.h
@@ -8,11 +8,6 @@
 #include <stdint.h>
 #include <stdlib.h>
 
-#ifdef __VXWORKS__
-// Because the vxworks system headers miss the noreturn...
-extern "C" void abort(void) __attribute__((noreturn));
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -30,14 +25,13 @@
 DECL_LEVEL(FATAL, 4); \
 DECL_LEVEL(LOG_UNKNOWN, 5); /* unknown logging level */
 #define DECL_LEVEL(name, value) static const log_level name = value;
-#undef ERROR
 DECL_LEVELS;
 #undef DECL_LEVEL
 
 #define STRINGIFY(x) TO_STRING(x)
 #define TO_STRING(x) #x
 
-//not static const size_t for c code
+// Not static const size_t for C code.
 #define LOG_MESSAGE_LEN 400
 
 #ifdef __VXWORKS__
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/logging_impl.cc
index 980f65a..fa76c86 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/logging_impl.cc
@@ -1,8 +1,8 @@
 #include "aos/common/logging/logging_impl.h"
 
 #include <assert.h>
+#include <stdarg.h>
 
-#include "aos/common/die.h"
 #include "aos/common/time.h"
 #include "aos/common/inttypes.h"
 #include "aos/common/once.h"
@@ -12,15 +12,8 @@
 namespace {
 
 using internal::Context;
+using internal::global_top_implementation;
 
-LogImplementation *global_top_implementation(NULL);
-// Just going to use a mutex instead of getting fancy because speed doesn't
-// really matter when accessing global_top_implementation.
-Mutex global_top_implementation_mutex;
-LogImplementation *get_global_top_implementation() {
-  MutexLocker locker(&global_top_implementation_mutex);
-  return global_top_implementation;
-}
 
 // The root LogImplementation. It only logs to stderr/stdout.
 // Some of the things specified in the LogImplementation documentation doesn't
@@ -43,27 +36,7 @@
   Context *context = Context::Get();
 
   context->implementation = implementation;
-  {
-    MutexLocker locker(&global_top_implementation_mutex);
-    global_top_implementation = implementation;
-  }
-}
-
-// Prints format (with ap) into output and correctly deals with the result
-// being too long etc.
-void ExecuteFormat(char *output, size_t output_size,
-                   const char *format, va_list ap) {
-  static const char *continued = "...\n";
-  const size_t size = output_size - strlen(continued);
-  const int ret = vsnprintf(output, size, format, ap);
-  if (ret < 0) {
-    LOG(FATAL, "vsnprintf(%p, %zd, %s, args) failed with %d (%s)\n",
-        output, size, format, errno, strerror(errno));
-  } else if (static_cast<uintmax_t>(ret) >= static_cast<uintmax_t>(size)) {
-    // Overwrite the '\0' at the end of the existing data and
-    // copy in the one on the end of continued.
-    memcpy(&output[size - 1], continued, strlen(continued) + 1);
-  }
+  global_top_implementation = implementation;
 }
 
 void NewContext() {
@@ -73,13 +46,11 @@
 void *DoInit() {
   SetGlobalImplementation(new RootLogImplementation());
 
-#ifndef __VXWORKS__
   if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
                      NewContext /*child*/) != 0) {
     LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n",
         NewContext);
   }
-#endif
 
   return NULL;
 }
@@ -87,12 +58,6 @@
 }  // namespace
 namespace internal {
 
-Context::Context()
-    : implementation(get_global_top_implementation()),
-      sequence(0) {
-  cork_data.Reset();
-}
-
 void FillInMessage(log_level level, const char *format, va_list ap,
                    LogMessage *message) {
   Context *context = Context::Get();
@@ -130,68 +95,6 @@
   internal::PrintMessage(stream_, message);
 }
 
-void LogImplementation::DoVLog(log_level level, const char *format, va_list ap,
-                   int levels) {
-  Context *context = Context::Get();
-
-  LogImplementation *top_implementation = context->implementation;
-  LogImplementation *new_implementation = top_implementation;
-  LogImplementation *implementation = NULL;
-  assert(levels >= 1);
-  for (int i = 0; i < levels; ++i) {
-    implementation = new_implementation;
-    if (new_implementation == NULL) {
-      Die("no logging implementation to use\n");
-    }
-    new_implementation = new_implementation->next();
-  }
-  context->implementation = new_implementation;
-  implementation->DoLog(level, format, ap);
-  context->implementation = top_implementation;
-
-  if (level == FATAL) {
-    VDie(format, ap);
-  }
-}
-
-void VLog(log_level level, const char *format, va_list ap) {
-  LogImplementation::DoVLog(level, format, ap, 1);
-}
-
-void VCork(int line, const char *function, const char *format, va_list ap) {
-  Context *context = Context::Get();
-
-  const size_t message_length = strlen(context->cork_data.message);
-  if (line > context->cork_data.line_max) context->cork_data.line_max = line;
-  if (line < context->cork_data.line_min) context->cork_data.line_min = line;
-
-  if (context->cork_data.function == NULL) {
-    context->cork_data.function = function;
-  } else {
-    if (strcmp(context->cork_data.function, function) != 0) {
-      LOG(FATAL, "started corking data in function %s but then moved to %s\n",
-          context->cork_data.function, function);
-    }
-  }
-
-  ExecuteFormat(context->cork_data.message + message_length,
-                sizeof(context->cork_data.message) - message_length,
-                format, ap);
-}
-
-void VUnCork(int line, const char *function, log_level level, const char *file,
-             const char *format, va_list ap) {
-  Context *context = Context::Get();
-
-  VCork(line, function, format, ap);
-
-  log_do(level, "%s: %d-%d: %s: %s", file,
-         context->cork_data.line_min, context->cork_data.line_max, function,
-         context->cork_data.message);
-
-  context->cork_data.Reset();
-}
-
 void LogNext(log_level level, const char *format, ...) {
   va_list ap;
   va_start(ap, format);
@@ -229,25 +132,3 @@
 
 }  // namespace logging
 }  // namespace aos
-
-void log_do(log_level level, const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  aos::logging::VLog(level, format, ap);
-  va_end(ap);
-}
-
-void log_cork(int line, const char *function, const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  aos::logging::VCork(line, function, format, ap);
-  va_end(ap);
-}
-
-void log_uncork(int line, const char *function, log_level level,
-                const char *file, const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  aos::logging::VUnCork(line, function, level, file, format, ap);
-  va_end(ap);
-}
diff --git a/aos/common/logging/logging_impl.h b/aos/common/logging/logging_impl.h
index 18f35bc..ca19dbc 100644
--- a/aos/common/logging/logging_impl.h
+++ b/aos/common/logging/logging_impl.h
@@ -18,6 +18,10 @@
 // code like logging.h can.
 // It is useful for the rest of the logging implementation and other C++ code
 // that needs to do special things with logging.
+//
+// It is implemented in logging_impl.cc and logging_interface.cc. They are
+// separate so that code used by logging_impl.cc can link in
+// logging_interface.cc to use logging.
 
 namespace aos {
 namespace logging {
@@ -151,6 +155,8 @@
 // goes.
 namespace internal {
 
+extern LogImplementation *global_top_implementation;
+
 // An separate instance of this class is accessible from each task/thread.
 // NOTE: It will get deleted in the child of a fork.
 struct Context {
@@ -210,6 +216,11 @@
 // Prints message to output.
 void PrintMessage(FILE *output, const LogMessage &message);
 
+// Prints format (with ap) into output and correctly deals with the result
+// being too long etc.
+void ExecuteFormat(char *output, size_t output_size, const char *format,
+                   va_list ap);
+
 }  // namespace internal
 }  // namespace logging
 }  // namespace aos
diff --git a/aos/common/logging/logging_interface.cc b/aos/common/logging/logging_interface.cc
new file mode 100644
index 0000000..01fb708
--- /dev/null
+++ b/aos/common/logging/logging_interface.cc
@@ -0,0 +1,128 @@
+#include "aos/common/logging/logging_impl.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "aos/common/die.h"
+
+// This file only contains the code necessary to link (ie no implementations).
+// See logging_impl.h for why this is necessary.
+
+namespace aos {
+namespace logging {
+namespace internal {
+
+LogImplementation *global_top_implementation(NULL);
+
+Context::Context()
+    : implementation(global_top_implementation),
+      sequence(0) {
+  cork_data.Reset();
+}
+
+void ExecuteFormat(char *output, size_t output_size,
+                   const char *format, va_list ap) {
+  static const char *continued = "...\n";
+  const size_t size = output_size - strlen(continued);
+  const int ret = vsnprintf(output, size, format, ap);
+  if (ret < 0) {
+    LOG(FATAL, "vsnprintf(%p, %zd, %s, args) failed with %d (%s)\n",
+        output, size, format, errno, strerror(errno));
+  } else if (static_cast<uintmax_t>(ret) >= static_cast<uintmax_t>(size)) {
+    // Overwrite the '\0' at the end of the existing data and
+    // copy in the one on the end of continued.
+    memcpy(&output[size - 1], continued, strlen(continued) + 1);
+  }
+}
+
+}  // namespace internal
+
+using internal::Context;
+
+void LogImplementation::DoVLog(log_level level, const char *format, va_list ap,
+                   int levels) {
+  Context *context = Context::Get();
+
+  LogImplementation *top_implementation = context->implementation;
+  LogImplementation *new_implementation = top_implementation;
+  LogImplementation *implementation = NULL;
+  assert(levels >= 1);
+  for (int i = 0; i < levels; ++i) {
+    implementation = new_implementation;
+    if (new_implementation == NULL) {
+      Die("no logging implementation to use\n");
+    }
+    new_implementation = new_implementation->next();
+  }
+  context->implementation = new_implementation;
+  implementation->DoLog(level, format, ap);
+  context->implementation = top_implementation;
+
+  if (level == FATAL) {
+    VDie(format, ap);
+  }
+}
+
+void VLog(log_level level, const char *format, va_list ap) {
+  LogImplementation::DoVLog(level, format, ap, 1);
+}
+
+void VCork(int line, const char *function, const char *format, va_list ap) {
+  Context *context = Context::Get();
+
+  const size_t message_length = strlen(context->cork_data.message);
+  if (line > context->cork_data.line_max) context->cork_data.line_max = line;
+  if (line < context->cork_data.line_min) context->cork_data.line_min = line;
+
+  if (context->cork_data.function == NULL) {
+    context->cork_data.function = function;
+  } else {
+    if (strcmp(context->cork_data.function, function) != 0) {
+      LOG(FATAL, "started corking data in function %s but then moved to %s\n",
+          context->cork_data.function, function);
+    }
+  }
+
+  internal::ExecuteFormat(context->cork_data.message + message_length,
+                          sizeof(context->cork_data.message) - message_length,
+                          format, ap);
+}
+
+void VUnCork(int line, const char *function, log_level level, const char *file,
+             const char *format, va_list ap) {
+  Context *context = Context::Get();
+
+  VCork(line, function, format, ap);
+
+  log_do(level, "%s: %d-%d: %s: %s", file,
+         context->cork_data.line_min, context->cork_data.line_max, function,
+         context->cork_data.message);
+
+  context->cork_data.Reset();
+}
+
+}  // namespace logging
+}  // namespace aos
+
+void log_do(log_level level, const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  aos::logging::VLog(level, format, ap);
+  va_end(ap);
+}
+
+void log_cork(int line, const char *function, const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  aos::logging::VCork(line, function, format, ap);
+  va_end(ap);
+}
+
+void log_uncork(int line, const char *function, log_level level,
+                const char *file, const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  aos::logging::VUnCork(line, function, level, file, format, ap);
+  va_end(ap);
+}