blob: 6579e9f48350e9090d2b498f8fef0d4e44fb451c [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program Helper Library
* -------------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Debug output utilities.
*//*--------------------------------------------------------------------*/
#include "qpDebugOut.h"
#include "qpCrashHandler.h" /*!< for QP_USE_SIGNAL_HANDLER */
#include <stdio.h>
#include <stdlib.h>
typedef enum MessageType_e
{
MESSAGETYPE_INFO = 0,
MESSAGETYPE_ERROR,
MESSAGETYPE_NONFATAL_ERROR,
MESSAGETYPE_LAST
} MessageType;
static writePtr writeRedirect = 0;
static writeFtmPtr writeFtmRedirect = 0;
static void printRaw (MessageType type, const char* msg);
static void printFmt (MessageType type, const char* fmt, va_list args);
static void exitProcess (void);
void qpRedirectOut (writePtr w, writeFtmPtr wftm)
{
writeRedirect = w;
writeFtmRedirect = wftm;
}
void qpPrint (const char* message)
{
printRaw(MESSAGETYPE_INFO, message);
}
void qpPrintf (const char* format, ...)
{
va_list args;
va_start(args, format);
printFmt(MESSAGETYPE_INFO, format, args);
va_end(args);
}
void qpPrintErrorf (const char* format, ...)
{
va_list args;
va_start(args, format);
printFmt(MESSAGETYPE_NONFATAL_ERROR, format, args);
va_end(args);
}
void qpPrintv (const char* format, va_list args)
{
printFmt(MESSAGETYPE_INFO, format, args);
}
void qpPrintErrorv (const char* format, va_list args)
{
printFmt(MESSAGETYPE_NONFATAL_ERROR, format, args);
}
void qpDief (const char* format, ...)
{
va_list args;
va_start(args, format);
printFmt(MESSAGETYPE_ERROR, format, args);
va_end(args);
exitProcess();
}
void qpDiev (const char* format, va_list args)
{
printFmt(MESSAGETYPE_ERROR, format, args);
exitProcess();
}
/* print() implementation. */
#if (DE_OS == DE_OS_ANDROID)
#include <android/log.h>
static android_LogPriority getLogPriority (MessageType type)
{
switch (type)
{
case MESSAGETYPE_INFO: return ANDROID_LOG_INFO;
case MESSAGETYPE_ERROR: return ANDROID_LOG_FATAL;
default: return ANDROID_LOG_DEBUG;
}
}
void printRaw (MessageType type, const char* message)
{
if (writeRedirect && !writeRedirect(type, message))
return;
__android_log_write(getLogPriority(type), "dEQP", message);
}
void printFmt (MessageType type, const char* format, va_list args)
{
if (writeFtmRedirect && !writeFtmRedirect(type, format, args))
return;
__android_log_vprint(getLogPriority(type), "dEQP", format, args);
}
#else
static FILE* getOutFile (MessageType type)
{
if (type == MESSAGETYPE_ERROR || type == MESSAGETYPE_NONFATAL_ERROR)
return stderr;
else
return stdout;
}
void printRaw (MessageType type, const char* message)
{
if (writeRedirect && !writeRedirect(type, message))
return;
FILE* out = getOutFile(type);
if (type == MESSAGETYPE_ERROR)
fprintf(out, "FATAL ERROR: ");
fputs(message, out);
if (type == MESSAGETYPE_ERROR)
{
putc('\n', out);
fflush(out);
}
}
void printFmt (MessageType type, const char* format, va_list args)
{
if (writeFtmRedirect && !writeFtmRedirect(type, format, args))
return;
FILE* out = getOutFile(type);
if (type == MESSAGETYPE_ERROR)
fprintf(out, "FATAL ERROR: ");
vfprintf(out, format, args);
if (type == MESSAGETYPE_ERROR)
{
putc('\n', out);
fflush(out);
}
}
#endif
/* exitProcess() implementation. */
#if (DE_OS == DE_OS_WIN32)
#define NOMINMAX
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
static void exitProcess (void)
{
/* Some API implementations register atexit() functions that may hang.
By using TerminateProcess() we can avoid calling any potentially hanging exit routines. */
HANDLE curProc = GetCurrentProcess();
TerminateProcess(curProc, -1);
}
#else
#if (DE_OS == DE_OS_IOS)
# include "deThread.h" /*!< for deSleep() */
#endif
#if defined(QP_USE_SIGNAL_HANDLER)
# include <signal.h>
#endif
static void exitProcess (void)
{
#if (DE_OS == DE_OS_IOS)
/* Since tests are in the same process as execserver, we want to give it
a chance to stream complete log data before terminating. */
deSleep(5000);
#endif
#if defined(QP_USE_SIGNAL_HANDLER)
/* QP_USE_SIGNAL_HANDLER defined, this means this function could have
been called from a signal handler. Calling exit() inside a signal
handler is not safe. */
/* Flush all open FILES */
fflush(DE_NULL);
/* Kill without calling any _at_exit handlers as those might hang */
raise(SIGKILL);
#else
exit(-1);
#endif
}
#endif