Merge //aos/linux_code/logging into //aos/common/logging

Shuffling files+targets to clean it up further is coming next.

Change-Id: Iae716b07b340a66502f8e0964281c10fae0fcb7a
diff --git a/aos/common/logging/linux_logging.cc b/aos/common/logging/linux_logging.cc
new file mode 100644
index 0000000..14ce72b
--- /dev/null
+++ b/aos/common/logging/linux_logging.cc
@@ -0,0 +1,145 @@
+#include "aos/common/logging/linux_logging.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <inttypes.h>
+
+#include <algorithm>
+
+#include "aos/common/die.h"
+#include "aos/common/logging/logging_interface.h"
+#include "aos/linux_code/ipc_lib/queue.h"
+#include "aos/common/time.h"
+
+namespace aos {
+namespace logging {
+namespace linux_code {
+namespace {
+
+RawQueue *queue = NULL;
+
+int dropped_messages = 0;
+::aos::time::Time dropped_start, backoff_start;
+// Wait this long after dropping a message before even trying to write any more.
+constexpr ::aos::time::Time kDropBackoff = ::aos::time::Time::InSeconds(0.1);
+
+LogMessage *GetMessageOrDie() {
+  LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
+  if (message == NULL) {
+    LOG(FATAL, "%p->GetMessage() failed\n", queue);
+  } else {
+    return message;
+  }
+}
+
+class LinuxQueueLogImplementation : public LogImplementation {
+  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
+  virtual void DoLog(log_level level, const char *format, va_list ap) override {
+    LogMessage *message = GetMessageOrDie();
+    internal::FillInMessage(level, format, ap, message);
+    Write(message);
+  }
+
+  virtual void LogStruct(log_level level, const ::std::string &message_string,
+                         size_t size, const MessageType *type,
+                         const ::std::function<size_t(char *)> &serialize)
+      override {
+    LogMessage *message = GetMessageOrDie();
+    internal::FillInMessageStructure(level, message_string, size, type,
+                                     serialize, message);
+    Write(message);
+  }
+
+  virtual void LogMatrix(log_level level, const ::std::string &message_string,
+                         uint32_t type_id, int rows, int cols, const void *data)
+      override {
+    LogMessage *message = GetMessageOrDie();
+    internal::FillInMessageMatrix(level, message_string, type_id, rows, cols,
+                                  data, message);
+    Write(message);
+  }
+};
+
+}  // namespace
+
+void Register() {
+  Init();
+
+  queue = RawQueue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 40000);
+  if (queue == NULL) {
+    Die("logging: couldn't fetch queue\n");
+  }
+
+  AddImplementation(new LinuxQueueLogImplementation());
+}
+
+const LogMessage *ReadNext(Options<RawQueue> flags, int *index) {
+  return static_cast<const LogMessage *>(queue->ReadMessageIndex(flags, index));
+}
+
+const LogMessage *ReadNext() {
+  return ReadNext(RawQueue::kBlock);
+}
+
+const LogMessage *ReadNext(Options<RawQueue> flags) {
+  const LogMessage *r = NULL;
+  do {
+    r = static_cast<const LogMessage *>(queue->ReadMessage(flags));
+    // not blocking means return a NULL if that's what it gets
+  } while ((flags & RawQueue::kBlock) && r == NULL);
+  return r;
+}
+
+LogMessage *Get() {
+  return static_cast<LogMessage *>(queue->GetMessage());
+}
+
+void Free(const LogMessage *msg) {
+  queue->FreeMessage(msg);
+}
+
+void Write(LogMessage *msg) {
+  if (__builtin_expect(dropped_messages > 0, false)) {
+    ::aos::time::Time message_time =
+        ::aos::time::Time(msg->seconds, msg->nseconds);
+    if (message_time - backoff_start < kDropBackoff) {
+      ++dropped_messages;
+      queue->FreeMessage(msg);
+      return;
+    }
+
+    LogMessage *dropped_message = GetMessageOrDie();
+    internal::FillInMessageVarargs(
+        ERROR, dropped_message,
+        "%d logs starting at %" PRId32 ".%" PRId32 " dropped\n",
+        dropped_messages, dropped_start.sec(), dropped_start.nsec());
+    if (queue->WriteMessage(dropped_message, RawQueue::kNonBlock)) {
+      dropped_messages = 0;
+    } else {
+      // Don't even bother trying to write this message because it's not likely
+      // to work and it would be confusing to have one log in the middle of a
+      // string of failures get through.
+      ++dropped_messages;
+      backoff_start = message_time;
+      queue->FreeMessage(msg);
+      return;
+    }
+  }
+  if (!queue->WriteMessage(msg, RawQueue::kNonBlock)) {
+    if (dropped_messages == 0) {
+      dropped_start = backoff_start =
+          ::aos::time::Time(msg->seconds, msg->nseconds);
+    }
+    ++dropped_messages;
+  }
+}
+
+}  // namespace linux_code
+}  // namespace logging
+}  // namespace aos