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