diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c3cf2073..ab7154f83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,6 +418,7 @@ set(libdevilutionx_SRCS Source/utils/language.cpp Source/utils/paths.cpp Source/utils/thread.cpp + Source/utils/sdl_thread.cpp Source/DiabloUI/art.cpp Source/DiabloUI/art_draw.cpp Source/DiabloUI/button.cpp diff --git a/Source/utils/sdl_thread.cpp b/Source/utils/sdl_thread.cpp new file mode 100644 index 000000000..168dd25f3 --- /dev/null +++ b/Source/utils/sdl_thread.cpp @@ -0,0 +1,20 @@ +#include "utils/sdl_thread.h" + +namespace devilution { + +int SDLCALL SdlThread::ThreadTranslate(void *ptr) +{ + auto handler = (void (*)())ptr; + + handler(); + + return 0; +} + +void SdlThread::ThreadDeleter(SDL_Thread *thread) +{ + if (thread != nullptr) + app_fatal("Joinable thread destroyed"); +} + +} //namespace devilution diff --git a/Source/utils/sdl_thread.h b/Source/utils/sdl_thread.h new file mode 100644 index 000000000..18a0250ca --- /dev/null +++ b/Source/utils/sdl_thread.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#ifdef USE_SDL1 +#include "utils/sdl2_to_1_2_backports.h" +#endif +#include "appfat.h" + +namespace devilution { + +namespace this_sdl_thread { + inline SDL_threadID get_id() + { + return SDL_GetThreadID(nullptr); + } +} //namespace this_sdl_thread + +class SdlThread final { + static int SDLCALL ThreadTranslate(void *ptr); + static void ThreadDeleter(SDL_Thread *thread); + + std::unique_ptr thread { nullptr, ThreadDeleter }; + +public: + SdlThread(int (SDLCALL *handler)(void *), void *data) +#ifdef USE_SDL1 + : thread(SDL_CreateThread(handler, data), ThreadDeleter) +#else + : thread(SDL_CreateThread(handler, nullptr, data), ThreadDeleter) +#endif + { + if (thread == nullptr) + ErrSdl(); + } + + SdlThread(void (*handler)(void)) + : SdlThread(ThreadTranslate, (void *)handler) + { + } + + SdlThread() = default; + + bool joinable() const + { + return thread != nullptr; + } + + SDL_threadID get_id() const + { + return SDL_GetThreadID(thread.get()); + } + + void join() + { + if (!joinable()) + return; + if (get_id() == this_sdl_thread::get_id()) + app_fatal("Thread joined from within itself"); + + SDL_WaitThread(thread.get(), nullptr); + thread.release(); + } +}; + +} // namespace devilution +