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/build/aos.gyp b/aos/build/aos.gyp
index d9a1bf6..b7775a1 100644
--- a/aos/build/aos.gyp
+++ b/aos/build/aos.gyp
@@ -2,9 +2,31 @@
# For the cRIO, shared_library means to build a .out file, NOT a shared library.
# This means that depending on shared libraries doesn't work very well.
# Shared libraries don't seem to be supported by the powerpc-wrs-vxworks
-# tools and gyp doesn't like a static_library that depends on static_librarys.
+# tools and gyp doesn't like a static_library that depends only on
+# other static_librarys.
{
'targets': [
+ # A target for things used by the logging implementation (except die) to
+ # depend on that allows linking successfully with logging calls but has no
+ # way to get initialized and so is basically useless unless something else
+ # links in the rest of the logging stuff.
+ {
+ 'target_name': 'logging_interface',
+ 'type': 'static_library',
+ 'sources': [
+ '<(AOS)/common/logging/logging_interface.cc',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'sources': [
+ '<(AOS)/linux_code/logging/linux_interface.cc',
+ ],
+ }],
+ ],
+ 'dependencies': [
+ '<(AOS)/common/common.gyp:die',
+ ],
+ },
{
'target_name': 'logging',
'type': 'static_library',
@@ -21,14 +43,13 @@
],
'export_dependent_settings': [
'<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:queue',
- ]
+ ],
}],
],
'dependencies': [
'<(AOS)/common/common.gyp:time',
'<(AOS)/common/common.gyp:once',
- '<(AOS)/common/common.gyp:mutex',
- '<(AOS)/common/common.gyp:die',
+ 'logging_interface',
],
},
{
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 4c2b684..508f94f 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -37,9 +37,7 @@
'time.cc'
],
'dependencies': [
- # TODO(aschuh): Fix this dependency loop by
- # providing a logging interface.
- # '<(AOS)/build/aos.gyp:logging',
+ '<(AOS)/build/aos.gyp:logging_interface',
'mutex',
],
},
@@ -229,9 +227,7 @@
'dependencies': [
'mutex',
'<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:aos_sync',
- # TODO(aschuh): Fix this dependency loop by
- # providing a logging interface.
- # '<(AOS)/build/aos.gyp:logging',
+ '<(AOS)/build/aos.gyp:logging_interface',
],
'export_dependent_settings': [
'mutex',
@@ -259,9 +255,7 @@
}],
],
'dependencies': [
- # TODO(aschuh): Fix this dependency loop by
- # providing a logging interface.
- # '<(AOS)/build/aos.gyp:logging',
+ '<(AOS)/build/aos.gyp:logging_interface',
],
},
{
@@ -273,7 +267,6 @@
'dependencies': [
'<(EXTERNALS):gtest',
'mutex',
- '<(AOS)/build/aos.gyp:logging',
],
},
{
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);
+}
diff --git a/aos/common/util/util.gyp b/aos/common/util/util.gyp
index 852f3d7..79275c0 100644
--- a/aos/common/util/util.gyp
+++ b/aos/common/util/util.gyp
@@ -37,8 +37,6 @@
'dependencies': [
':trapezoid_profile',
'<(EXTERNALS):gtest',
- # TODO(brians): remove this when time no longer requires it
- '<(AOS)/build/aos.gyp:logging',
],
},
{
diff --git a/aos/linux_code/ipc_lib/ipc_lib.gyp b/aos/linux_code/ipc_lib/ipc_lib.gyp
index f947d5e..df7b658 100644
--- a/aos/linux_code/ipc_lib/ipc_lib.gyp
+++ b/aos/linux_code/ipc_lib/ipc_lib.gyp
@@ -44,8 +44,7 @@
'<(AOS)/common/common.gyp:condition',
'<(AOS)/common/common.gyp:mutex',
'core_lib',
- # TODO(brians): fix this once there's a nice logging interface to use
- # '<(AOS)/build/aos.gyp:logging',
+ '<(AOS)/build/aos.gyp:logging_interface',
],
},
{
diff --git a/aos/linux_code/logging/linux_interface.cc b/aos/linux_code/logging/linux_interface.cc
new file mode 100644
index 0000000..d039c70
--- /dev/null
+++ b/aos/linux_code/logging/linux_interface.cc
@@ -0,0 +1,65 @@
+#include "aos/linux_code/logging/linux_logging.h"
+
+#include <sys/prctl.h>
+
+#include "aos/linux_code/thread_local.h"
+#include "aos/common/die.h"
+
+namespace aos {
+namespace logging {
+namespace internal {
+namespace {
+
+::std::string GetMyName() {
+ // The maximum number of characters that can make up a thread name.
+ // The docs are unclear if it can be 16 characters with no '\0', so we'll be
+ // safe by adding our own where necessary.
+ static const size_t kThreadNameLength = 16;
+
+ ::std::string process_name(program_invocation_short_name);
+
+ char thread_name_array[kThreadNameLength + 1];
+ if (prctl(PR_GET_NAME, thread_name_array) != 0) {
+ Die("prctl(PR_GET_NAME, %p) failed with %d: %s\n",
+ thread_name_array, errno, strerror(errno));
+ }
+ thread_name_array[sizeof(thread_name_array) - 1] = '\0';
+ ::std::string thread_name(thread_name_array);
+
+ // If the first bunch of characters are the same.
+ // We cut off comparing at the shorter of the 2 strings because one or the
+ // other often ends up cut off.
+ if (strncmp(thread_name.c_str(), process_name.c_str(),
+ ::std::min(thread_name.length(), process_name.length())) == 0) {
+ // This thread doesn't have an actual name.
+ return process_name;
+ }
+
+ return process_name + '.' + thread_name;
+}
+
+AOS_THREAD_LOCAL Context *my_context(NULL);
+
+} // namespace
+
+Context *Context::Get() {
+ if (my_context == NULL) {
+ my_context = new Context();
+ my_context->name = GetMyName();
+ if (my_context->name.size() + 1 > sizeof(LogMessage::name)) {
+ Die("logging: process/thread name '%s' is too long\n",
+ my_context->name.c_str());
+ }
+ my_context->source = getpid();
+ }
+ return my_context;
+}
+
+void Context::Delete() {
+ delete my_context;
+ my_context = NULL;
+}
+
+} // namespace internal
+} // namespace logging
+} // namespace aos
diff --git a/aos/linux_code/logging/linux_logging.cc b/aos/linux_code/logging/linux_logging.cc
index faeb04a..985577b 100644
--- a/aos/linux_code/logging/linux_logging.cc
+++ b/aos/linux_code/logging/linux_logging.cc
@@ -8,75 +8,20 @@
#include <errno.h>
#include <unistd.h>
#include <limits.h>
-#include <sys/prctl.h>
#include <algorithm>
#include "aos/common/die.h"
#include "aos/common/logging/logging_impl.h"
-#include "aos/linux_code/thread_local.h"
#include "aos/linux_code/ipc_lib/queue.h"
namespace aos {
namespace logging {
namespace {
-using internal::Context;
-
-AOS_THREAD_LOCAL Context *my_context(NULL);
-
-::std::string GetMyName() {
- // The maximum number of characters that can make up a thread name.
- // The docs are unclear if it can be 16 characters with no '\0', so we'll be
- // safe by adding our own where necessary.
- static const size_t kThreadNameLength = 16;
-
- ::std::string process_name(program_invocation_short_name);
-
- char thread_name_array[kThreadNameLength + 1];
- if (prctl(PR_GET_NAME, thread_name_array) != 0) {
- Die("prctl(PR_GET_NAME, %p) failed with %d: %s\n",
- thread_name_array, errno, strerror(errno));
- }
- thread_name_array[sizeof(thread_name_array) - 1] = '\0';
- ::std::string thread_name(thread_name_array);
-
- // If the first bunch of characters are the same.
- // We cut off comparing at the shorter of the 2 strings because one or the
- // other often ends up cut off.
- if (strncmp(thread_name.c_str(), process_name.c_str(),
- ::std::min(thread_name.length(), process_name.length())) == 0) {
- // This thread doesn't have an actual name.
- return process_name;
- }
-
- return process_name + '.' + thread_name;
-}
-
RawQueue *queue;
} // namespace
-namespace internal {
-
-Context *Context::Get() {
- if (my_context == NULL) {
- my_context = new Context();
- my_context->name = GetMyName();
- if (my_context->name.size() + 1 > sizeof(LogMessage::name)) {
- Die("logging: process/thread name '%s' is too long\n",
- my_context->name.c_str());
- }
- my_context->source = getpid();
- }
- return my_context;
-}
-
-void Context::Delete() {
- delete my_context;
- my_context = NULL;
-}
-
-} // namespace internal
namespace linux_code {
namespace {