split threading

This commit is contained in:
isanae
2020-11-09 03:28:49 -05:00
parent 946a5e9c40
commit 1bbd34285a
13 changed files with 314 additions and 275 deletions
+1
View File
@@ -5,6 +5,7 @@
#include "core/conf.h"
#include "tasks/tasks.h"
#include "tools/tools.h"
#include "utility/threading.h"
namespace mob
{
+1
View File
@@ -6,6 +6,7 @@
#include "core/op.h"
#include "tasks/tasks.h"
#include "tools/tools.h"
#include "utility/threading.h"
namespace mob
{
+1
View File
@@ -4,6 +4,7 @@
#include "core/conf.h"
#include "core/op.h"
#include "core/context.h"
#include "utility/threading.h"
namespace mob
{
+1
View File
@@ -3,6 +3,7 @@
#include "../core/conf.h"
#include "../core/op.h"
#include "../tools/tools.h"
#include "../utility/threading.h"
namespace mob
{
+1
View File
@@ -1,5 +1,6 @@
#include "pch.h"
#include "tasks.h"
#include "../utility/threading.h"
namespace mob
{
+1
View File
@@ -1,6 +1,7 @@
#include "pch.h"
#include "tools.h"
#include "../core/conf.h"
#include "../utility/threading.h"
namespace mob
{
+6 -232
View File
@@ -14,179 +14,6 @@ static std::mutex g_output_mutex;
extern u8stream u8cout(false);
extern u8stream u8cerr(true);
constexpr std::size_t max_name_length = 1000;
constexpr std::size_t max_frames = 100;
const std::size_t exception_message_length = 5000;
static void* frame_addresses[max_frames];
static wchar_t undecorated_name[max_name_length + 1] = {};
static unsigned char sym_buffer[sizeof(SYMBOL_INFOW) + max_name_length];
static SYMBOL_INFOW* sym = (SYMBOL_INFOW*)sym_buffer;
static wchar_t exception_message[exception_message_length + 1] = {};
static LPTOP_LEVEL_EXCEPTION_FILTER g_previous_handler = nullptr;
void dump_stacktrace(const wchar_t* what)
{
std::scoped_lock lock(g_output_mutex);
std::wcerr
<< "\n\nmob has crashed\n"
<< L"*****************************\n\n"
<< what << L"\n\n";
HANDLE process = INVALID_HANDLE_VALUE;
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
GetCurrentProcess(), &process, 0, false, DUPLICATE_SAME_ACCESS);
SymSetOptions(SymGetOptions() & (~SYMOPT_UNDNAME));
SymInitializeW(process, NULL, TRUE);
const std::size_t frame_count = CaptureStackBackTrace(
0, max_frames, frame_addresses, nullptr);
for (std::size_t i=0; i<frame_count; ++i)
{
DWORD disp = 0;
IMAGEHLP_LINEW64 line = {0};
line.SizeOfStruct = sizeof(line);
std::wcerr << frame_addresses[i] << L" ";
if (SymGetLineFromAddrW64(
process, reinterpret_cast<DWORD64>(frame_addresses[i]),
&disp, &line))
{
std::wcerr << line.FileName << L":" << line.LineNumber << L" ";
}
DWORD64 disp2 = 0;
sym->MaxNameLen = max_name_length;
sym->SizeOfStruct = sizeof(SYMBOL_INFOW);
if (SymFromAddrW(process, reinterpret_cast<DWORD64>(frame_addresses[i]), &disp2, sym))
{
const DWORD und_length = UnDecorateSymbolNameW(
sym->Name, undecorated_name, max_name_length, UNDNAME_COMPLETE);
std::wcerr << undecorated_name;
}
std::wcerr << L"\n";
}
if (IsDebuggerPresent())
DebugBreak();
else
TerminateProcess(GetCurrentProcess(), 0xffff);
}
void terminate_handler() noexcept
{
try
{
std::rethrow_exception(std::current_exception());
}
catch(std::exception& e)
{
auto* p = exception_message;
std::size_t remaining = exception_message_length;
const int n = _snwprintf(
p, remaining, L"%s", L"unhandled exception: ");
if (n >= 0)
{
p += n;
remaining -=n ;
}
::MultiByteToWideChar(
CP_ACP, 0, e.what(), -1, p, static_cast<int>(remaining));
}
catch(...)
{
auto* p = exception_message;
std::size_t remaining = exception_message_length;
_snwprintf(
p, remaining, L"%s", L"unhandled exception");
}
dump_stacktrace(exception_message);
}
const wchar_t* error_code_name(DWORD code)
{
switch (code)
{
case EXCEPTION_ACCESS_VIOLATION: return L"EXCEPTION_ACCESS_VIOLATION";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
case EXCEPTION_BREAKPOINT: return L"EXCEPTION_BREAKPOINT";
case EXCEPTION_DATATYPE_MISALIGNMENT: return L"EXCEPTION_DATATYPE_MISALIGNMENT";
case EXCEPTION_FLT_DENORMAL_OPERAND: return L"EXCEPTION_FLT_DENORMAL_OPERAND";
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return L"EXCEPTION_FLT_DIVIDE_BY_ZERO";
case EXCEPTION_FLT_INEXACT_RESULT: return L"EXCEPTION_FLT_INEXACT_RESULT";
case EXCEPTION_FLT_INVALID_OPERATION: return L"EXCEPTION_FLT_INVALID_OPERATION";
case EXCEPTION_FLT_OVERFLOW: return L"EXCEPTION_FLT_OVERFLOW";
case EXCEPTION_FLT_STACK_CHECK: return L"EXCEPTION_FLT_STACK_CHECK";
case EXCEPTION_FLT_UNDERFLOW: return L"EXCEPTION_FLT_UNDERFLOW";
case EXCEPTION_ILLEGAL_INSTRUCTION: return L"EXCEPTION_ILLEGAL_INSTRUCTION";
case EXCEPTION_IN_PAGE_ERROR: return L"EXCEPTION_IN_PAGE_ERROR";
case EXCEPTION_INT_DIVIDE_BY_ZERO: return L"EXCEPTION_INT_DIVIDE_BY_ZERO";
case EXCEPTION_INT_OVERFLOW: return L"EXCEPTION_INT_OVERFLOW";
case EXCEPTION_INVALID_DISPOSITION: return L"EXCEPTION_INVALID_DISPOSITION";
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return L"EXCEPTION_NONCONTINUABLE_EXCEPTION";
case EXCEPTION_PRIV_INSTRUCTION: return L"EXCEPTION_PRIV_INSTRUCTION";
case EXCEPTION_SINGLE_STEP: return L"EXCEPTION_SINGLE_STEP";
case EXCEPTION_STACK_OVERFLOW: return L"EXCEPTION_STACK_OVERFLOW";
default: return L"unknown exception" ;
}
}
LONG WINAPI unhandled_exception_handler(LPEXCEPTION_POINTERS ep) noexcept
{
if (ep->ExceptionRecord->ExceptionCode == 0xE06D7363)
{
if (g_previous_handler)
return g_previous_handler(ep);;
}
wchar_t* p = exception_message;
std::size_t remaining = exception_message_length;
const auto n = GetModuleFileNameW(
GetModuleHandleW(nullptr), exception_message,
exception_message_length);
p += n;
remaining -= n;
const auto n2 = _snwprintf(
p, remaining, L": exception thrown at 0x%p: 0x%lX %s",
ep->ExceptionRecord->ExceptionAddress,
ep->ExceptionRecord->ExceptionCode,
error_code_name(ep->ExceptionRecord->ExceptionCode));
p += n2;
remaining -= n2;
dump_stacktrace(exception_message);
return EXCEPTION_CONTINUE_SEARCH;
}
void set_thread_exception_handlers()
{
g_previous_handler = SetUnhandledExceptionFilter(
mob::unhandled_exception_handler);
std::set_terminate(mob::terminate_handler);
}
static bool stdout_console = []
{
@@ -224,6 +51,12 @@ void set_std_streams()
_setmode(_fileno(stderr), _O_U16TEXT);
}
std::mutex& global_output_mutex()
{
return g_output_mutex;
}
void u8stream::do_output(const std::string& s)
{
std::scoped_lock lock(g_output_mutex);
@@ -967,63 +800,4 @@ std::string path_to_utf8(fs::path p)
return utf16_to_utf8(p.native());
}
thread_pool::thread_pool(std::size_t count)
: count_(std::max<std::size_t>(1, count))
{
for (std::size_t i=0; i<count_; ++i)
threads_.emplace_back(std::make_unique<thread_info>());
}
thread_pool::~thread_pool()
{
join();
}
void thread_pool::join()
{
for (auto&& t : threads_)
{
if (t->thread.joinable())
t->thread.join();
}
}
void thread_pool::add(fun thread_fun)
{
for (;;)
{
if (try_add(thread_fun))
break;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
bool thread_pool::try_add(fun thread_fun)
{
for (auto& t : threads_)
{
if (!t->running)
{
if (t->thread.joinable())
t->thread.join();
t->running = true;
t->thread_fun = thread_fun;
t->thread = std::thread([&]
{
t->thread_fun();
t->running = false;
});
return true;
}
}
return false;
}
} // namespace
+1 -43
View File
@@ -51,18 +51,6 @@ inline void mob_assert(
mob_assertion_failed(nullptr, exp, file, line, func);
}
void set_thread_exception_handlers();
template <class F>
std::thread start_thread(F&& f)
{
return std::thread([f]
{
set_thread_exception_handlers();
f();
});
}
enum class encodings
{
@@ -395,6 +383,7 @@ extern u8stream u8cout;
extern u8stream u8cerr;
void set_std_streams();
std::mutex& global_output_mutex();
template <class F>
@@ -590,37 +579,6 @@ auto map(const std::vector<T>& v, F&& f)
}
class thread_pool
{
public:
typedef std::function<void ()> fun;
thread_pool(std::size_t count=std::thread::hardware_concurrency());
~thread_pool();
// non-copyable
thread_pool(const thread_pool&) = delete;
thread_pool& operator=(const thread_pool&) = delete;
void add(fun f);
void join();
private:
struct thread_info
{
std::atomic<bool> running = false;
fun thread_fun;
std::thread thread;
};
const std::size_t count_;
std::vector<std::unique_ptr<thread_info>> threads_;
bool try_add(fun thread_fun);
};
// see https://github.com/isanae/mob/issues/4
//
// this restores the original console font if it changed
+2
View File
@@ -0,0 +1,2 @@
// for intellisense
#include "../pch.h"
+239
View File
@@ -0,0 +1,239 @@
#include "pch.h"
#include "threading.h"
#include "../utility.h"
namespace mob
{
constexpr std::size_t max_name_length = 1000;
constexpr std::size_t max_frames = 100;
const std::size_t exception_message_length = 5000;
static void* frame_addresses[max_frames];
static wchar_t undecorated_name[max_name_length + 1] = {};
static unsigned char sym_buffer[sizeof(SYMBOL_INFOW) + max_name_length];
static SYMBOL_INFOW* sym = (SYMBOL_INFOW*)sym_buffer;
static wchar_t exception_message[exception_message_length + 1] = {};
static LPTOP_LEVEL_EXCEPTION_FILTER g_previous_handler = nullptr;
void dump_stacktrace(const wchar_t* what)
{
std::scoped_lock lock(global_output_mutex());
std::wcerr
<< "\n\nmob has crashed\n"
<< L"*****************************\n\n"
<< what << L"\n\n";
HANDLE process = INVALID_HANDLE_VALUE;
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
GetCurrentProcess(), &process, 0, false, DUPLICATE_SAME_ACCESS);
SymSetOptions(SymGetOptions() & (~SYMOPT_UNDNAME));
SymInitializeW(process, NULL, TRUE);
const std::size_t frame_count = CaptureStackBackTrace(
0, max_frames, frame_addresses, nullptr);
for (std::size_t i=0; i<frame_count; ++i)
{
DWORD disp = 0;
IMAGEHLP_LINEW64 line = {0};
line.SizeOfStruct = sizeof(line);
std::wcerr << frame_addresses[i] << L" ";
if (SymGetLineFromAddrW64(
process, reinterpret_cast<DWORD64>(frame_addresses[i]),
&disp, &line))
{
std::wcerr << line.FileName << L":" << line.LineNumber << L" ";
}
DWORD64 disp2 = 0;
sym->MaxNameLen = max_name_length;
sym->SizeOfStruct = sizeof(SYMBOL_INFOW);
if (SymFromAddrW(process, reinterpret_cast<DWORD64>(frame_addresses[i]), &disp2, sym))
{
const DWORD und_length = UnDecorateSymbolNameW(
sym->Name, undecorated_name, max_name_length, UNDNAME_COMPLETE);
std::wcerr << undecorated_name;
}
std::wcerr << L"\n";
}
if (IsDebuggerPresent())
DebugBreak();
else
TerminateProcess(GetCurrentProcess(), 0xffff);
}
void terminate_handler() noexcept
{
try
{
std::rethrow_exception(std::current_exception());
}
catch(std::exception& e)
{
auto* p = exception_message;
std::size_t remaining = exception_message_length;
const int n = _snwprintf(
p, remaining, L"%s", L"unhandled exception: ");
if (n >= 0)
{
p += n;
remaining -=n ;
}
::MultiByteToWideChar(
CP_ACP, 0, e.what(), -1, p, static_cast<int>(remaining));
}
catch(...)
{
auto* p = exception_message;
std::size_t remaining = exception_message_length;
_snwprintf(
p, remaining, L"%s", L"unhandled exception");
}
dump_stacktrace(exception_message);
}
const wchar_t* error_code_name(DWORD code)
{
switch (code)
{
case EXCEPTION_ACCESS_VIOLATION: return L"EXCEPTION_ACCESS_VIOLATION";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
case EXCEPTION_BREAKPOINT: return L"EXCEPTION_BREAKPOINT";
case EXCEPTION_DATATYPE_MISALIGNMENT: return L"EXCEPTION_DATATYPE_MISALIGNMENT";
case EXCEPTION_FLT_DENORMAL_OPERAND: return L"EXCEPTION_FLT_DENORMAL_OPERAND";
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return L"EXCEPTION_FLT_DIVIDE_BY_ZERO";
case EXCEPTION_FLT_INEXACT_RESULT: return L"EXCEPTION_FLT_INEXACT_RESULT";
case EXCEPTION_FLT_INVALID_OPERATION: return L"EXCEPTION_FLT_INVALID_OPERATION";
case EXCEPTION_FLT_OVERFLOW: return L"EXCEPTION_FLT_OVERFLOW";
case EXCEPTION_FLT_STACK_CHECK: return L"EXCEPTION_FLT_STACK_CHECK";
case EXCEPTION_FLT_UNDERFLOW: return L"EXCEPTION_FLT_UNDERFLOW";
case EXCEPTION_ILLEGAL_INSTRUCTION: return L"EXCEPTION_ILLEGAL_INSTRUCTION";
case EXCEPTION_IN_PAGE_ERROR: return L"EXCEPTION_IN_PAGE_ERROR";
case EXCEPTION_INT_DIVIDE_BY_ZERO: return L"EXCEPTION_INT_DIVIDE_BY_ZERO";
case EXCEPTION_INT_OVERFLOW: return L"EXCEPTION_INT_OVERFLOW";
case EXCEPTION_INVALID_DISPOSITION: return L"EXCEPTION_INVALID_DISPOSITION";
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return L"EXCEPTION_NONCONTINUABLE_EXCEPTION";
case EXCEPTION_PRIV_INSTRUCTION: return L"EXCEPTION_PRIV_INSTRUCTION";
case EXCEPTION_SINGLE_STEP: return L"EXCEPTION_SINGLE_STEP";
case EXCEPTION_STACK_OVERFLOW: return L"EXCEPTION_STACK_OVERFLOW";
default: return L"unknown exception" ;
}
}
LONG WINAPI unhandled_exception_handler(LPEXCEPTION_POINTERS ep) noexcept
{
if (ep->ExceptionRecord->ExceptionCode == 0xE06D7363)
{
if (g_previous_handler)
return g_previous_handler(ep);;
}
wchar_t* p = exception_message;
std::size_t remaining = exception_message_length;
const auto n = GetModuleFileNameW(
GetModuleHandleW(nullptr), exception_message,
exception_message_length);
p += n;
remaining -= n;
const auto n2 = _snwprintf(
p, remaining, L": exception thrown at 0x%p: 0x%lX %s",
ep->ExceptionRecord->ExceptionAddress,
ep->ExceptionRecord->ExceptionCode,
error_code_name(ep->ExceptionRecord->ExceptionCode));
p += n2;
remaining -= n2;
dump_stacktrace(exception_message);
return EXCEPTION_CONTINUE_SEARCH;
}
void set_thread_exception_handlers()
{
g_previous_handler = SetUnhandledExceptionFilter(
mob::unhandled_exception_handler);
std::set_terminate(mob::terminate_handler);
}
thread_pool::thread_pool(std::size_t count)
: count_(std::max<std::size_t>(1, count))
{
for (std::size_t i=0; i<count_; ++i)
threads_.emplace_back(std::make_unique<thread_info>());
}
thread_pool::~thread_pool()
{
join();
}
void thread_pool::join()
{
for (auto&& t : threads_)
{
if (t->thread.joinable())
t->thread.join();
}
}
void thread_pool::add(fun thread_fun)
{
for (;;)
{
if (try_add(thread_fun))
break;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
bool thread_pool::try_add(fun thread_fun)
{
for (auto& t : threads_)
{
if (!t->running)
{
if (t->thread.joinable())
t->thread.join();
t->running = true;
t->thread_fun = thread_fun;
t->thread = std::thread([&]
{
t->thread_fun();
t->running = false;
});
return true;
}
}
return false;
}
} // namespace
+49
View File
@@ -0,0 +1,49 @@
#pragma once
namespace mob
{
void set_thread_exception_handlers();
template <class F>
std::thread start_thread(F&& f)
{
return std::thread([f]
{
set_thread_exception_handlers();
f();
});
}
class thread_pool
{
public:
typedef std::function<void ()> fun;
thread_pool(std::size_t count=std::thread::hardware_concurrency());
~thread_pool();
// non-copyable
thread_pool(const thread_pool&) = delete;
thread_pool& operator=(const thread_pool&) = delete;
void add(fun f);
void join();
private:
struct thread_info
{
std::atomic<bool> running = false;
fun thread_fun;
std::thread thread;
};
const std::size_t count_;
std::vector<std::unique_ptr<thread_info>> threads_;
bool try_add(fun thread_fun);
};
} // namespace
+2
View File
@@ -106,6 +106,7 @@
<ClCompile Include="..\src\tools\process_runner.cpp" />
<ClCompile Include="..\src\tools\tools.cpp" />
<ClCompile Include="..\src\utility.cpp" />
<ClCompile Include="..\src\utility\threading.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\commands.h" />
@@ -120,6 +121,7 @@
<ClInclude Include="..\src\tasks\tasks.h" />
<ClInclude Include="..\src\tools\tools.h" />
<ClInclude Include="..\src\utility.h" />
<ClInclude Include="..\src\utility\threading.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
+9
View File
@@ -13,6 +13,9 @@
<Filter Include="src\core">
<UniqueIdentifier>{6e4d31d5-100c-4a4d-8e7d-4c48939819bd}</UniqueIdentifier>
</Filter>
<Filter Include="src\utility">
<UniqueIdentifier>{78dd6066-d407-4450-b520-649454c15ee9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\main.cpp">
@@ -150,6 +153,9 @@
<ClCompile Include="..\src\core\context.cpp">
<Filter>src\core</Filter>
</ClCompile>
<ClCompile Include="..\src\utility\threading.cpp">
<Filter>src\utility</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\pch.h">
@@ -188,5 +194,8 @@
<ClInclude Include="..\src\core\conf.h">
<Filter>src\core</Filter>
</ClInclude>
<ClInclude Include="..\src\utility\threading.h">
<Filter>src\utility</Filter>
</ClInclude>
</ItemGroup>
</Project>