00001 /** @file rutz/backtrace.cc represents the state of the call stack as 00002 given by GVX_TRACE statements */ 00003 /////////////////////////////////////////////////////////////////////// 00004 // 00005 // Copyright (c) 1999-2004 California Institute of Technology 00006 // Copyright (c) 2004-2007 University of Southern California 00007 // Rob Peters <rjpeters at usc dot edu> 00008 // 00009 // created: Wed Oct 13 16:33:19 2004 00010 // commit: $Id: backtrace.cc 8249 2007-04-12 06:03:40Z rjpeters $ 00011 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/backtrace.cc $ 00012 // 00013 // -------------------------------------------------------------------- 00014 // 00015 // This file is part of GroovX. 00016 // [http://ilab.usc.edu/rjpeters/groovx/] 00017 // 00018 // GroovX is free software; you can redistribute it and/or modify it 00019 // under the terms of the GNU General Public License as published by 00020 // the Free Software Foundation; either version 2 of the License, or 00021 // (at your option) any later version. 00022 // 00023 // GroovX is distributed in the hope that it will be useful, but 00024 // WITHOUT ANY WARRANTY; without even the implied warranty of 00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00026 // General Public License for more details. 00027 // 00028 // You should have received a copy of the GNU General Public License 00029 // along with GroovX; if not, write to the Free Software Foundation, 00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00031 // 00032 /////////////////////////////////////////////////////////////////////// 00033 00034 #ifndef GROOVX_RUTZ_BACKTRACE_CC_UTC20050626084019_DEFINED 00035 #define GROOVX_RUTZ_BACKTRACE_CC_UTC20050626084019_DEFINED 00036 00037 #include "rutz/backtrace.h" 00038 00039 #include "rutz/abort.h" 00040 #include "rutz/prof.h" 00041 00042 #include <cstdio> // for fprintf() 00043 #include <ostream> 00044 #include <pthread.h> 00045 00046 namespace 00047 { 00048 // thread-local storage (see rutz::backtrace::current() below) 00049 pthread_key_t current_backtrace_key; 00050 pthread_once_t current_backtrace_key_once = PTHREAD_ONCE_INIT; 00051 00052 void current_backtrace_destroy(void* bt) 00053 { 00054 delete static_cast<rutz::backtrace*>(bt); 00055 } 00056 00057 void current_backtrace_key_alloc() 00058 { 00059 pthread_key_create(¤t_backtrace_key, 00060 ¤t_backtrace_destroy); 00061 } 00062 } 00063 00064 /////////////////////////////////////////////////////////////////////// 00065 // 00066 // rutz::backtrace member definitions 00067 // 00068 /////////////////////////////////////////////////////////////////////// 00069 00070 rutz::backtrace::backtrace() throw() : 00071 m_vec() 00072 {} 00073 00074 rutz::backtrace::backtrace(const backtrace& other) throw() : 00075 m_vec(other.m_vec) 00076 {} 00077 00078 rutz::backtrace& rutz::backtrace::operator=(const backtrace& other) throw() 00079 { 00080 m_vec = other.m_vec; 00081 return *this; 00082 } 00083 00084 rutz::backtrace::~backtrace() throw() 00085 {} 00086 00087 rutz::backtrace& rutz::backtrace::current() throw() 00088 { 00089 // we need one backtrace per thread, so we use pthreads thread-local 00090 // storage to set up that association 00091 00092 pthread_once(¤t_backtrace_key_once, 00093 ¤t_backtrace_key_alloc); 00094 00095 void* const ptr = pthread_getspecific(current_backtrace_key); 00096 00097 if (ptr != 0) 00098 { 00099 return *(static_cast<rutz::backtrace*>(ptr)); 00100 } 00101 00102 // else... 00103 rutz::backtrace* const bt = new (std::nothrow) rutz::backtrace; 00104 00105 if (bt == 0) 00106 GVX_ABORT("memory allocation failed"); 00107 00108 pthread_setspecific(current_backtrace_key, 00109 static_cast<void*>(bt)); 00110 00111 return *bt; 00112 } 00113 00114 bool rutz::backtrace::push(rutz::prof* p) throw() 00115 { 00116 return m_vec.push(p); 00117 } 00118 00119 void rutz::backtrace::pop() throw() 00120 { 00121 m_vec.pop(); 00122 } 00123 00124 unsigned int rutz::backtrace::size() const throw() 00125 { 00126 return m_vec.size(); 00127 } 00128 00129 rutz::prof* rutz::backtrace::top() const throw() 00130 { 00131 return m_vec.top(); 00132 } 00133 00134 rutz::prof* rutz::backtrace::at(unsigned int i) const throw() 00135 { 00136 return m_vec.at(i); 00137 } 00138 00139 void rutz::backtrace::print() const throw() 00140 { 00141 const unsigned int end = size(); 00142 00143 if (end == 0) 00144 return; // don't print anything if we have an empty backtrace 00145 00146 fprintf(stderr, "stack trace:\n"); 00147 00148 unsigned int i = 0; 00149 unsigned int ri = end-1; 00150 00151 for (; i < end; ++i, --ri) 00152 { 00153 fprintf(stderr, "\t[%d] %s\n", int(i), 00154 m_vec.at(ri)->context_name()); 00155 } 00156 } 00157 00158 void rutz::backtrace::print(std::ostream& os) const throw() 00159 { 00160 const unsigned int end = size(); 00161 00162 if (end == 0) 00163 return; // don't print anything if we have an empty backtrace 00164 00165 os.exceptions(std::ios::goodbit); 00166 00167 os << "stack trace:\n"; 00168 00169 unsigned int i = 0; 00170 unsigned int ri = end-1; 00171 00172 for (; i < end; ++i, --ri) 00173 { 00174 os << "\t[" << i << "] " 00175 << m_vec.at(ri)->context_name() << '\n'; 00176 } 00177 00178 os << std::flush; 00179 } 00180 00181 static const char __attribute__((used)) vcid_groovx_rutz_backtrace_cc_utc20050626084019[] = "$Id: backtrace.cc 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/backtrace.cc $"; 00182 #endif // !GROOVX_RUTZ_BACKTRACE_CC_UTC20050626084019_DEFINED