]> git.lizzy.rs Git - dragonfireclient.git/blob - src/debug.h
Add support for IPv6
[dragonfireclient.git] / src / debug.h
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef DEBUG_HEADER
21 #define DEBUG_HEADER
22
23 #include <stdio.h>
24 #include <jmutex.h>
25 #include <jmutexautolock.h>
26 #include <iostream>
27 #include "irrlichttypes.h"
28 #include <irrMap.h>
29 #include "threads.h"
30 #include "gettime.h"
31 #include "exceptions.h"
32 #include <map>
33
34 #ifdef _WIN32
35         #define WIN32_LEAN_AND_MEAN
36         #ifndef _WIN32_WINNT
37                 #define _WIN32_WINNT 0x0501
38         #endif
39         #include <windows.h>
40         #ifdef _MSC_VER
41                 #include <eh.h>
42         #endif
43 #else
44 #endif
45
46 // Whether to catch all std::exceptions.
47 // Assert will be called on such an event.
48 // In debug mode, leave these for the debugger and don't catch them.
49 #ifdef NDEBUG
50         #define CATCH_UNHANDLED_EXCEPTIONS 1
51 #else
52         #define CATCH_UNHANDLED_EXCEPTIONS 0
53 #endif
54
55 /*
56         Debug output
57 */
58
59 #define DTIME (getTimestamp()+": ")
60
61 #define DEBUGSTREAM_COUNT 2
62
63 extern FILE *g_debugstreams[DEBUGSTREAM_COUNT];
64
65 extern void debugstreams_init(bool disable_stderr, const char *filename);
66 extern void debugstreams_deinit();
67
68 #define DEBUGPRINT(...)\
69 {\
70         for(int i=0; i<DEBUGSTREAM_COUNT; i++)\
71         {\
72                 if(g_debugstreams[i] != NULL){\
73                         fprintf(g_debugstreams[i], __VA_ARGS__);\
74                         fflush(g_debugstreams[i]);\
75                 }\
76         }\
77 }
78
79 class Debugbuf : public std::streambuf
80 {
81 public:
82         Debugbuf(bool disable_stderr)
83         {
84                 m_disable_stderr = disable_stderr;
85         }
86
87         int overflow(int c)
88         {
89                 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
90                 {
91                         if(g_debugstreams[i] == stderr && m_disable_stderr)
92                                 continue;
93                         if(g_debugstreams[i] != NULL)
94                                 (void)fwrite(&c, 1, 1, g_debugstreams[i]);
95                         //TODO: Is this slow?
96                         fflush(g_debugstreams[i]);
97                 }
98                 
99                 return c;
100         }
101         std::streamsize xsputn(const char *s, std::streamsize n)
102         {
103                 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
104                 {
105                         if(g_debugstreams[i] == stderr && m_disable_stderr)
106                                 continue;
107                         if(g_debugstreams[i] != NULL)
108                                 (void)fwrite(s, 1, n, g_debugstreams[i]);
109                         //TODO: Is this slow?
110                         fflush(g_debugstreams[i]);
111                 }
112
113                 return n;
114         }
115         
116 private:
117         bool m_disable_stderr;
118 };
119
120 // This is used to redirect output to /dev/null
121 class Nullstream : public std::ostream {
122 public:
123         Nullstream():
124                 std::ostream(0)
125         {
126         }
127 private:
128 };
129
130 extern Debugbuf debugbuf;
131 extern std::ostream dstream;
132 extern std::ostream dstream_no_stderr;
133 extern Nullstream dummyout;
134
135 /*
136         Assert
137 */
138
139 __NORETURN extern void assert_fail(
140                 const char *assertion, const char *file,
141                 unsigned int line, const char *function);
142
143 #define ASSERT(expr)\
144         ((expr)\
145         ? (void)(0)\
146         : assert_fail(#expr, __FILE__, __LINE__, __FUNCTION_NAME))
147
148 #define assert(expr) ASSERT(expr)
149
150 /*
151         DebugStack
152 */
153
154 #define DEBUG_STACK_SIZE 50
155 #define DEBUG_STACK_TEXT_SIZE 300
156
157 struct DebugStack
158 {
159         DebugStack(threadid_t id);
160         void print(FILE *file, bool everything);
161         void print(std::ostream &os, bool everything);
162         
163         threadid_t threadid;
164         char stack[DEBUG_STACK_SIZE][DEBUG_STACK_TEXT_SIZE];
165         int stack_i; // Points to the lowest empty position
166         int stack_max_i; // Highest i that was seen
167 };
168
169 extern std::map<threadid_t, DebugStack*> g_debug_stacks;
170 extern JMutex g_debug_stacks_mutex;
171
172 extern void debug_stacks_init();
173 extern void debug_stacks_print_to(std::ostream &os);
174 extern void debug_stacks_print();
175
176 class DebugStacker
177 {
178 public:
179         DebugStacker(const char *text);
180         ~DebugStacker();
181
182 private:
183         DebugStack *m_stack;
184         bool m_overflowed;
185 };
186
187 #define DSTACK(msg)\
188         DebugStacker __debug_stacker(msg);
189
190 #define DSTACKF(...)\
191         char __buf[DEBUG_STACK_TEXT_SIZE];\
192         snprintf(__buf,\
193                         DEBUG_STACK_TEXT_SIZE, __VA_ARGS__);\
194         DebugStacker __debug_stacker(__buf);
195
196 /*
197         Packet counter
198 */
199
200 class PacketCounter
201 {
202 public:
203         PacketCounter()
204         {
205         }
206
207         void add(u16 command)
208         {
209                 std::map<u16, u16>::iterator n = m_packets.find(command);
210                 if(n == m_packets.end())
211                 {
212                         m_packets[command] = 1;
213                 }
214                 else
215                 {
216                         n->second++;
217                 }
218         }
219
220         void clear()
221         {
222                 for(std::map<u16, u16>::iterator
223                                 i = m_packets.begin();
224                                 i != m_packets.end(); ++i)
225                 {
226                         i->second = 0;
227                 }
228         }
229
230         void print(std::ostream &o)
231         {
232                 for(std::map<u16, u16>::iterator
233                                 i = m_packets.begin();
234                                 i != m_packets.end(); ++i)
235                 {
236                         o<<"cmd "<<i->first
237                                         <<" count "<<i->second
238                                         <<std::endl;
239                 }
240         }
241
242 private:
243         // command, count
244         std::map<u16, u16> m_packets;
245 };
246
247 /*
248         These should be put into every thread
249 */
250
251 #if CATCH_UNHANDLED_EXCEPTIONS == 1
252         #define BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER try{
253         #define END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)\
254                 }catch(std::exception &e){\
255                         logstream<<"ERROR: An unhandled exception occurred: "\
256                                         <<e.what()<<std::endl;\
257                         assert(0);\
258                 }
259         #ifdef _WIN32 // Windows
260                 #ifdef _MSC_VER // MSVC
261 void se_trans_func(unsigned int, EXCEPTION_POINTERS*);
262
263 class FatalSystemException : public BaseException
264 {
265 public:
266         FatalSystemException(const char *s):
267                 BaseException(s)
268         {}
269 };
270                         #define BEGIN_DEBUG_EXCEPTION_HANDLER \
271                                 BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER\
272                                 _set_se_translator(se_trans_func);
273
274                         #define END_DEBUG_EXCEPTION_HANDLER(logstream) \
275                                 END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)
276                 #else // Probably mingw
277                         #define BEGIN_DEBUG_EXCEPTION_HANDLER\
278                                 BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER
279                         #define END_DEBUG_EXCEPTION_HANDLER(logstream)\
280                                 END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)
281                 #endif
282         #else // Posix
283                 #define BEGIN_DEBUG_EXCEPTION_HANDLER\
284                         BEGIN_PORTABLE_DEBUG_EXCEPTION_HANDLER
285                 #define END_DEBUG_EXCEPTION_HANDLER(logstream)\
286                         END_PORTABLE_DEBUG_EXCEPTION_HANDLER(logstream)
287         #endif
288 #else
289         // Dummy ones
290         #define BEGIN_DEBUG_EXCEPTION_HANDLER
291         #define END_DEBUG_EXCEPTION_HANDLER(logstream)
292 #endif
293
294 #endif // DEBUG_HEADER
295
296