blob: 72c19703a9a9113931f5a6de0474b1ed491577f5 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/logging/context.h"
Austin Schuh044e18b2015-10-21 20:17:09 -07002
Alex Perrycb7da4b2019-08-28 19:35:56 -07003#ifndef _GNU_SOURCE
4#define _GNU_SOURCE /* See feature_test_macros(7) */
5#endif
6
Austin Schuh044e18b2015-10-21 20:17:09 -07007#include <string.h>
Brian Silvermancb5da1f2015-12-05 22:19:58 -05008#include <sys/prctl.h>
9#include <sys/types.h>
10#include <unistd.h>
11
12#include <string>
13
Alex Perrycb7da4b2019-08-28 19:35:56 -070014#include <errno.h>
15
16extern char *program_invocation_name;
17extern char *program_invocation_short_name;
18
John Park33858a32018-09-28 23:05:48 -070019#include "aos/die.h"
John Park398c74a2018-10-20 21:17:39 -070020#include "aos/complex_thread_local.h"
Austin Schuh044e18b2015-10-21 20:17:09 -070021
22namespace aos {
23namespace logging {
24namespace internal {
Brian Silvermancb5da1f2015-12-05 22:19:58 -050025namespace {
26
27// TODO(brians): Differentiate between threads with the same name in the same
28// process.
29
30::std::string GetMyName() {
31 // The maximum number of characters that can make up a thread name.
32 // The docs are unclear if it can be 16 characters with no '\0', so we'll be
33 // safe by adding our own where necessary.
34 static const size_t kThreadNameLength = 16;
35
36 ::std::string process_name(program_invocation_short_name);
37
38 char thread_name_array[kThreadNameLength + 1];
39 if (prctl(PR_GET_NAME, thread_name_array) != 0) {
40 PDie("prctl(PR_GET_NAME, %p) failed", thread_name_array);
41 }
42 thread_name_array[sizeof(thread_name_array) - 1] = '\0';
43 ::std::string thread_name(thread_name_array);
44
45 // If the first bunch of characters are the same.
46 // We cut off comparing at the shorter of the 2 strings because one or the
47 // other often ends up cut off.
48 if (strncmp(thread_name.c_str(), process_name.c_str(),
49 ::std::min(thread_name.length(), process_name.length())) == 0) {
50 // This thread doesn't have an actual name.
51 return process_name;
52 }
53
54 return process_name + '.' + thread_name;
55}
56
57::aos::ComplexThreadLocal<Context> my_context;
58
59// True if we're going to delete the current Context object ASAP. The
60// reason for doing this instead of just deleting them is that tsan (at least)
61// doesn't like it when pthread_atfork handlers do complicated stuff and it's
62// not a great idea anyways.
63thread_local bool delete_current_context(false);
64
65} // namespace
Austin Schuh044e18b2015-10-21 20:17:09 -070066
67::std::atomic<LogImplementation *> global_top_implementation(NULL);
68
69Context::Context()
70 : implementation(global_top_implementation.load()),
71 sequence(0) {
72 cork_data.Reset();
73}
74
Brian Silvermancb5da1f2015-12-05 22:19:58 -050075// Used in aos/linux_code/init.cc when a thread's name is changed.
76void ReloadThreadName() {
77 if (my_context.created()) {
78 ::std::string my_name = GetMyName();
79 if (my_name.size() + 1 > sizeof(Context::name)) {
80 Die("logging: process/thread name '%s' is too long\n",
81 my_name.c_str());
82 }
83 strcpy(my_context->name, my_name.c_str());
84 my_context->name_size = my_name.size();
85 }
86}
87
88Context *Context::Get() {
89 if (__builtin_expect(delete_current_context, false)) {
90 my_context.Clear();
91 delete_current_context = false;
92 }
93 if (__builtin_expect(!my_context.created(), false)) {
94 my_context.Create();
95 ReloadThreadName();
96 my_context->source = getpid();
97 }
98 return my_context.get();
99}
100
101void Context::Delete() {
102 delete_current_context = true;
103}
104
Austin Schuh044e18b2015-10-21 20:17:09 -0700105} // namespace internal
106} // namespace logging
107} // namespace aos