new home directory
[feisty_meow.git] / nucleus / library / application / callstack_tracker.h
1 #ifndef CALLSTACK_TRACKER_CLASS
2 #define CALLSTACK_TRACKER_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : callstack_tracker                                                 *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 2007-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include "definitions.h"
19
20 #ifdef ENABLE_CALLSTACK_TRACKING
21
22 #include "build_configuration.h"
23 #include "root_object.h"
24
25 namespace application {
26
27 // forward.
28 class callstack_records;
29 class callstack_tracker;
30
31 //////////////
32
33 callstack_tracker BASIS_EXTERN &program_wide_stack_trace();
34   //!< a global object that can be used to track the runtime callstack.
35
36 //////////////
37
38 //! This object can provide a backtrace at runtime of the invoking methods.
39 /*!
40   The callstack tracking is hooked in through the FUNCDEF macros used to
41   set function names for logging.  Thus it will only be visible if those
42   macros are used fairly carefully or if people invoke the stack frame addition
43   method themselves.
44 */
45
46 class callstack_tracker
47 {
48 public:
49   callstack_tracker();
50   virtual ~callstack_tracker();
51
52   DEFINE_CLASS_NAME("callstack_tracker");
53
54   bool push_frame(const char *class_name, const char *func, const char *file,
55           int line);
56     //!< adds a new stack from for the "class_name" in "function" at the "line".
57     /*!< this function should be invoked when entering a new stack frame.  the
58     "file" can be gotten from the __FILE__ macro and the "line" number can come
59     from __LINE__, but the "class_name" and "func" must be tracked some other
60     way.  we recommend the FUNCDEF macro.  this function might return false if
61     there is no longer any room for tracking more frames; that is a serious
62     issue that might indicate a runaway recursion or infinite loop. */
63
64   bool pop_frame();
65     //!< removes the last callstack frame off from our tracking.
66
67   bool update_line(int line);
68     //!< sets the line number within the current stack frame.
69     /*!< the current frame can reside across several line numbers, so this
70     allows the code to be more specific about the location of an invocation. */
71
72   char *full_trace() const;
73     //!< provides the current stack trace in a newly malloc'd string.
74     /*!< the user *must* free() the string returned. */
75
76   int full_trace_size() const;
77     //!< this returns the number of bytes needed for the above full_trace().
78
79   int depth() const { return _depth; }
80     //!< the current number of frames we know of.
81
82   double frames_in() const { return _frames_in; }
83     //!< reports the number of call stack frames that were added, total.
84
85   double frames_out() const { return _frames_out; }
86     //!< reports the number of call stack frames that were removed, total.
87
88   double highest() const { return _highest; }
89     //!< reports the maximum stack depth seen during the runtime so far.
90
91 private:
92   callstack_records *_bt;  //!< the backtrace records for current program.
93   int _depth;  //!< the current number of frames we know of.
94   double _frames_in;  //!< number of frame additions.
95   double _frames_out;  //!< number of frame removals.
96   double _highest;  //!< the most number of frames in play at once.
97   bool _unusable;  //!< object has already been destroyed.
98 };
99
100 //////////////
101
102 //! a small object that represents a stack trace in progress.
103 /*! the object will automatically be destroyed when the containing scope
104 exits.  this enables a users of the stack tracker to simply label their
105 function name and get the frame added.  if they want finer grained tracking,
106 they should update the line number periodically through their function,
107 especially when memory is about to be allocated or where something might go
108 wrong. */
109
110 class frame_tracking_instance
111 {
112 public:
113   // these are not encapsulated, but be careful with the contents.
114   bool _frame_involved;  //!< has this object been added to the tracker?
115   char *_class, *_func, *_file;  //!< newly allocated copies.
116   int _line;
117
118   frame_tracking_instance(const char *class_name = "", const char *func = "",
119       const char *file = "", int line = 0, bool add_frame = false);
120     //!< as an automatic variable, this can hang onto frame information.
121     /*!< if "add_frame" is true, then this actually adds the stack frame in
122     question to the tracker.  thus if you use this class at the top of your
123     function, such as via the FUNCDEF macro, then you can forget about having
124     to pop the frame later. */
125
126   frame_tracking_instance(const frame_tracking_instance &to_copy);
127
128   ~frame_tracking_instance();
129     //!< releases the information *and* this stack frame in the tracker.
130
131   frame_tracking_instance &operator =(const frame_tracking_instance &to_copy);
132
133   void assign(const char *class_name, const char *func, const char *file,
134           int line);
135     //!< similar to assignment operator but doesn't require an object.
136
137   void clean();
138     //!< throws out our accumulated memory and pops frame if applicable.
139 };
140
141 void update_current_stack_frame_line_number(int line);
142   //!< sets the line number for the current frame in the global stack trace.
143
144 #else // ENABLE_CALLSTACK_TRACKING
145   // bogus replacements for most commonly used callstack tracking support.
146   #define frame_tracking_instance
147   #define __trail_of_function(p1, p2, p3, p4, p5) if (func) {}
148     // the above actually trades on the name of the object we'd normally
149     // define.  it must match the object name in the FUNCDEF macro.
150   #define update_current_stack_frame_line_number(line)
151 #endif // ENABLE_CALLSTACK_TRACKING
152
153 } //namespace.
154
155 #endif // outer guard.
156