PageRenderTime 56ms CodeModel.GetById 13ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/third_party/glog/src/utilities.cc

http://github.com/tomahawk-player/tomahawk
C++ | 346 lines | 234 code | 51 blank | 61 comment | 25 complexity | 423caa7488948002bb742d14a8097dce MD5 | raw file
  1// Copyright (c) 2008, Google Inc.
  2// All rights reserved.
  3//
  4// Redistribution and use in source and binary forms, with or without
  5// modification, are permitted provided that the following conditions are
  6// met:
  7//
  8//     * Redistributions of source code must retain the above copyright
  9// notice, this list of conditions and the following disclaimer.
 10//     * Redistributions in binary form must reproduce the above
 11// copyright notice, this list of conditions and the following disclaimer
 12// in the documentation and/or other materials provided with the
 13// distribution.
 14//     * Neither the name of Google Inc. nor the names of its
 15// contributors may be used to endorse or promote products derived from
 16// this software without specific prior written permission.
 17//
 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 29//
 30// Author: Shinichiro Hamaji
 31
 32#include "utilities.h"
 33
 34#include <stdio.h>
 35#include <stdlib.h>
 36
 37#include <signal.h>
 38#ifdef HAVE_SYS_TIME_H
 39# include <sys/time.h>
 40#endif
 41#include <time.h>
 42#if defined(HAVE_SYSCALL_H)
 43#include <syscall.h>                 // for syscall()
 44#elif defined(HAVE_SYS_SYSCALL_H)
 45#include <sys/syscall.h>                 // for syscall()
 46#endif
 47#ifdef HAVE_SYSLOG_H
 48# include <syslog.h>
 49#endif
 50
 51#include "base/googleinit.h"
 52
 53using std::string;
 54
 55_START_GOOGLE_NAMESPACE_
 56
 57static const char* g_program_invocation_short_name = NULL;
 58static pthread_t g_main_thread_id;
 59
 60_END_GOOGLE_NAMESPACE_
 61
 62// The following APIs are all internal.
 63#ifdef HAVE_STACKTRACE
 64
 65#include "stacktrace.h"
 66#include "symbolize.h"
 67#include "base/commandlineflags.h"
 68
 69GLOG_DEFINE_bool(symbolize_stacktrace, true,
 70                 "Symbolize the stack trace in the tombstone");
 71
 72_START_GOOGLE_NAMESPACE_
 73
 74typedef void DebugWriter(const char*, void*);
 75
 76// The %p field width for printf() functions is two characters per byte.
 77// For some environments, add two extra bytes for the leading "0x".
 78static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
 79
 80static void DebugWriteToStderr(const char* data, void *unused) {
 81  // This one is signal-safe.
 82  if (write(STDERR_FILENO, data, strlen(data)) < 0) {
 83    // Ignore errors.
 84  }
 85}
 86
 87void DebugWriteToString(const char* data, void *arg) {
 88  reinterpret_cast<string*>(arg)->append(data);
 89}
 90
 91#ifdef HAVE_SYMBOLIZE
 92// Print a program counter and its symbol name.
 93static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
 94                            const char * const prefix) {
 95  char tmp[1024];
 96  const char *symbol = "(unknown)";
 97  // Symbolizes the previous address of pc because pc may be in the
 98  // next function.  The overrun happens when the function ends with
 99  // a call to a function annotated noreturn (e.g. CHECK).
100  if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
101      symbol = tmp;
102  }
103  char buf[1024];
104  snprintf(buf, sizeof(buf), "%s@ %*p  %s\n",
105           prefix, kPrintfPointerFieldWidth, pc, symbol);
106  writerfn(buf, arg);
107}
108#endif
109
110static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
111                   const char * const prefix) {
112  char buf[100];
113  snprintf(buf, sizeof(buf), "%s@ %*p\n",
114           prefix, kPrintfPointerFieldWidth, pc);
115  writerfn(buf, arg);
116}
117
118// Dump current stack trace as directed by writerfn
119static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
120  // Print stack trace
121  void* stack[32];
122  int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
123  for (int i = 0; i < depth; i++) {
124#if defined(HAVE_SYMBOLIZE)
125    if (FLAGS_symbolize_stacktrace) {
126      DumpPCAndSymbol(writerfn, arg, stack[i], "    ");
127    } else {
128      DumpPC(writerfn, arg, stack[i], "    ");
129    }
130#else
131    DumpPC(writerfn, arg, stack[i], "    ");
132#endif
133  }
134}
135
136static void DumpStackTraceAndExit() {
137  DumpStackTrace(1, DebugWriteToStderr, NULL);
138
139  // Set the default signal handler for SIGABRT, to avoid invoking our
140  // own signal handler installed by InstallFailedSignalHandler().
141  struct sigaction sig_action;
142  memset(&sig_action, 0, sizeof(sig_action));
143  sigemptyset(&sig_action.sa_mask);
144  sig_action.sa_handler = SIG_DFL;
145  sigaction(SIGABRT, &sig_action, NULL);
146
147  abort();
148}
149
150_END_GOOGLE_NAMESPACE_
151
152#endif  // HAVE_STACKTRACE
153
154_START_GOOGLE_NAMESPACE_
155
156namespace glog_internal_namespace_ {
157
158const char* ProgramInvocationShortName() {
159  if (g_program_invocation_short_name != NULL) {
160    return g_program_invocation_short_name;
161  } else {
162    // TODO(hamaji): Use /proc/self/cmdline and so?
163    return "UNKNOWN";
164  }
165}
166
167bool IsGoogleLoggingInitialized() {
168  return g_program_invocation_short_name != NULL;
169}
170
171bool is_default_thread() {
172  if (g_program_invocation_short_name == NULL) {
173    // InitGoogleLogging() not yet called, so unlikely to be in a different
174    // thread
175    return true;
176  } else {
177    return pthread_equal(pthread_self(), g_main_thread_id);
178  }
179}
180
181#ifdef OS_WINDOWS
182struct timeval {
183  long tv_sec, tv_usec;
184};
185
186// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
187// See COPYING for copyright information.
188static int gettimeofday(struct timeval *tv, void* tz) {
189#define EPOCHFILETIME (116444736000000000ULL)
190  FILETIME ft;
191  LARGE_INTEGER li;
192  uint64 tt;
193
194  GetSystemTimeAsFileTime(&ft);
195  li.LowPart = ft.dwLowDateTime;
196  li.HighPart = ft.dwHighDateTime;
197  tt = (li.QuadPart - EPOCHFILETIME) / 10;
198  tv->tv_sec = tt / 1000000;
199  tv->tv_usec = tt % 1000000;
200
201  return 0;
202}
203#endif
204
205int64 CycleClock_Now() {
206  // TODO(hamaji): temporary impementation - it might be too slow.
207  struct timeval tv;
208  gettimeofday(&tv, NULL);
209  return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
210}
211
212int64 UsecToCycles(int64 usec) {
213  return usec;
214}
215
216WallTime WallTime_Now() {
217  // Now, cycle clock is retuning microseconds since the epoch.
218  return CycleClock_Now() * 0.000001;
219}
220
221static int32 g_main_thread_pid = getpid();
222int32 GetMainThreadPid() {
223  return g_main_thread_pid;
224}
225
226bool PidHasChanged() {
227  int32 pid = getpid();
228  if (g_main_thread_pid == pid) {
229    return false;
230  }
231  g_main_thread_pid = pid;
232  return true;
233}
234
235pid_t GetTID() {
236  // On Linux and FreeBSD, we try to use gettid().
237#if defined OS_LINUX || defined OS_FREEBSD || defined OS_MACOSX
238#ifndef __NR_gettid
239#ifdef OS_MACOSX
240#define __NR_gettid SYS_gettid
241#elif ! defined __i386__
242#error "Must define __NR_gettid for non-x86 platforms"
243#else
244#define __NR_gettid 224
245#endif
246#endif
247  static bool lacks_gettid = false;
248  if (!lacks_gettid) {
249    pid_t tid = syscall(__NR_gettid);
250    if (tid != -1) {
251      return tid;
252    }
253    // Technically, this variable has to be volatile, but there is a small
254    // performance penalty in accessing volatile variables and there should
255    // not be any serious adverse effect if a thread does not immediately see
256    // the value change to "true".
257    lacks_gettid = true;
258  }
259#endif  // OS_LINUX || OS_FREEBSD
260
261  // If gettid() could not be used, we use one of the following.
262#if defined OS_LINUX
263  return getpid();  // Linux:  getpid returns thread ID when gettid is absent
264#elif defined OS_WINDOWS || defined OS_CYGWIN
265  return GetCurrentThreadId();
266#else
267  // If none of the techniques above worked, we use pthread_self().
268  return (pid_t)(uintptr_t)pthread_self();
269#endif
270}
271
272const char* const_basename(const char* filepath) {
273  const char* base = strrchr(filepath, '/');
274#ifdef OS_WINDOWS  // Look for either path separator in Windows
275  if (!base)
276    base = strrchr(filepath, '\\');
277#endif
278  return base ? (base+1) : filepath;
279}
280
281static string g_my_user_name;
282const string& MyUserName() {
283  return g_my_user_name;
284}
285static void MyUserNameInitializer() {
286  // TODO(hamaji): Probably this is not portable.
287#if defined(OS_WINDOWS)
288  const char* user = getenv("USERNAME");
289#else
290  const char* user = getenv("USER");
291#endif
292  if (user != NULL) {
293    g_my_user_name = user;
294  } else {
295    g_my_user_name = "invalid-user";
296  }
297}
298REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
299
300#ifdef HAVE_STACKTRACE
301void DumpStackTraceToString(string* stacktrace) {
302  DumpStackTrace(1, DebugWriteToString, stacktrace);
303}
304#endif
305
306// We use an atomic operation to prevent problems with calling CrashReason
307// from inside the Mutex implementation (potentially through RAW_CHECK).
308static const CrashReason* g_reason = 0;
309
310void SetCrashReason(const CrashReason* r) {
311  sync_val_compare_and_swap(&g_reason,
312                            reinterpret_cast<const CrashReason*>(0),
313                            r);
314}
315
316void InitGoogleLoggingUtilities(const char* argv0) {
317  CHECK(!IsGoogleLoggingInitialized())
318      << "You called InitGoogleLogging() twice!";
319  const char* slash = strrchr(argv0, '/');
320#ifdef OS_WINDOWS
321  if (!slash)  slash = strrchr(argv0, '\\');
322#endif
323  g_program_invocation_short_name = slash ? slash + 1 : argv0;
324  g_main_thread_id = pthread_self();
325
326#ifdef HAVE_STACKTRACE
327  InstallFailureFunction(&DumpStackTraceAndExit);
328#endif
329}
330
331void ShutdownGoogleLoggingUtilities() {
332  CHECK(IsGoogleLoggingInitialized())
333      << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
334#ifdef HAVE_SYSLOG_H
335  closelog();
336#endif
337}
338
339}  // namespace glog_internal_namespace_
340
341_END_GOOGLE_NAMESPACE_
342
343// Make an implementation of stacktrace compiled.
344#ifdef STACKTRACE_H
345# include STACKTRACE_H
346#endif