+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
#include "stdafx.h"
#include "except.h"
-#include <boost/thread.hpp>
-
-#include "os/windows/windows.h"
+#include <boost/thread/tss.hpp>
+#include <boost/algorithm/string/join.hpp>
-namespace caspar { namespace detail {
+namespace {
-typedef struct tagTHREADNAME_INFO
+boost::thread_specific_ptr<std::list<std::string>>& context_stacks_per_thread()
{
- DWORD dwType; // must be 0x1000
- LPCSTR szName; // pointer to name (in user addr space)
- DWORD dwThreadID; // thread ID (-1=caller thread)
- DWORD dwFlags; // reserved for future use, must be zero
-} THREADNAME_INFO;
+ static boost::thread_specific_ptr<std::list<std::string>> instances;
-inline void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName)
-{
- THREADNAME_INFO info;
- {
- info.dwType = 0x1000;
- info.szName = szThreadName;
- info.dwThreadID = dwThreadID;
- info.dwFlags = 0;
- }
- __try
- {
- RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
- }
- __except (EXCEPTION_CONTINUE_EXECUTION){}
+ return instances;
}
-} // namespace detail
+}
+
+namespace caspar {
-bool& installed_for_thread()
+std::list<std::string>& context_stack_for_thread()
{
- static boost::thread_specific_ptr<bool> installed;
+ auto local = context_stacks_per_thread().get();
- auto for_thread = installed.get();
-
- if (!for_thread)
+ if (!local)
{
- for_thread = new bool(false);
- installed.reset(for_thread);
+ local = new std::list<std::string>();
+ context_stacks_per_thread().reset(local);
}
- return *for_thread;
+ return *local;
}
-void win32_exception::install_handler()
+std::string get_context()
{
-//#ifndef _DEBUG
- _set_se_translator(win32_exception::Handler);
- installed_for_thread() = true;
-//#endif
+ return boost::join(context_stack_for_thread(), "");
}
-void win32_exception::ensure_handler_installed_for_thread(
- const char* thread_description)
+scoped_context::scoped_context()
+ : scoped_context::scoped_context("")
{
- if (!installed_for_thread())
- {
- install_handler();
+}
- if (thread_description)
- detail::SetThreadName(GetCurrentThreadId(), thread_description);
- }
+scoped_context::scoped_context(std::string msg)
+ : for_thread_(context_stack_for_thread())
+{
+ for_thread_.push_back(std::move(msg));
+ msg_ = &for_thread_.back();
}
-void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo) {
- switch(errorCode)
- {
- case EXCEPTION_ACCESS_VIOLATION:
- throw win32_access_violation(*(pInfo->ExceptionRecord));
- break;
+void scoped_context::replace_msg(std::string msg)
+{
+ if (&for_thread_ != &context_stack_for_thread())
+ CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Called from wrong thread"));
- default:
- throw win32_exception(*(pInfo->ExceptionRecord));
- }
+ *msg_ = std::move(msg);
}
-win32_exception::win32_exception(const EXCEPTION_RECORD& info) : message_("Win32 exception"), location_(info.ExceptionAddress), errorCode_(info.ExceptionCode)
+void scoped_context::clear_msg()
{
- switch(info.ExceptionCode)
- {
- case EXCEPTION_ACCESS_VIOLATION:
- message_ = "Access violation";
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- message_ = "Divide by zero";
- break;
- }
+ replace_msg("");
}
-win32_access_violation::win32_access_violation(const EXCEPTION_RECORD& info) : win32_exception(info), isWrite_(false), badAddress_(0)
+scoped_context::~scoped_context()
{
- isWrite_ = info.ExceptionInformation[0] == 1;
- badAddress_ = reinterpret_cast<win32_exception::address>(info.ExceptionInformation[1]);
+ for_thread_.pop_back();
}
-const char* win32_access_violation::what() const
+
+
+std::string get_message_and_context(const caspar_exception& e)
{
- sprintf_s<>(messageBuffer_, "Access violation at %p, trying to %s %p", location(), isWrite_?"write":"read", badAddress_);
+ std::string result;
+
+ auto msg = boost::get_error_info<msg_info_t>(e);
+ auto ctx = boost::get_error_info<context_info_t>(e);
- return messageBuffer_;
+ if (msg)
+ result += *msg;
+
+ if (ctx && !ctx->empty())
+ {
+ result += " (";
+ result += *ctx;
+ result += ")";
+ }
+
+ if (!result.empty() && result.back() != '.')
+ result += ".";
+
+ return result;
}
-}
\ No newline at end of file
+}