alsk/lib/celero/Exceptions.cpp

252 lines
7.2 KiB
C++

///
/// \author Peter Azmanov
///
/// \copyright Copyright 2016, 2017, 2018 John Farrier
///
/// 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.
///
#include <celero/Exceptions.h>
#include <celero/Console.h>
#include <celero/TestFixture.h>
#ifdef WIN32
#include <Windows.h>
#endif // WIN32
#include <iomanip>
#include <iostream>
//
// Macros and general logics below taken from Google Test code,
// see gtest/internal/gtest-port.h
// gtest/src/gtest.cc
//
#ifndef CELERO_HAS_EXCEPTIONS
// The user didn't tell us whether exceptions are enabled, so we need
// to figure it out.
#if defined(_MSC_VER) || defined(__BORLANDC__)
// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
// macro to enable exceptions, so we'll do the same.
// Assumes that exceptions are enabled by default.
#ifndef _HAS_EXCEPTIONS
#define _HAS_EXCEPTIONS 1
#endif // _HAS_EXCEPTIONS
#define CELERO_HAS_EXCEPTIONS _HAS_EXCEPTIONS
#elif defined(__GNUC__) && __EXCEPTIONS
// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
#define CELERO_HAS_EXCEPTIONS 1
#elif defined(__SUNPRO_CC)
// Sun Pro CC supports exceptions. However, there is no compile-time way of
// detecting whether they are enabled or not. Therefore, we assume that
// they are enabled unless the user tells us otherwise.
#define CELERO_HAS_EXCEPTIONS 1
#elif defined(__IBMCPP__) && __EXCEPTIONS
// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
#define CELERO_HAS_EXCEPTIONS 1
#elif defined(__HP_aCC)
// Exception handling is in effect by default in HP aCC compiler. It has to
// be turned of by +noeh compiler option if desired.
#define CELERO_HAS_EXCEPTIONS 1
#else
// For other compilers, we assume exceptions are disabled to be
// conservative.
#define CELERO_HAS_EXCEPTIONS 0
#endif // defined(_MSC_VER) || defined(__BORLANDC__)
#endif // CELERO_HAS_EXCEPTIONS
// Determine whether the compiler supports Microsoft's Structured Exception
// Handling. This is supported by several Windows compilers but generally
// does not exist on any other system.
#ifndef CELERO_HAS_SEH
// The user didn't tell us, so we need to figure it out.
#if defined(_MSC_VER) || defined(__BORLANDC__)
// These two compilers are known to support SEH.
#define CELERO_HAS_SEH 1
#else
// Assume no SEH.
#define CELERO_HAS_SEH 0
#endif
#endif // CELERO_HAS_SEH
namespace celero
{
bool ExceptionSettings::GetCatchExceptions()
{
return ExceptionSettings::instance().catchExceptions;
}
void ExceptionSettings::SetCatchExceptions(bool x)
{
ExceptionSettings::instance().catchExceptions = x;
}
ExceptionSettings& ExceptionSettings::instance()
{
static ExceptionSettings settings;
return settings;
}
#if CELERO_HAS_SEH
int HandleSEH(DWORD exceptionCode)
{
// see https://support.microsoft.com/en-us/kb/185294
const DWORD cppExceptionCode = 0xe06d7363;
if((exceptionCode == EXCEPTION_BREAKPOINT) || (exceptionCode == cppExceptionCode))
{
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
const char* ExceptionCodeToStr(DWORD exceptionCode)
{
switch(exceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
return "EXCEPTION_ACCESS_VIOLATION";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
case EXCEPTION_BREAKPOINT:
return "EXCEPTION_BREAKPOINT";
case EXCEPTION_DATATYPE_MISALIGNMENT:
return "EXCEPTION_DATATYPE_MISALIGNMENT";
case EXCEPTION_FLT_DENORMAL_OPERAND:
return "EXCEPTION_FLT_DENORMAL_OPERAND";
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
case EXCEPTION_FLT_INEXACT_RESULT:
return "EXCEPTION_FLT_INEXACT_RESULT";
case EXCEPTION_FLT_INVALID_OPERATION:
return "EXCEPTION_FLT_INVALID_OPERATION";
case EXCEPTION_FLT_OVERFLOW:
return "EXCEPTION_FLT_OVERFLOW";
case EXCEPTION_FLT_STACK_CHECK:
return "EXCEPTION_FLT_STACK_CHECK";
case EXCEPTION_FLT_UNDERFLOW:
return "EXCEPTION_FLT_UNDERFLOW";
case EXCEPTION_GUARD_PAGE:
return "EXCEPTION_GUARD_PAGE";
case EXCEPTION_ILLEGAL_INSTRUCTION:
return "EXCEPTION_ILLEGAL_INSTRUCTION";
case EXCEPTION_IN_PAGE_ERROR:
return "EXCEPTION_IN_PAGE_ERROR";
case EXCEPTION_INT_DIVIDE_BY_ZERO:
return "EXCEPTION_INT_DIVIDE_BY_ZERO";
case EXCEPTION_INT_OVERFLOW:
return "EXCEPTION_INT_OVERFLOW";
case EXCEPTION_INVALID_DISPOSITION:
return "EXCEPTION_INVALID_DISPOSITION";
case EXCEPTION_INVALID_HANDLE:
return "EXCEPTION_INVALID_HANDLE";
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
case EXCEPTION_PRIV_INSTRUCTION:
return "EXCEPTION_PRIV_INSTRUCTION";
case EXCEPTION_SINGLE_STEP:
return "EXCEPTION_SINGLE_STEP";
case EXCEPTION_STACK_OVERFLOW:
return "EXCEPTION_STACK_OVERFLOW";
case STATUS_UNWIND_CONSOLIDATE:
return "STATUS_UNWIND_CONSOLIDATE";
default:
return "Unknown exception code.";
}
}
#endif // CELERO_HAS_SEH
std::pair<bool, uint64_t> RunAndCatchSEHExc(TestFixture& test, uint64_t threads, uint64_t calls,
const celero::TestFixture::ExperimentValue& experimentValue)
{
#if CELERO_HAS_SEH
__try
{
return std::make_pair(true, test.run(threads, calls, experimentValue));
}
__except(HandleSEH(GetExceptionCode()))
{
const auto exceptionCode = GetExceptionCode();
celero::console::SetConsoleColor(celero::console::ConsoleColor::Red);
std::cout << "SEH exception " << ExceptionCodeToStr(exceptionCode) << std::endl;
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
return std::make_pair(false, 0);
}
#else // CELERO_HAS_SEH
return std::make_pair(true, test.run(threads, calls, experimentValue));
#endif // CELERO_HAS_SEH
}
std::pair<bool, uint64_t> RunAndCatchExc(TestFixture& test, uint64_t threads, uint64_t calls,
const celero::TestFixture::ExperimentValue& experimentValue)
{
if(ExceptionSettings::GetCatchExceptions() == true)
{
#if CELERO_HAS_EXCEPTIONS
try
{
return RunAndCatchSEHExc(test, threads, calls, experimentValue);
}
catch(const std::exception& e)
{
celero::console::SetConsoleColor(celero::console::ConsoleColor::Red);
std::cout << "C++ exception \"" << e.what() << "\"" << std::endl;
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
}
catch(...)
{
celero::console::SetConsoleColor(celero::console::ConsoleColor::Red);
std::cout << "Unknown C++ exception" << std::endl;
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
}
return std::make_pair(false, 0);
#else // CELERO_HAS_EXCEPTIONS
return RunAndCatchSEHExc(test, threads, calls, experimentValue);
#endif // CELERO_HAS_EXCEPTIONS
}
else
{
return std::make_pair(true, test.run(threads, calls, experimentValue));
}
}
} // namespace celero