]> git.lizzy.rs Git - dragonfireclient.git/blob - src/debug.cpp
Added tag working for changeset c37bcfd89dd6
[dragonfireclient.git] / src / debug.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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
21 #include "debug.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #ifdef _WIN32
26         #define WIN32_LEAN_AND_MEAN
27         #include <windows.h>
28         #define sleep_ms(x) Sleep(x)
29 #else
30         #include <unistd.h>
31         #define sleep_ms(x) usleep(x*1000)
32 #endif
33
34 /*
35         Debug output
36 */
37
38 FILE *g_debugstreams[DEBUGSTREAM_COUNT] = {stderr, NULL};
39
40 void debugstreams_init(bool disable_stderr, const char *filename)
41 {
42         if(disable_stderr)
43                 g_debugstreams[0] = NULL;
44
45         if(filename)
46                 g_debugstreams[1] = fopen(filename, "a");
47                 
48         if(g_debugstreams[1])
49         {
50                 fprintf(g_debugstreams[1], "\n\n-------------\n");
51                 fprintf(g_debugstreams[1],     "  Separator  \n");
52                 fprintf(g_debugstreams[1],     "-------------\n\n");
53         }
54 }
55
56 void debugstreams_deinit()
57 {
58         if(g_debugstreams[1] != NULL)
59                 fclose(g_debugstreams[1]);
60 }
61
62 Debugbuf debugbuf(false);
63 std::ostream dstream(&debugbuf);
64 Debugbuf debugbuf_no_stderr(true);
65 std::ostream dstream_no_stderr(&debugbuf_no_stderr);
66 Nullstream dummyout;
67
68 /*
69         Assert
70 */
71
72 void assert_fail(const char *assertion, const char *file,
73                 unsigned int line, const char *function)
74 {
75         DEBUGPRINT("\nIn thread %x:\n"
76                         "%s:%d: %s: Assertion '%s' failed.\n",
77                         (unsigned int)get_current_thread_id(),
78                         file, line, function, assertion);
79         
80         debug_stacks_print();
81
82         if(g_debugstreams[1])
83                 fclose(g_debugstreams[1]);
84
85         //sleep_ms(3000);
86
87         abort();
88 }
89
90 /*
91         DebugStack
92 */
93
94 DebugStack::DebugStack(threadid_t id)
95 {
96         threadid = id;
97         stack_i = 0;
98         stack_max_i = 0;
99 }
100
101 void DebugStack::print(FILE *file, bool everything)
102 {
103         fprintf(file, "DEBUG STACK FOR THREAD %x:\n",
104                         (unsigned int)threadid);
105
106         for(int i=0; i<stack_max_i; i++)
107         {
108                 if(i == stack_i && everything == false)
109                         continue;
110
111                 if(i < stack_i)
112                         fprintf(file, "#%d  %s\n", i, stack[i]);
113                 else
114                         fprintf(file, "(Leftover data: #%d  %s)\n", i, stack[i]);
115         }
116
117         if(stack_i == DEBUG_STACK_SIZE)
118                 fprintf(file, "Probably overflown.\n");
119 }
120
121
122 core::map<threadid_t, DebugStack*> g_debug_stacks;
123 JMutex g_debug_stacks_mutex;
124
125 void debug_stacks_init()
126 {
127         g_debug_stacks_mutex.Init();
128 }
129
130 void debug_stacks_print()
131 {
132         JMutexAutoLock lock(g_debug_stacks_mutex);
133
134         DEBUGPRINT("Debug stacks:\n");
135
136         for(core::map<threadid_t, DebugStack*>::Iterator
137                         i = g_debug_stacks.getIterator();
138                         i.atEnd() == false; i++)
139         {
140                 DebugStack *stack = i.getNode()->getValue();
141
142                 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
143                 {
144                         if(g_debugstreams[i] != NULL)
145                                 stack->print(g_debugstreams[i], true);
146                 }
147         }
148 }
149
150 DebugStacker::DebugStacker(const char *text)
151 {
152         threadid_t threadid = get_current_thread_id();
153
154         JMutexAutoLock lock(g_debug_stacks_mutex);
155
156         core::map<threadid_t, DebugStack*>::Node *n;
157         n = g_debug_stacks.find(threadid);
158         if(n != NULL)
159         {
160                 m_stack = n->getValue();
161         }
162         else
163         {
164                 /*DEBUGPRINT("Creating new debug stack for thread %x\n",
165                                 (unsigned int)threadid);*/
166                 m_stack = new DebugStack(threadid);
167                 g_debug_stacks.insert(threadid, m_stack);
168         }
169
170         if(m_stack->stack_i >= DEBUG_STACK_SIZE)
171         {
172                 m_overflowed = true;
173         }
174         else
175         {
176                 m_overflowed = false;
177
178                 snprintf(m_stack->stack[m_stack->stack_i],
179                                 DEBUG_STACK_TEXT_SIZE, "%s", text);
180                 m_stack->stack_i++;
181                 if(m_stack->stack_i > m_stack->stack_max_i)
182                         m_stack->stack_max_i = m_stack->stack_i;
183         }
184 }
185
186 DebugStacker::~DebugStacker()
187 {
188         JMutexAutoLock lock(g_debug_stacks_mutex);
189         
190         if(m_overflowed == true)
191                 return;
192         
193         m_stack->stack_i--;
194
195         if(m_stack->stack_i == 0)
196         {
197                 threadid_t threadid = m_stack->threadid;
198                 /*DEBUGPRINT("Deleting debug stack for thread %x\n",
199                                 (unsigned int)threadid);*/
200                 delete m_stack;
201                 g_debug_stacks.remove(threadid);
202         }
203 }
204