Add -lpthread in addition to -pthread on Linux.
[platform/upstream/glog.git] / src / utilities.cc
1 // Copyright 2008 Google Inc. All Rights Reserved.
2 // Author: hamaji@google.com (Shinichiro Hamaji)
3
4 #include "utilities.h"
5
6 #include <signal.h>
7 #include <sys/time.h>
8 #include <time.h>
9
10 #include "base/googleinit.h"
11 #include "stacktrace.h"
12 #include "symbolize.h"
13
14 using std::string;
15
16 _START_GOOGLE_NAMESPACE_
17
18 static const char* g_program_invocation_short_name = NULL;
19 static pthread_t g_main_thread_id;
20
21 // The following APIs are all internal.
22 #ifdef HAVE_STACKTRACE
23
24 #include "stacktrace.h"
25 #include "symbolize.h"
26 #include "base/commandlineflags.h"
27
28 DEFINE_bool(symbolize_stacktrace, true,
29             "Symbolize the stack trace in the tombstone");
30
31 typedef void DebugWriter(const char*, void*);
32
33 // The %p field width for printf() functions is two characters per byte.
34 // For some environments, add two extra bytes for the leading "0x".
35 static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
36
37 static void DebugWriteToStderr(const char* data, void *unused) {
38   // This one is signal-safe.
39   write(STDERR_FILENO, data, strlen(data));
40 }
41
42 // Print a program counter and its symbol name.
43 static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
44                             const char * const prefix) {
45   char tmp[1024];
46   const char *symbol = "(unknown)";
47   // Symbolizes the previous address of pc because pc may be in the
48   // next function.  The overrun happens when the function ends with
49   // a call to a function annotated noreturn (e.g. CHECK).
50   if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
51       symbol = tmp;
52   }
53   char buf[1024];
54   snprintf(buf, sizeof(buf), "%s@ %*p  %s\n",
55            prefix, kPrintfPointerFieldWidth, pc, symbol);
56   writerfn(buf, arg);
57 }
58
59 // Print a program counter and the corresponding stack frame size.
60 static void DumpPCAndFrameSize(DebugWriter *writerfn, void *arg, void *pc,
61                                int framesize, const char * const prefix) {
62   char buf[100];
63   if (framesize <= 0) {
64     snprintf(buf, sizeof(buf), "%s@ %*p  (unknown)\n",
65              prefix, kPrintfPointerFieldWidth, pc);
66   } else {
67     snprintf(buf, sizeof(buf), "%s@ %*p  %9d\n",
68              prefix, kPrintfPointerFieldWidth, pc, framesize);
69   }
70   writerfn(buf, arg);
71 }
72
73 static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
74                    const char * const prefix) {
75   char buf[100];
76   snprintf(buf, sizeof(buf), "%s@ %*p\n",
77            prefix, kPrintfPointerFieldWidth, pc);
78   writerfn(buf, arg);
79 }
80
81 // Dump current stack trace as directed by writerfn
82 static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
83   // Print stack trace
84   void* stack[32];
85   int depth = GetStackTrace(stack, sizeof(stack)/sizeof(*stack), skip_count+1);
86   for (int i = 0; i < depth; i++) {
87 #if defined(HAVE_SYMBOLIZE)
88     if (FLAGS_symbolize_stacktrace) {
89       DumpPCAndSymbol(writerfn, arg, stack[i], "    ");
90     } else {
91       DumpPC(writerfn, arg, stack[i], "    ");
92     }
93 #else
94     DumpPC(writerfn, arg, stack[i], "    ");
95 #endif
96   }
97 }
98
99 static void DumpStackTraceAndExit() {
100   DumpStackTrace(1, DebugWriteToStderr, NULL);
101
102   // Set the default signal handler for SIGABRT, to avoid invoking our
103   // own signal handler installed by InstallFailedSignalHandler().
104   struct sigaction sig_action = {};  // Zero-clear.
105   sigemptyset(&sig_action.sa_mask);
106   sig_action.sa_handler = SIG_DFL;
107   sigaction(SIGABRT, &sig_action, NULL);
108
109   abort();
110 }
111
112 #endif  // HAVE_STACKTRACE
113
114 namespace glog_internal_namespace_ {
115
116 const char* ProgramInvocationShortName() {
117   if (g_program_invocation_short_name != NULL) {
118     return g_program_invocation_short_name;
119   } else {
120     // TODO(hamaji): Use /proc/self/cmdline and so?
121     return "UNKNOWN";
122   }
123 }
124
125 bool IsGoogleLoggingInitialized() {
126   return g_program_invocation_short_name != NULL;
127 }
128
129 bool is_default_thread() {
130   if (g_program_invocation_short_name == NULL) {
131     // InitGoogleLogging() not yet called, so unlikely to be in a different
132     // thread
133     return true;
134   } else {
135     return pthread_equal(pthread_self(), g_main_thread_id);
136   }
137 }
138
139 int64 CycleClock_Now() {
140   // TODO(hamaji): temporary impementation - it might be too slow.
141   struct timeval tv;
142   gettimeofday(&tv, NULL);
143   return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
144 }
145
146 int64 UsecToCycles(int64 usec) {
147   return usec;
148 }
149
150 static int32 g_main_thread_pid = getpid();
151 int32 GetMainThreadPid() {
152   return g_main_thread_pid;
153 }
154
155 static string g_my_user_name;
156 const string& MyUserName() {
157   return g_my_user_name;
158 }
159 static void MyUserNameInitializer() {
160   // TODO(hamaji): Probably this is not portable.
161   const char* user = getenv("USER");
162   if (user != NULL) {
163     g_my_user_name = user;
164   } else {
165     g_my_user_name = "invalid-user";
166   }
167 }
168 REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
169
170 }  // namespace glog_internal_namespace_
171
172 void InitGoogleLogging(const char* argv0) {
173   const char* slash = strrchr(argv0, '/');
174 #ifdef OS_WINDOWS
175   if (!slash)  slash = strrchr(argv0, '\\');
176 #endif
177   g_program_invocation_short_name = slash ? slash + 1 : argv0;
178   g_main_thread_id = pthread_self();
179
180 #ifdef HAVE_STACKTRACE
181   InstallFailureFunction(&DumpStackTraceAndExit);
182 #endif
183 }
184
185 _END_GOOGLE_NAMESPACE_
186
187 // Make an implementation of stacktrace compiled.
188 #ifdef STACKTRACE_H
189 # include STACKTRACE_H
190 #endif