blob: c9b119506ee992841a40bca3e82c6b90386234be [file] [log] [blame]
Brian Silvermanf665d692013-02-17 22:11:39 -08001#include "aos/atom_code/logging/atom_logging.h"
2
3#include <stdarg.h>
4#include <stdio.h>
5#include <string.h>
6#include <time.h>
7#include <sys/types.h>
8#include <errno.h>
9#include <unistd.h>
10#include <limits.h>
11#include <sys/prctl.h>
12
13#include <algorithm>
14
15#include "aos/common/die.h"
16#include "aos/common/logging/logging_impl.h"
17#include "aos/atom_code/thread_local.h"
18#include "aos/atom_code/ipc_lib/queue.h"
19
20namespace aos {
21namespace logging {
22namespace {
23
24using internal::Context;
25
26AOS_THREAD_LOCAL Context *my_context(NULL);
27
28std::string GetMyName() {
29 // The maximum number of characters that can make up a thread name.
30 // The docs are unclear if it can be 16 characters with no '\0', so we'll be
31 // safe by adding our own where necessary.
32 static const size_t kThreadNameLength = 16;
33
34 std::string process_name(program_invocation_short_name);
35
36 char thread_name_array[kThreadNameLength + 1];
37 if (prctl(PR_GET_NAME, thread_name_array) != 0) {
38 Die("prctl(PR_GET_NAME, %p) failed with %d: %s\n",
39 thread_name_array, errno, strerror(errno));
40 }
41 thread_name_array[sizeof(thread_name_array) - 1] = '\0';
42 std::string thread_name(thread_name_array);
43
44 // If the first bunch of characters are the same.
45 // We cut off comparing at the shorter of the 2 strings because one or the
46 // other often ends up cut off.
47 if (strncmp(thread_name.c_str(), process_name.c_str(),
48 std::min(thread_name.length(), process_name.length())) == 0) {
49 // This thread doesn't have an actual name.
50 return process_name;
51 }
52
53 return process_name + '.' + thread_name;
54}
55
56static const aos_type_sig message_sig = {sizeof(LogMessage), 1234, 1500};
57static aos_queue *queue;
58
59} // namespace
60namespace internal {
61
62Context *Context::Get() {
63 if (my_context == NULL) {
64 my_context = new Context();
65 std::string name = GetMyName();
66 char *name_chars = new char[name.size() + 1];
67 my_context->name_size = std::min(name.size() + 1, sizeof(LogMessage::name));
68 memcpy(name_chars, name.c_str(), my_context->name_size);
69 name_chars[my_context->name_size - 1] = '\0';
70 my_context->name = name_chars;
71 my_context->source = getpid();
72 }
73 return my_context;
74}
75
76void Context::Delete() {
77 delete my_context;
78 my_context = NULL;
79}
80
81} // namespace internal
82namespace atom {
83namespace {
84
85class AtomLogImplementation : public LogImplementation {
86 virtual void DoLog(log_level level, const char *format, va_list ap) {
87 LogMessage *message = static_cast<LogMessage *>(aos_queue_get_msg(queue));
88 if (message == NULL) {
89 LOG(FATAL, "queue get message failed\n");
90 }
91
92 internal::FillInMessage(level, format, ap, message);
93
94 Write(message);
95 }
96};
97
98} // namespace
99
100void Register() {
101 Init();
102
103 queue = aos_fetch_queue("LoggingQueue", &message_sig);
104 if (queue == NULL) {
105 Die("logging: couldn't fetch queue\n");
106 }
107
108 AddImplementation(new AtomLogImplementation());
109}
110
111const LogMessage *ReadNext(int flags, int *index) {
112 return static_cast<const LogMessage *>(
113 aos_queue_read_msg_index(queue, flags, index));
114}
115
116const LogMessage *ReadNext() {
117 return ReadNext(BLOCK);
118}
119
120const LogMessage *ReadNext(int flags) {
121 const LogMessage *r = NULL;
122 do {
123 r = static_cast<const LogMessage *>(aos_queue_read_msg(queue, flags));
124 // not blocking means return a NULL if that's what it gets
125 } while ((flags & BLOCK) && r == NULL);
126 return r;
127}
128
129LogMessage *Get() {
130 return static_cast<LogMessage *>(aos_queue_get_msg(queue));
131}
132
133void Free(const LogMessage *msg) {
134 aos_queue_free_msg(queue, msg);
135}
136
137void Write(LogMessage *msg) {
138 if (aos_queue_write_msg_free(queue, msg, OVERRIDE) < 0) {
139 LOG(FATAL, "writing failed");
140 }
141}
142
143} // namespace atom
144} // namespace logging
145} // namespace aos