From ce0fcf9cab64116476c71e2f1bd3c103714cd8fe Mon Sep 17 00:00:00 2001 From: InoriRus Date: Wed, 19 Jan 2022 17:24:34 +1000 Subject: [PATCH] fix deadlock --- source/CMakeLists.txt | 6 +- source/emulator/src/Graphics/Label.cpp | 131 +++--- source/include/Kyty/Core/Threads.h | 10 +- source/lib/Core/src/Threads.cpp | 530 ++++++++++++++++++------- 4 files changed, 470 insertions(+), 207 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 005491d..c371f87 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -79,7 +79,7 @@ if (KYTY_LINKER STREQUAL LD) set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000") endif() -project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.6) +project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.7) include(src_script.cmake) @@ -112,7 +112,7 @@ add_custom_target( KytyGitVersion list(APPEND KYTY_IWYU emulator_obj - #core_obj + core_obj #math_obj #scripts_obj #sys_obj @@ -121,7 +121,7 @@ list(APPEND KYTY_IWYU list(APPEND KYTY_CLANG_TYDY emulator_obj - #core_obj + core_obj #core #math_obj #scripts_obj diff --git a/source/emulator/src/Graphics/Label.cpp b/source/emulator/src/Graphics/Label.cpp index d012dd8..3986eac 100644 --- a/source/emulator/src/Graphics/Label.cpp +++ b/source/emulator/src/Graphics/Label.cpp @@ -22,11 +22,8 @@ enum LabelStatus NotActive, }; -struct Label +struct LabelCallbacks { - VkDevice device = nullptr; - VkEvent event = nullptr; - LabelStatus status = LabelStatus::New; uint64_t* dst_gpu_addr64 = nullptr; uint64_t value64 = 0; uint32_t* dst_gpu_addr32 = nullptr; @@ -34,7 +31,15 @@ struct Label LabelGpuObject::callback_t callback_1 = nullptr; LabelGpuObject::callback_t callback_2 = nullptr; uint64_t args[4] = {}; - CommandBuffer* buffer = nullptr; +}; + +struct Label +{ + VkDevice device = nullptr; + VkEvent event = nullptr; + LabelStatus status = LabelStatus::New; + LabelCallbacks callbacks; + CommandBuffer* buffer = nullptr; }; class LabelManager @@ -76,7 +81,8 @@ void LabelManager::ThreadRun(void* data) int active_count = 0; - Vector deleted_labels; + Vector deleted_labels; + Vector fired_labels; for (auto& label: manager->m_labels) { @@ -93,33 +99,7 @@ void LabelManager::ThreadRun(void* data) label->status = LabelStatus::NotActive; - bool write = true; - - if (label->callback_1 != nullptr) - { - write = label->callback_1(label->args); - } - - if (write && label->dst_gpu_addr64 != nullptr) - { - *label->dst_gpu_addr64 = label->value64; - - printf(FG_BRIGHT_GREEN "EndOfPipe Signal!!! [0x%016" PRIx64 "] <- 0x%016" PRIx64 "\n" FG_DEFAULT, - reinterpret_cast(label->dst_gpu_addr64), label->value64); - } - - if (write && label->dst_gpu_addr32 != nullptr) - { - *label->dst_gpu_addr32 = label->value32; - - printf(FG_BRIGHT_GREEN "EndOfPipe Signal!!! [0x%016" PRIx64 "] <- 0x%08" PRIx32 "\n" FG_DEFAULT, - reinterpret_cast(label->dst_gpu_addr32), label->value32); - } - - if (label->callback_2 != nullptr) - { - label->callback_2(label->args); - } + fired_labels.Add(label->callbacks); } } } @@ -136,6 +116,37 @@ void LabelManager::ThreadRun(void* data) manager->m_mutex.Unlock(); + for (auto& label: fired_labels) + { + bool write = true; + + if (label.callback_1 != nullptr) + { + write = label.callback_1(label.args); + } + + if (write && label.dst_gpu_addr64 != nullptr) + { + *label.dst_gpu_addr64 = label.value64; + + printf(FG_BRIGHT_GREEN "EndOfPipe Signal!!! [0x%016" PRIx64 "] <- 0x%016" PRIx64 "\n" FG_DEFAULT, + reinterpret_cast(label.dst_gpu_addr64), label.value64); + } + + if (write && label.dst_gpu_addr32 != nullptr) + { + *label.dst_gpu_addr32 = label.value32; + + printf(FG_BRIGHT_GREEN "EndOfPipe Signal!!! [0x%016" PRIx64 "] <- 0x%08" PRIx32 "\n" FG_DEFAULT, + reinterpret_cast(label.dst_gpu_addr32), label.value32); + } + + if (label.callback_2 != nullptr) + { + label.callback_2(label.args); + } + } + Core::Thread::SleepMicro(100); } } @@ -150,20 +161,20 @@ Label* LabelManager::Create(GraphicContext* ctx, uint64_t* dst_gpu_addr, uint64_ auto* label = new Label; - label->status = LabelStatus::New; - label->dst_gpu_addr64 = dst_gpu_addr; - label->value64 = value; - label->dst_gpu_addr32 = nullptr; - label->value32 = 0; - label->event = nullptr; - label->device = ctx->device; - label->callback_1 = callback_1; - label->callback_2 = callback_2; - label->args[0] = args[0]; - label->args[1] = args[1]; - label->args[2] = args[2]; - label->args[3] = args[3]; - label->buffer = nullptr; + label->status = LabelStatus::New; + label->callbacks.dst_gpu_addr64 = dst_gpu_addr; + label->callbacks.value64 = value; + label->callbacks.dst_gpu_addr32 = nullptr; + label->callbacks.value32 = 0; + label->event = nullptr; + label->device = ctx->device; + label->callbacks.callback_1 = callback_1; + label->callbacks.callback_2 = callback_2; + label->callbacks.args[0] = args[0]; + label->callbacks.args[1] = args[1]; + label->callbacks.args[2] = args[2]; + label->callbacks.args[3] = args[3]; + label->buffer = nullptr; VkEventCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; @@ -190,19 +201,19 @@ Label* LabelManager::Create(GraphicContext* ctx, uint32_t* dst_gpu_addr, uint32_ auto* label = new Label; - label->status = LabelStatus::New; - label->dst_gpu_addr32 = dst_gpu_addr; - label->value32 = value; - label->dst_gpu_addr64 = nullptr; - label->value64 = 0; - label->event = nullptr; - label->device = ctx->device; - label->callback_1 = callback_1; - label->callback_2 = callback_2; - label->args[0] = args[0]; - label->args[1] = args[1]; - label->args[2] = args[2]; - label->args[3] = args[3]; + label->status = LabelStatus::New; + label->callbacks.dst_gpu_addr32 = dst_gpu_addr; + label->callbacks.value32 = value; + label->callbacks.dst_gpu_addr64 = nullptr; + label->callbacks.value64 = 0; + label->event = nullptr; + label->device = ctx->device; + label->callbacks.callback_1 = callback_1; + label->callbacks.callback_2 = callback_2; + label->callbacks.args[0] = args[0]; + label->callbacks.args[1] = args[1]; + label->callbacks.args[2] = args[2]; + label->callbacks.args[3] = args[3]; VkEventCreateInfo create_info {}; create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; diff --git a/source/include/Kyty/Core/Threads.h b/source/include/Kyty/Core/Threads.h index cb6a126..db7d433 100644 --- a/source/include/Kyty/Core/Threads.h +++ b/source/include/Kyty/Core/Threads.h @@ -10,7 +10,9 @@ KYTY_SUBSYSTEM_DEFINE(Threads); using thread_func_t = void (*)(void*); -// struct ThreadPrivate; +struct ThreadPrivate; +struct MutexPrivate; +struct CondVarPrivate; class String; class Thread @@ -25,6 +27,9 @@ public: // Once a thread has finished, the id may be reused by another thread. [[nodiscard]] String GetId() const; + // The id is unique and can't be reused by another thread. + [[nodiscard]] int GetUniqueId() const; + static void Sleep(uint32_t millis); static void SleepMicro(uint32_t micros); static void SleepNano(uint64_t nanos); @@ -41,7 +46,6 @@ public: KYTY_CLASS_NO_COPY(Thread); private: - struct ThreadPrivate; ThreadPrivate* m_thread; }; @@ -60,7 +64,6 @@ public: KYTY_CLASS_NO_COPY(Mutex); private: - struct MutexPrivate; MutexPrivate* m_mutex; }; @@ -97,7 +100,6 @@ public: KYTY_CLASS_NO_COPY(CondVar); private: - struct CondVarPrivate; CondVarPrivate* m_cond_var; }; diff --git a/source/lib/Core/src/Threads.cpp b/source/lib/Core/src/Threads.cpp index da02d7b..2db74aa 100644 --- a/source/lib/Core/src/Threads.cpp +++ b/source/lib/Core/src/Threads.cpp @@ -1,14 +1,12 @@ #include "Kyty/Core/Threads.h" #include "Kyty/Core/DbgAssert.h" +#include "Kyty/Core/Debug.h" +#include "Kyty/Core/MagicEnum.h" #include "Kyty/Core/SafeDelete.h" #include "Kyty/Core/String.h" +#include "Kyty/Core/Vector.h" -//#define THREADS_SDL - -#ifdef THREADS_SDL -#include "SDL.h" -#else #include #include #include @@ -16,72 +14,111 @@ #include #include #include -#endif //#define KYTY_DEBUG_LOCKS namespace Kyty::Core { -#ifdef THREADS_SDL -typedef uint64_t thread_id_t; -#else using thread_id_t = std::thread::id; -#endif -struct Thread::ThreadPrivate -{ - ThreadPrivate(thread_func_t func, void* arg) - : finished(false), auto_delete(false), -#ifdef THREADS_SDL - m_func(func), m_arg(arg) - { - sdl = SDL_CreateThread(thread_run, "sdl_thread", this); - } -#else - m_thread(func, arg) - { - } -#endif - - bool finished; - bool auto_delete; -#ifdef THREADS_SDL - SDL_Thread* sdl; - thread_func_t m_func; - void* m_arg; - - static int thread_run(void* data) - { - ThreadPrivate* t = (ThreadPrivate*)data; - t->m_func(t->m_arg); - return 0; - } - -#else - std::thread m_thread; -#endif -}; - -struct Mutex::MutexPrivate -{ -#ifdef THREADS_SDL - SDL_mutex* sdl; -#else #ifdef KYTY_DEBUG_LOCKS - std::recursive_timed_mutex m_mutex; +constexpr auto DBG_TRY_SECONDS = std::chrono::seconds(15); +#endif + +struct MutexPrivate +{ +#ifdef KYTY_DEBUG_LOCKS + std::recursive_timed_mutex m_mutex; #else std::recursive_mutex m_mutex; #endif -#endif }; -struct CondVar::CondVarPrivate +struct CondVarPrivate { -#ifdef THREADS_SDL - SDL_cond* sdl; -#else std::condition_variable_any m_cv; +}; + +class WaitForGraph +{ +public: + using T = int; + using R = MutexPrivate*; + using Cycle = Vector; + + enum class Link + { + None, + Own, + Wait, + CondVar + }; + + WaitForGraph() = default; + virtual ~WaitForGraph() = default; + + KYTY_CLASS_NO_COPY(WaitForGraph); + + void DbgDump(const Vector& list); + Vector DetectDeadlocks(); + + int Insert(T t, R r, Link link); + void Update(int index, Link link); + void DeleteByIndex(int index); + void Delete(T t, R r, Link link); + void Delete(T t); + void Delete(R r); + +private: + void FindCycles(Cycle* c, Vector* list); + + static constexpr int MAX_EDGES = 1024; + + struct Edge + { + T t = 0; + R r = nullptr; + Link link = Link::None; + uint64_t time = 0; + DebugStack stack; + }; + + std::recursive_mutex m_mutex; + Edge m_edges[MAX_EDGES]; + int m_edges_num = 0; + uint64_t m_time = 0; + bool m_disabled = false; +}; + +static std::atomic g_wait_for_graph = nullptr; + +struct ThreadPrivate +{ + ThreadPrivate(thread_func_t f, void* a): func(f), arg(a), m_thread(&Run, this) {} + + static void Run(ThreadPrivate* t) + { + t->unique_id = Thread::GetThreadIdUnique(); + t->started = true; + t->func(t->arg); + if (t->auto_delete) + { +#ifdef KYTY_DEBUG_LOCKS + if (g_wait_for_graph != nullptr) + { + g_wait_for_graph.load()->Delete(t->unique_id); + } #endif + } + } + + thread_func_t func; + void* arg; + std::atomic_bool finished = false; + std::atomic_bool auto_delete = false; + std::atomic_bool started = false; + int unique_id = 0; + std::thread m_thread; }; static thread_id_t g_main_thread; @@ -90,26 +127,261 @@ static std::atomic g_thread_counter = 0; KYTY_SUBSYSTEM_INIT(Threads) { -#ifdef THREADS_SDL - g_main_thread = SDL_ThreadID(); -#else g_main_thread = std::this_thread::get_id(); g_main_thread_int = Thread::GetThreadIdUnique(); -#endif + g_wait_for_graph = new WaitForGraph; } KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Threads) {} KYTY_SUBSYSTEM_DESTROY(Threads) {} -Thread::Thread(thread_func_t func, void* arg): m_thread(new ThreadPrivate(func, arg)) // @suppress("Symbol is not resolved") +void WaitForGraph::DbgDump(const Vector& list) { + std::lock_guard lock(m_mutex); + + m_disabled = true; + + Vector indices; + + for (const auto& c: list) + { + printf("cycle: "); + for (int n: c) + { + printf("%d ", n); + indices.Add(n); + } + printf("\n"); + } + + for (int index = 0; index < m_edges_num; index++) + { + auto& e = m_edges[index]; + if (e.link != Link::None && (indices.IsEmpty() || indices.Contains(index))) + { + printf("\n[%d] thread = %d, mutex = %" PRIx64 ", link = %s, time = %" PRIu64 "\n\n", index, e.t, + reinterpret_cast(e.r), Core::EnumName(e.link).C_Str(), e.time); + e.stack.Print(0); + } + } + + m_disabled = false; +} + +Vector WaitForGraph::DetectDeadlocks() +{ + std::lock_guard lock(m_mutex); + + m_disabled = true; + + Cycle c; + Vector list; + + FindCycles(&c, &list); + + m_disabled = false; + + return list; +} + +void WaitForGraph::FindCycles(Cycle* c, Vector* list) +{ + uint32_t size = c->Size(); + int last = -1; + if (size > 0) + { + last = c->At(size - 1); + for (uint32_t i = 0; i < size - 1; i++) + { + if (c->At(i) == last) + { + list->Add(*c); + return; + } + } + } + + Cycle nc = *c; + const auto* l = (last >= 0 ? &m_edges[last] : nullptr); + for (int index = 0; index < m_edges_num; index++) + { + const auto& e = m_edges[index]; + if (e.link != Link::None && (last < 0 || (l->link == Link::Own && l->r == e.r && e.link == Link::Wait) || + (l->link == Link::Wait && l->t == e.t && e.link == Link::Own))) + { + nc.Add(index); + FindCycles(&nc, list); + nc.RemoveAt(size); + } + } +} + +int WaitForGraph::Insert(T t, R r, Link link) +{ + std::lock_guard lock(m_mutex); + + if (m_disabled) + { + return -1; + } + + Edge* edge = nullptr; + int index = 0; + for (index = 0; index < m_edges_num; index++) + { + auto& e = m_edges[index]; + if (e.link == Link::None) + { + edge = &e; + break; + } + } + + if (edge == nullptr) + { + if (m_edges_num < MAX_EDGES) + { + edge = &m_edges[index]; + m_edges_num++; + } else + { + return -1; + } + } + + edge->t = t; + edge->r = r; + edge->link = link; + edge->time = ++m_time; + DebugStack::Trace(&edge->stack); + + return index; +} + +void WaitForGraph::Update(int index, Link link) +{ + std::lock_guard lock(m_mutex); + + if (m_disabled) + { + return; + } + + if (index >= 0 && index < MAX_EDGES) + { + m_edges[index].link = link; + m_edges[index].time = ++m_time; + DebugStack::Trace(&m_edges[index].stack); + } +} + +void WaitForGraph::DeleteByIndex(int index) +{ + std::lock_guard lock(m_mutex); + + if (m_disabled) + { + return; + } + + if (index >= 0 && index < MAX_EDGES) + { + m_edges[index].link = Link::None; + } +} + +void WaitForGraph::Delete(T t, R r, Link l) +{ + std::lock_guard lock(m_mutex); + + if (m_disabled) + { + return; + } + + uint64_t max_time = 0; + int max_index = -1; + for (int index = 0; index < m_edges_num; index++) + { + auto& e = m_edges[index]; + if (e.t == t && e.r == r && e.link == l && e.time > max_time) + { + max_time = e.time; + max_index = index; + } + } + + if (max_index >= 0) + { + m_edges[max_index].link = Link::None; + if (max_index == m_edges_num - 1) + { + m_edges_num--; + } + } +} + +void WaitForGraph::Delete(T t) +{ + std::lock_guard lock(m_mutex); + + if (m_disabled) + { + return; + } + + for (int index = 0; index < m_edges_num; index++) + { + auto& e = m_edges[index]; + if (e.t == t && e.link != Link::None) + { + e.link = Link::None; + } + } +} + +void WaitForGraph::Delete(R r) +{ + std::lock_guard lock(m_mutex); + + if (m_disabled) + { + return; + } + + for (int index = 0; index < m_edges_num; index++) + { + auto& e = m_edges[index]; + if (e.r == r && e.link != Link::None) + { + e.link = Link::None; + } + } +} + +Thread::Thread(thread_func_t func, void* arg): m_thread(new ThreadPrivate(func, arg)) +{ + while (!m_thread->started) + { + Core::Thread::SleepMicro(1000); + } } Thread::~Thread() { EXIT_IF(!m_thread->finished && !m_thread->auto_delete); + if (m_thread->finished) + { +#ifdef KYTY_DEBUG_LOCKS + if (g_wait_for_graph != nullptr) + { + g_wait_for_graph.load()->Delete(m_thread->unique_id); + } +#endif + } + Delete(m_thread); } @@ -117,13 +389,7 @@ void Thread::Join() { EXIT_IF(m_thread->finished || m_thread->auto_delete); -#ifdef THREADS_SDL - int status = -1; - SDL_WaitThread(m_thread->sdl, &status); - EXIT_IF(status != 0); -#else m_thread->m_thread.join(); -#endif m_thread->finished = true; } @@ -133,107 +399,99 @@ void Thread::Detach() EXIT_IF(m_thread->finished || m_thread->auto_delete); m_thread->auto_delete = true; -#ifdef THREADS_SDL - SDL_DetachThread(m_thread->sdl); -#else m_thread->m_thread.detach(); -#endif } void Thread::Sleep(uint32_t millis) { -#ifdef THREADS_SDL - SDL_Delay(millis); -#else std::this_thread::sleep_for(std::chrono::milliseconds(millis)); -#endif } void Thread::SleepMicro(uint32_t micros) { -#ifdef THREADS_SDL - SDL_Delay(micros / 1000); -#else std::this_thread::sleep_for(std::chrono::microseconds(micros)); -#endif } void Thread::SleepNano(uint64_t nanos) { -#ifdef THREADS_SDL - SDL_Delay(nanos / 1000000); -#else std::this_thread::sleep_for(std::chrono::nanoseconds(nanos)); -#endif } bool Thread::IsMainThread() { -#ifdef THREADS_SDL - return g_main_thread == thread_id_t(SDL_ThreadID()); -#else return g_main_thread == std::this_thread::get_id(); -#endif } String Thread::GetId() const { -#ifdef THREADS_SDL - return String::FromPrintf("%" PRIu64, (uint64_t)SDL_GetThreadID(m_thread->sdl)); -#else std::stringstream ss; ss << m_thread->m_thread.get_id(); return String::FromUtf8(ss.str().c_str()); -#endif +} + +int Thread::GetUniqueId() const +{ + return m_thread->unique_id; } String Thread::GetThreadId() { -#ifdef THREADS_SDL - return String::FromPrintf("%" PRIu64, (uint64_t)SDL_ThreadID()); -#else std::stringstream ss; ss << std::this_thread::get_id(); return String::FromUtf8(ss.str().c_str()); -#endif } -Mutex::Mutex(): m_mutex(new MutexPrivate) -{ -#ifdef THREADS_SDL - m_mutex->sdl = SDL_CreateMutex(); - EXIT_IF(!m_mutex->sdl); -#endif -} +Mutex::Mutex(): m_mutex(new MutexPrivate) {} Mutex::~Mutex() { -#ifdef THREADS_SDL - SDL_DestroyMutex(m_mutex->sdl); +#ifdef KYTY_DEBUG_LOCKS + if (g_wait_for_graph != nullptr) + { + g_wait_for_graph.load()->Delete(m_mutex); + } #endif Delete(m_mutex); } void Mutex::Lock() { -#ifdef THREADS_SDL - SDL_LockMutex(m_mutex->sdl); -#else #ifdef KYTY_DEBUG_LOCKS - if (!m_mutex->m_mutex.try_lock_for(std::chrono::seconds(20))) + if (g_wait_for_graph != nullptr) { - EXIT("lock timeout!"); + int index = g_wait_for_graph.load()->Insert(Thread::GetThreadIdUnique(), m_mutex, WaitForGraph::Link::Wait); + bool locked = false; + do + { + locked = m_mutex->m_mutex.try_lock_for(DBG_TRY_SECONDS); + + if (!locked) + { + if (auto list = g_wait_for_graph.load()->DetectDeadlocks(); !list.IsEmpty()) + { + g_wait_for_graph.load()->DbgDump(list); + EXIT("deadlock!"); + } + } + } while (!locked); + g_wait_for_graph.load()->Update(index, WaitForGraph::Link::Own); + } else + { + m_mutex->m_mutex.lock(); } #else m_mutex->m_mutex.lock(); #endif -#endif } void Mutex::Unlock() { -#ifdef THREADS_SDL - SDL_UnlockMutex(m_mutex->sdl); +#ifdef KYTY_DEBUG_LOCKS + if (g_wait_for_graph != nullptr) + { + g_wait_for_graph.load()->Delete(Thread::GetThreadIdUnique(), m_mutex, WaitForGraph::Link::Own); + } + m_mutex->m_mutex.unlock(); #else m_mutex->m_mutex.unlock(); #endif @@ -241,10 +499,13 @@ void Mutex::Unlock() bool Mutex::TryLock() { -#ifdef THREADS_SDL - int status = SDL_TryLockMutex(m_mutex->sdl); - if (status == 0) +#ifdef KYTY_DEBUG_LOCKS + if (m_mutex->m_mutex.try_lock()) { + if (g_wait_for_graph != nullptr) + { + g_wait_for_graph.load()->Insert(Thread::GetThreadIdUnique(), m_mutex, WaitForGraph::Link::Own); + } return true; } return false; @@ -253,42 +514,40 @@ bool Mutex::TryLock() #endif } -CondVar::CondVar(): m_cond_var(new CondVarPrivate) -{ -#ifdef THREADS_SDL - m_cond_var->sdl = SDL_CreateCond(); - EXIT_IF(!m_cond_var->sdl); -#endif -} +CondVar::CondVar(): m_cond_var(new CondVarPrivate) {} CondVar::~CondVar() { -#ifdef THREADS_SDL - SDL_DestroyCond(m_cond_var->sdl); -#endif Delete(m_cond_var); } void CondVar::Wait(Mutex* mutex) { -#ifdef THREADS_SDL - SDL_CondWait(m_cond_var->sdl, mutex->m_mutex->sdl); -#else #ifdef KYTY_DEBUG_LOCKS std::unique_lock cpp_lock(mutex->m_mutex->m_mutex, std::adopt_lock_t()); #else std::unique_lock cpp_lock(mutex->m_mutex->m_mutex, std::adopt_lock_t()); #endif +#ifdef KYTY_DEBUG_LOCKS + if (g_wait_for_graph != nullptr) + { + g_wait_for_graph.load()->Delete(Thread::GetThreadIdUnique(), mutex->m_mutex, WaitForGraph::Link::Own); + int index = g_wait_for_graph.load()->Insert(Thread::GetThreadIdUnique(), mutex->m_mutex, WaitForGraph::Link::CondVar); + m_cond_var->m_cv.wait(cpp_lock); + g_wait_for_graph.load()->DeleteByIndex(index); + g_wait_for_graph.load()->Insert(Thread::GetThreadIdUnique(), mutex->m_mutex, WaitForGraph::Link::Own); + } else + { + m_cond_var->m_cv.wait(cpp_lock); + } +#else m_cond_var->m_cv.wait(cpp_lock); - cpp_lock.release(); #endif + cpp_lock.release(); } void CondVar::WaitFor(Mutex* mutex, uint32_t micros) { -#ifdef THREADS_SDL - SDL_CondWaitTimeout(m_cond_var->sdl, mutex->m_mutex->sdl, (micros < 1000 ? 1 : micros / 1000)); -#else #ifdef KYTY_DEBUG_LOCKS std::unique_lock cpp_lock(mutex->m_mutex->m_mutex, std::adopt_lock_t()); #else @@ -296,25 +555,16 @@ void CondVar::WaitFor(Mutex* mutex, uint32_t micros) #endif m_cond_var->m_cv.wait_for(cpp_lock, std::chrono::microseconds(micros)); cpp_lock.release(); -#endif } void CondVar::Signal() { -#ifdef THREADS_SDL - SDL_CondSignal(m_cond_var->sdl); -#else m_cond_var->m_cv.notify_one(); -#endif } void CondVar::SignalAll() { -#ifdef THREADS_SDL - SDL_CondBroadcast(m_cond_var->sdl); -#else m_cond_var->m_cv.notify_all(); -#endif } int Thread::GetThreadIdUnique()