Initial files
[oweals/minetest.git] / src / debug.h
1 /*
2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
3 */
4
5 /*
6         Debug stack and assertion
7 */
8
9 #ifndef DEBUG_HEADER
10 #define DEBUG_HEADER
11
12 #include <stdio.h>
13 #include <jmutex.h>
14 #include <jmutexautolock.h>
15 #include <iostream>
16 #include "common_irrlicht.h"
17
18 /*
19         Compatibility stuff
20 */
21
22 #if (defined(WIN32) || defined(_WIN32_WCE))
23 typedef DWORD threadid_t;
24 #define __NORETURN __declspec(noreturn)
25 #define __FUNCTION_NAME __FUNCTION__
26 #else
27 typedef pthread_t threadid_t;
28 #define __NORETURN __attribute__ ((__noreturn__))
29 #define __FUNCTION_NAME __PRETTY_FUNCTION__
30 #endif
31
32 inline threadid_t get_current_thread_id()
33 {
34 #if (defined(WIN32) || defined(_WIN32_WCE))
35         return GetCurrentThreadId();
36 #else
37         return pthread_self();
38 #endif
39 }
40
41 /*
42         Debug output
43 */
44
45 #define DEBUGSTREAM_COUNT 2
46
47 extern FILE *g_debugstreams[DEBUGSTREAM_COUNT];
48
49 extern void debugstreams_init(bool disable_stderr, const char *filename);
50 extern void debugstreams_deinit();
51
52 #define DEBUGPRINT(...)\
53 {\
54         for(int i=0; i<DEBUGSTREAM_COUNT; i++)\
55         {\
56                 if(g_debugstreams[i] != NULL){\
57                         fprintf(g_debugstreams[i], __VA_ARGS__);\
58                         fflush(g_debugstreams[i]);\
59                 }\
60         }\
61 }
62
63 class Debugbuf : public std::streambuf
64 {
65 public:
66         Debugbuf(bool disable_stderr)
67         {
68                 m_disable_stderr = disable_stderr;
69         }
70
71         int overflow(int c)
72         {
73                 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
74                 {
75                         if(g_debugstreams[i] == stderr && m_disable_stderr)
76                                 continue;
77                         if(g_debugstreams[i] != NULL)
78                                 fwrite(&c, 1, 1, g_debugstreams[i]);
79                         //TODO: Is this slow?
80                         fflush(g_debugstreams[i]);
81                 }
82                 
83                 return c;
84         }
85         int xsputn(const char *s, int n)
86         {
87                 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
88                 {
89                         if(g_debugstreams[i] == stderr && m_disable_stderr)
90                                 continue;
91                         if(g_debugstreams[i] != NULL)
92                                 fwrite(s, 1, n, g_debugstreams[i]);
93                         //TODO: Is this slow?
94                         fflush(g_debugstreams[i]);
95                 }
96
97                 return n;
98         }
99         
100 private:
101         bool m_disable_stderr;
102 };
103
104 // This is used to redirect output to /dev/null
105 class Nullstream : public std::ostream {
106 public:
107         Nullstream():
108                 std::ostream(0)
109         {
110         }
111 private:
112 };
113
114 extern Debugbuf debugbuf;
115 extern std::ostream dstream;
116 extern std::ostream dstream_no_stderr;
117 extern Nullstream dummyout;
118
119 /*
120         Assert
121 */
122
123 __NORETURN extern void assert_fail(
124                 const char *assertion, const char *file,
125                 unsigned int line, const char *function);
126
127 #define ASSERT(expr)\
128         ((expr)\
129         ? (void)(0)\
130         : assert_fail(#expr, __FILE__, __LINE__, __FUNCTION_NAME))
131
132 #define assert(expr) ASSERT(expr)
133
134 /*
135         DebugStack
136 */
137
138 #define DEBUG_STACK_SIZE 50
139 #define DEBUG_STACK_TEXT_SIZE 300
140
141 struct DebugStack
142 {
143         DebugStack(threadid_t id);
144         void print(FILE *file, bool everything);
145         
146         threadid_t threadid;
147         char stack[DEBUG_STACK_SIZE][DEBUG_STACK_TEXT_SIZE];
148         int stack_i; // Points to the lowest empty position
149         int stack_max_i; // Highest i that was seen
150 };
151
152 extern core::map<threadid_t, DebugStack*> g_debug_stacks;
153 extern JMutex g_debug_stacks_mutex;
154
155 extern void debug_stacks_init();
156 extern void debug_stacks_print();
157
158 class DebugStacker
159 {
160 public:
161         DebugStacker(const char *text);
162         ~DebugStacker();
163
164 private:
165         DebugStack *m_stack;
166         bool m_overflowed;
167 };
168
169 #define DSTACK(...)\
170         char __buf[DEBUG_STACK_TEXT_SIZE];\
171         snprintf(__buf,\
172                         DEBUG_STACK_TEXT_SIZE, __VA_ARGS__);\
173         DebugStacker __debug_stacker(__buf);
174
175 #endif
176