rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : OVR_Log.cpp
|
nuclear@0
|
4 Content : Logging support
|
nuclear@0
|
5 Created : September 19, 2012
|
nuclear@0
|
6 Notes :
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 ************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "OVR_Log.h"
|
nuclear@0
|
28 #include "OVR_Std.h"
|
nuclear@0
|
29 #include <stdarg.h>
|
nuclear@0
|
30 #include <stdio.h>
|
nuclear@0
|
31 #include <time.h>
|
nuclear@0
|
32 #include "../Kernel/OVR_System.h"
|
nuclear@0
|
33 #include "../Kernel/OVR_DebugHelp.h"
|
nuclear@0
|
34 #include "../Util/Util_SystemGUI.h"
|
nuclear@0
|
35
|
nuclear@0
|
36 #if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE)
|
nuclear@0
|
37 #define WIN32_LEAN_AND_MEAN
|
nuclear@0
|
38 #include <windows.h>
|
nuclear@0
|
39 #elif defined(OVR_OS_ANDROID)
|
nuclear@0
|
40 #include <android/log.h>
|
nuclear@0
|
41 #elif defined(OVR_OS_LINUX) || defined(OVR_OS_MAC) || defined(OVR_OS_UNIX)
|
nuclear@0
|
42 #include <syslog.h>
|
nuclear@0
|
43 #endif
|
nuclear@0
|
44
|
nuclear@0
|
45
|
nuclear@0
|
46 class LogSubject : public OVR::SystemSingletonBase<LogSubject>
|
nuclear@0
|
47 {
|
nuclear@0
|
48 static bool isShuttingDown;
|
nuclear@0
|
49
|
nuclear@0
|
50 public:
|
nuclear@0
|
51
|
nuclear@0
|
52 LogSubject(){
|
nuclear@0
|
53 isShuttingDown = false;
|
nuclear@0
|
54 // Must be at end of function
|
nuclear@0
|
55 PushDestroyCallbacks();
|
nuclear@0
|
56 }
|
nuclear@0
|
57
|
nuclear@0
|
58 virtual ~LogSubject(){} // Required because we use delete this below.
|
nuclear@0
|
59
|
nuclear@0
|
60 virtual void OnThreadDestroy()
|
nuclear@0
|
61 {
|
nuclear@0
|
62 isShuttingDown = true;
|
nuclear@0
|
63 }
|
nuclear@0
|
64
|
nuclear@0
|
65 virtual void OnSystemDestroy()
|
nuclear@0
|
66 {
|
nuclear@0
|
67 delete this;
|
nuclear@0
|
68 }
|
nuclear@0
|
69
|
nuclear@0
|
70 static bool IsValid() {
|
nuclear@0
|
71 return isShuttingDown == false;
|
nuclear@0
|
72 }
|
nuclear@0
|
73
|
nuclear@0
|
74 OVR::Lock logSubjectLock;
|
nuclear@0
|
75 OVR::ObserverScope<OVR::Log::LogHandler> logSubject;
|
nuclear@0
|
76 };
|
nuclear@0
|
77
|
nuclear@0
|
78 bool LogSubject::isShuttingDown;
|
nuclear@0
|
79
|
nuclear@0
|
80 OVR_DEFINE_SINGLETON(LogSubject);
|
nuclear@0
|
81
|
nuclear@0
|
82 namespace OVR {
|
nuclear@0
|
83
|
nuclear@0
|
84 // Global Log pointer.
|
nuclear@0
|
85 Log* volatile OVR_GlobalLog = 0;
|
nuclear@0
|
86
|
nuclear@0
|
87 //-----------------------------------------------------------------------------------
|
nuclear@0
|
88 // ***** Log Implementation
|
nuclear@0
|
89
|
nuclear@0
|
90 Log::Log(unsigned logMask) :
|
nuclear@0
|
91 LoggingMask(logMask)
|
nuclear@0
|
92 {
|
nuclear@0
|
93 #ifdef OVR_OS_WIN32
|
nuclear@0
|
94 hEventSource = RegisterEventSourceA(NULL, "OculusVR");
|
nuclear@0
|
95 OVR_ASSERT(hEventSource != NULL);
|
nuclear@0
|
96 #endif
|
nuclear@0
|
97 }
|
nuclear@0
|
98
|
nuclear@0
|
99 Log::~Log()
|
nuclear@0
|
100 {
|
nuclear@0
|
101 #ifdef OVR_OS_WIN32
|
nuclear@0
|
102 if (hEventSource)
|
nuclear@0
|
103 {
|
nuclear@0
|
104 DeregisterEventSource(hEventSource);
|
nuclear@0
|
105 }
|
nuclear@0
|
106 #endif
|
nuclear@0
|
107
|
nuclear@0
|
108 // Clear out global log
|
nuclear@0
|
109 if (this == OVR_GlobalLog)
|
nuclear@0
|
110 {
|
nuclear@0
|
111 // TBD: perhaps we should ASSERT if this happens before system shutdown?
|
nuclear@0
|
112 OVR_GlobalLog = 0;
|
nuclear@0
|
113 }
|
nuclear@0
|
114 }
|
nuclear@0
|
115 void Log::AddLogObserver(ObserverScope<LogHandler> *logObserver)
|
nuclear@0
|
116 {
|
nuclear@0
|
117 if (OVR::System::IsInitialized() && LogSubject::GetInstance()->IsValid())
|
nuclear@0
|
118 {
|
nuclear@0
|
119 Lock::Locker locker(&LogSubject::GetInstance()->logSubjectLock);
|
nuclear@0
|
120 logObserver->GetPtr()->Observe(LogSubject::GetInstance()->logSubject);
|
nuclear@0
|
121 }
|
nuclear@0
|
122 }
|
nuclear@0
|
123 void Log::LogMessageVargInt(LogMessageType messageType, const char* fmt, va_list argList)
|
nuclear@0
|
124 {
|
nuclear@0
|
125 if (OVR::System::IsInitialized() && LogSubject::GetInstance()->IsValid())
|
nuclear@0
|
126 {
|
nuclear@0
|
127 // Invoke subject
|
nuclear@0
|
128 char buffer[MaxLogBufferMessageSize];
|
nuclear@0
|
129 char* pBuffer = buffer;
|
nuclear@0
|
130 char* pAllocated = NULL;
|
nuclear@0
|
131
|
nuclear@0
|
132 #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list.
|
nuclear@0
|
133 va_list argListSaved;
|
nuclear@0
|
134 va_copy(argListSaved, argList);
|
nuclear@0
|
135 #endif
|
nuclear@0
|
136
|
nuclear@0
|
137 int result = FormatLog(pBuffer, MaxLogBufferMessageSize, Log_Text, fmt, argList);
|
nuclear@0
|
138
|
nuclear@0
|
139 if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity...
|
nuclear@0
|
140 {
|
nuclear@0
|
141 pAllocated = (char*)OVR_ALLOC(result + 1); // We assume C++ exceptions are disabled. FormatLog will handle the case that pAllocated is NULL.
|
nuclear@0
|
142 pBuffer = pAllocated;
|
nuclear@0
|
143
|
nuclear@0
|
144 #if !defined(OVR_CC_MSVC)
|
nuclear@0
|
145 va_end(argList); // The caller owns argList and will call va_end on it.
|
nuclear@0
|
146 va_copy(argList, argListSaved);
|
nuclear@0
|
147 #endif
|
nuclear@0
|
148
|
nuclear@0
|
149 FormatLog(pBuffer, (size_t)result + 1, Log_Text, fmt, argList);
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 Lock::Locker locker(&LogSubject::GetInstance()->logSubjectLock);
|
nuclear@0
|
153 LogSubject::GetInstance()->logSubject.GetPtr()->Call(pBuffer, messageType);
|
nuclear@0
|
154
|
nuclear@0
|
155 delete[] pAllocated;
|
nuclear@0
|
156 }
|
nuclear@0
|
157 }
|
nuclear@0
|
158
|
nuclear@0
|
159 void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList)
|
nuclear@0
|
160 {
|
nuclear@0
|
161 if ((messageType & LoggingMask) == 0)
|
nuclear@0
|
162 return;
|
nuclear@0
|
163 #ifndef OVR_BUILD_DEBUG
|
nuclear@0
|
164 if (IsDebugMessage(messageType))
|
nuclear@0
|
165 return;
|
nuclear@0
|
166 #endif
|
nuclear@0
|
167
|
nuclear@0
|
168 char buffer[MaxLogBufferMessageSize];
|
nuclear@0
|
169 char* pBuffer = buffer;
|
nuclear@0
|
170 char* pAllocated = NULL;
|
nuclear@0
|
171
|
nuclear@0
|
172 #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list.
|
nuclear@0
|
173 va_list argListSaved;
|
nuclear@0
|
174 va_copy(argListSaved, argList);
|
nuclear@0
|
175 #endif
|
nuclear@0
|
176
|
nuclear@0
|
177 int result = FormatLog(pBuffer, MaxLogBufferMessageSize, messageType, fmt, argList);
|
nuclear@0
|
178
|
nuclear@0
|
179 if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity...
|
nuclear@0
|
180 {
|
nuclear@0
|
181 pAllocated = (char*)OVR_ALLOC(result + 1); // We assume C++ exceptions are disabled. FormatLog will handle the case that pAllocated is NULL.
|
nuclear@0
|
182 pBuffer = pAllocated;
|
nuclear@0
|
183
|
nuclear@0
|
184 #if !defined(OVR_CC_MSVC)
|
nuclear@0
|
185 va_end(argList); // The caller owns argList and will call va_end on it.
|
nuclear@0
|
186 va_copy(argList, argListSaved);
|
nuclear@0
|
187 #endif
|
nuclear@0
|
188
|
nuclear@0
|
189 FormatLog(pBuffer, (size_t)result + 1, messageType, fmt, argList);
|
nuclear@0
|
190 }
|
nuclear@0
|
191
|
nuclear@0
|
192 DefaultLogOutput(pBuffer, messageType, result);
|
nuclear@0
|
193 delete[] pAllocated;
|
nuclear@0
|
194 }
|
nuclear@0
|
195
|
nuclear@0
|
196 void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...)
|
nuclear@0
|
197 {
|
nuclear@0
|
198 va_list argList;
|
nuclear@0
|
199 va_start(argList, pfmt);
|
nuclear@0
|
200 LogMessageVarg(messageType, pfmt, argList);
|
nuclear@0
|
201 va_end(argList);
|
nuclear@0
|
202 }
|
nuclear@0
|
203
|
nuclear@0
|
204
|
nuclear@0
|
205 // Return behavior is the same as ISO C vsnprintf: returns the required strlen of buffer (which will
|
nuclear@0
|
206 // be >= bufferSize if bufferSize is insufficient) or returns a negative value because the input was bad.
|
nuclear@0
|
207 int Log::FormatLog(char* buffer, size_t bufferSize, LogMessageType messageType,
|
nuclear@0
|
208 const char* fmt, va_list argList)
|
nuclear@0
|
209 {
|
nuclear@0
|
210 OVR_ASSERT(buffer && (bufferSize >= 10)); // Need to be able to at least print "Assert: \n" to it.
|
nuclear@0
|
211 if(!buffer || (bufferSize < 10))
|
nuclear@0
|
212 return -1;
|
nuclear@0
|
213
|
nuclear@0
|
214 int addNewline = 1;
|
nuclear@0
|
215 int prefixLength = 0;
|
nuclear@0
|
216
|
nuclear@0
|
217 switch(messageType)
|
nuclear@0
|
218 {
|
nuclear@0
|
219 case Log_Error: OVR_strcpy(buffer, bufferSize, "Error: "); prefixLength = 7; break;
|
nuclear@0
|
220 case Log_Debug: OVR_strcpy(buffer, bufferSize, "Debug: "); prefixLength = 7; break;
|
nuclear@0
|
221 case Log_Assert: OVR_strcpy(buffer, bufferSize, "Assert: "); prefixLength = 8; break;
|
nuclear@0
|
222 case Log_Text: buffer[0] = 0; addNewline = 0; break;
|
nuclear@0
|
223 case Log_DebugText: buffer[0] = 0; addNewline = 0; break;
|
nuclear@0
|
224 default: buffer[0] = 0; addNewline = 0; break;
|
nuclear@0
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 char* buffer2 = buffer + prefixLength;
|
nuclear@0
|
228 size_t size2 = bufferSize - (size_t)prefixLength;
|
nuclear@0
|
229 int messageLength = OVR_vsnprintf(buffer2, size2, fmt, argList);
|
nuclear@0
|
230
|
nuclear@0
|
231 if (addNewline)
|
nuclear@0
|
232 {
|
nuclear@0
|
233 if (messageLength < 0) // If there was a format error...
|
nuclear@0
|
234 {
|
nuclear@0
|
235 // To consider: append <format error> to the buffer here.
|
nuclear@0
|
236 buffer2[0] = '\n'; // We are guaranteed to have capacity for this.
|
nuclear@0
|
237 buffer2[1] = '\0';
|
nuclear@0
|
238 }
|
nuclear@0
|
239 else
|
nuclear@0
|
240 {
|
nuclear@0
|
241 // If the printed string used all of the capacity or required more than the capacity,
|
nuclear@0
|
242 // Chop the output by one character so we can append the \n safely.
|
nuclear@0
|
243 int messageEnd = (messageLength >= (int)(size2 - 1)) ? (int)(size2 - 2) : messageLength;
|
nuclear@0
|
244 buffer2[messageEnd + 0] = '\n';
|
nuclear@0
|
245 buffer2[messageEnd + 1] = '\0';
|
nuclear@0
|
246 }
|
nuclear@0
|
247 }
|
nuclear@0
|
248
|
nuclear@0
|
249 if (messageLength >= 0) // If the format was OK...
|
nuclear@0
|
250 return prefixLength + messageLength + addNewline; // Return the required strlen of buffer.
|
nuclear@0
|
251
|
nuclear@0
|
252 return messageLength; // Else we cannot know what the required strlen is and return the error to the caller.
|
nuclear@0
|
253 }
|
nuclear@0
|
254
|
nuclear@0
|
255 void Log::DefaultLogOutput(const char* formattedText, LogMessageType messageType, int bufferSize)
|
nuclear@0
|
256 {
|
nuclear@0
|
257 bool debug = IsDebugMessage(messageType);
|
nuclear@0
|
258 OVR_UNUSED(bufferSize);
|
nuclear@0
|
259
|
nuclear@0
|
260 #if defined(OVR_OS_WIN32)
|
nuclear@0
|
261 // Under Win32, output regular messages to console if it exists; debug window otherwise.
|
nuclear@0
|
262 static DWORD dummyMode;
|
nuclear@0
|
263 static bool hasConsole = (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) &&
|
nuclear@0
|
264 (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummyMode));
|
nuclear@0
|
265
|
nuclear@0
|
266 if (!hasConsole || debug)
|
nuclear@0
|
267 {
|
nuclear@0
|
268 ::OutputDebugStringA(formattedText);
|
nuclear@0
|
269 }
|
nuclear@0
|
270
|
nuclear@0
|
271 fputs(formattedText, stdout);
|
nuclear@0
|
272
|
nuclear@0
|
273 #elif defined(OVR_OS_MS) // Any other Microsoft OSs
|
nuclear@0
|
274
|
nuclear@0
|
275 ::OutputDebugStringA(formattedText);
|
nuclear@0
|
276
|
nuclear@0
|
277 #elif defined(OVR_OS_ANDROID)
|
nuclear@0
|
278 // To do: use bufferSize to deal with the case that Android has a limited output length.
|
nuclear@0
|
279 __android_log_write(ANDROID_LOG_INFO, "OVR", formattedText);
|
nuclear@0
|
280
|
nuclear@0
|
281 #else
|
nuclear@0
|
282 fputs(formattedText, stdout);
|
nuclear@0
|
283
|
nuclear@0
|
284 #endif
|
nuclear@0
|
285
|
nuclear@0
|
286 if (messageType == Log_Error)
|
nuclear@0
|
287 {
|
nuclear@0
|
288 #if defined(OVR_OS_WIN32)
|
nuclear@0
|
289 if (!ReportEventA(hEventSource, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 1, 0, &formattedText, NULL))
|
nuclear@0
|
290 {
|
nuclear@0
|
291 OVR_ASSERT(false);
|
nuclear@0
|
292 }
|
nuclear@0
|
293 #elif defined(OVR_OS_MS) // Any other Microsoft OSs
|
nuclear@0
|
294 // TBD
|
nuclear@0
|
295 #elif defined(OVR_OS_ANDROID)
|
nuclear@0
|
296 // TBD
|
nuclear@0
|
297 #elif defined(OVR_OS_MAC) || defined(OVR_OS_LINUX)
|
nuclear@0
|
298 syslog(LOG_ERR, "%s", formattedText);
|
nuclear@0
|
299 #else
|
nuclear@0
|
300 // TBD
|
nuclear@0
|
301 #endif
|
nuclear@0
|
302 }
|
nuclear@0
|
303
|
nuclear@0
|
304 // Just in case.
|
nuclear@0
|
305 OVR_UNUSED2(formattedText, debug);
|
nuclear@0
|
306 }
|
nuclear@0
|
307
|
nuclear@0
|
308
|
nuclear@0
|
309 //static
|
nuclear@0
|
310 void Log::SetGlobalLog(Log *log)
|
nuclear@0
|
311 {
|
nuclear@0
|
312 OVR_GlobalLog = log;
|
nuclear@0
|
313 }
|
nuclear@0
|
314 //static
|
nuclear@0
|
315 Log* Log::GetGlobalLog()
|
nuclear@0
|
316 {
|
nuclear@0
|
317 // No global log by default?
|
nuclear@0
|
318 // if (!OVR_GlobalLog)
|
nuclear@0
|
319 // OVR_GlobalLog = GetDefaultLog();
|
nuclear@0
|
320 return OVR_GlobalLog;
|
nuclear@0
|
321 }
|
nuclear@0
|
322
|
nuclear@0
|
323 //static
|
nuclear@0
|
324 Log* Log::GetDefaultLog()
|
nuclear@0
|
325 {
|
nuclear@0
|
326 // Create default log pointer statically so that it can be used
|
nuclear@0
|
327 // even during startup.
|
nuclear@0
|
328 static Log defaultLog;
|
nuclear@0
|
329 return &defaultLog;
|
nuclear@0
|
330 }
|
nuclear@0
|
331
|
nuclear@0
|
332
|
nuclear@0
|
333 //-----------------------------------------------------------------------------------
|
nuclear@0
|
334 // ***** Global Logging functions
|
nuclear@0
|
335
|
nuclear@0
|
336 #if !defined(OVR_CC_MSVC)
|
nuclear@0
|
337 // The reason for va_copy is because you can't use va_start twice on Linux
|
nuclear@0
|
338 #define OVR_LOG_FUNCTION_IMPL(Name) \
|
nuclear@0
|
339 void Log##Name(const char* fmt, ...) \
|
nuclear@0
|
340 { \
|
nuclear@0
|
341 if (OVR_GlobalLog) \
|
nuclear@0
|
342 { \
|
nuclear@0
|
343 va_list argList1; \
|
nuclear@0
|
344 va_start(argList1, fmt); \
|
nuclear@0
|
345 va_list argList2; \
|
nuclear@0
|
346 va_copy(argList2, argList1); \
|
nuclear@0
|
347 OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList2); \
|
nuclear@0
|
348 va_end(argList2); \
|
nuclear@0
|
349 OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1); \
|
nuclear@0
|
350 va_end(argList1); \
|
nuclear@0
|
351 } \
|
nuclear@0
|
352 }
|
nuclear@0
|
353 #else
|
nuclear@0
|
354 #define OVR_LOG_FUNCTION_IMPL(Name) \
|
nuclear@0
|
355 void Log##Name(const char* fmt, ...) \
|
nuclear@0
|
356 { \
|
nuclear@0
|
357 if (OVR_GlobalLog) \
|
nuclear@0
|
358 { \
|
nuclear@0
|
359 va_list argList1; \
|
nuclear@0
|
360 va_start(argList1, fmt); \
|
nuclear@0
|
361 OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList1); \
|
nuclear@0
|
362 OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1); \
|
nuclear@0
|
363 va_end(argList1); \
|
nuclear@0
|
364 } \
|
nuclear@0
|
365 }
|
nuclear@0
|
366 #endif // #if !defined(OVR_OS_WIN32)
|
nuclear@0
|
367
|
nuclear@0
|
368 OVR_LOG_FUNCTION_IMPL(Text)
|
nuclear@0
|
369 OVR_LOG_FUNCTION_IMPL(Error)
|
nuclear@0
|
370
|
nuclear@0
|
371 #ifdef OVR_BUILD_DEBUG
|
nuclear@0
|
372 OVR_LOG_FUNCTION_IMPL(DebugText)
|
nuclear@0
|
373 OVR_LOG_FUNCTION_IMPL(Debug)
|
nuclear@0
|
374 OVR_LOG_FUNCTION_IMPL(Assert)
|
nuclear@0
|
375 #endif
|
nuclear@0
|
376
|
nuclear@0
|
377
|
nuclear@0
|
378
|
nuclear@0
|
379 // Assertion handler support
|
nuclear@0
|
380 // To consider: Move this to an OVR_Types.cpp or OVR_Assert.cpp source file.
|
nuclear@0
|
381
|
nuclear@0
|
382 static OVRAssertionHandler sOVRAssertionHandler = OVR::DefaultAssertionHandler;
|
nuclear@0
|
383 static intptr_t sOVRAssertionHandlerUserParameter = 0;
|
nuclear@0
|
384
|
nuclear@0
|
385 OVRAssertionHandler GetAssertionHandler(intptr_t* userParameter)
|
nuclear@0
|
386 {
|
nuclear@0
|
387 if(userParameter)
|
nuclear@0
|
388 *userParameter = sOVRAssertionHandlerUserParameter;
|
nuclear@0
|
389 return sOVRAssertionHandler;
|
nuclear@0
|
390 }
|
nuclear@0
|
391
|
nuclear@0
|
392 void SetAssertionHandler(OVRAssertionHandler assertionHandler, intptr_t userParameter)
|
nuclear@0
|
393 {
|
nuclear@0
|
394 sOVRAssertionHandler = assertionHandler;
|
nuclear@0
|
395 sOVRAssertionHandlerUserParameter = userParameter;
|
nuclear@0
|
396 }
|
nuclear@0
|
397
|
nuclear@0
|
398 intptr_t DefaultAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message)
|
nuclear@0
|
399 {
|
nuclear@0
|
400 if(OVRIsDebuggerPresent())
|
nuclear@0
|
401 {
|
nuclear@0
|
402 OVR_DEBUG_BREAK;
|
nuclear@0
|
403 }
|
nuclear@0
|
404 else
|
nuclear@0
|
405 {
|
nuclear@0
|
406 #if defined(OVR_BUILD_DEBUG)
|
nuclear@0
|
407 // Print a stack trace of all threads.
|
nuclear@0
|
408 OVR::String s;
|
nuclear@0
|
409 OVR::String threadListOutput;
|
nuclear@0
|
410 static OVR::SymbolLookup symbolLookup;
|
nuclear@0
|
411
|
nuclear@0
|
412 s = "Failure: ";
|
nuclear@0
|
413 s += message;
|
nuclear@0
|
414
|
nuclear@0
|
415 if(symbolLookup.Initialize() && symbolLookup.ReportThreadCallstack(threadListOutput, 4)) // This '4' is there to skip our internal handling and retrieve starting at the assertion location (our caller) only.
|
nuclear@0
|
416 {
|
nuclear@0
|
417 s += "\r\n\r\n";
|
nuclear@0
|
418 s += threadListOutput;
|
nuclear@0
|
419 }
|
nuclear@0
|
420
|
nuclear@0
|
421 OVR::Util::DisplayMessageBox(title, s.ToCStr());
|
nuclear@0
|
422 #else
|
nuclear@0
|
423 OVR::Util::DisplayMessageBox(title, message);
|
nuclear@0
|
424 #endif
|
nuclear@0
|
425 }
|
nuclear@0
|
426
|
nuclear@0
|
427 return 0;
|
nuclear@0
|
428 }
|
nuclear@0
|
429
|
nuclear@0
|
430
|
nuclear@0
|
431
|
nuclear@0
|
432 } // OVR
|