| @@ -99,25 +99,26 @@ public: | |||||
| m_aabb.aa = m_position; | m_aabb.aa = m_position; | ||||
| m_aabb.bb = vec3((vec2)m_window_size, 0); | m_aabb.bb = vec3((vec2)m_window_size, 0); | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Spawn worker threads and wait for their readiness. */ | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_threads[i] = new thread(std::bind(&Fractal::DoWorkHelper, this, std::placeholders::_1)); | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_spawnqueue.pop(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| // Spawn worker threads and wait for their readiness | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_threads[i] = new thread(std::bind(&Fractal::DoWorkHelper, this, std::placeholders::_1)); | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_spawnqueue.pop(); | |||||
| } | |||||
| } | } | ||||
| ~Fractal() | ~Fractal() | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Signal worker threads for completion and wait for | |||||
| * them to quit. */ | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_jobqueue.push(-1); | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_donequeue.pop(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| // Signal worker threads for completion and wait for them to quit | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_jobqueue.push(-1); | |||||
| for (int i = 0; i < MAX_THREADS; i++) | |||||
| m_donequeue.pop(); | |||||
| } | |||||
| Ticker::Unref(m_centertext); | Ticker::Unref(m_centertext); | ||||
| Ticker::Unref(m_mousetext); | Ticker::Unref(m_mousetext); | ||||
| @@ -290,16 +291,14 @@ public: | |||||
| for (int i = 0; i < m_size.y; i += MAX_LINES * 2) | for (int i = 0; i < m_size.y; i += MAX_LINES * 2) | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| m_jobqueue.push(i); | |||||
| #else | |||||
| DoWork(i); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| m_jobqueue.push(i); | |||||
| else | |||||
| DoWork(i); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #if LOL_FEATURE_THREADS | |||||
| void DoWorkHelper(thread *) | void DoWorkHelper(thread *) | ||||
| { | { | ||||
| m_spawnqueue.push(0); | m_spawnqueue.push(0); | ||||
| @@ -313,7 +312,6 @@ public: | |||||
| } | } | ||||
| m_donequeue.push(0); | m_donequeue.push(0); | ||||
| }; | }; | ||||
| #endif | |||||
| void DoWork(int line) | void DoWork(int line) | ||||
| { | { | ||||
| @@ -475,10 +473,11 @@ public: | |||||
| if (m_dirty[m_frame]) | if (m_dirty[m_frame]) | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| for (int i = 0; i < m_size.y; i += MAX_LINES * 2) | |||||
| m_donequeue.pop(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| for (int i = 0; i < m_size.y; i += MAX_LINES * 2) | |||||
| m_donequeue.pop(); | |||||
| } | |||||
| m_dirty[m_frame]--; | m_dirty[m_frame]--; | ||||
| @@ -551,13 +550,11 @@ private: | |||||
| vec4 m_texel_settings, m_screen_settings; | vec4 m_texel_settings, m_screen_settings; | ||||
| mat4 m_zoom_settings; | mat4 m_zoom_settings; | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Worker threads */ | |||||
| // Worker threads | |||||
| thread *m_threads[MAX_THREADS]; | thread *m_threads[MAX_THREADS]; | ||||
| queue<int> m_spawnqueue, m_jobqueue, m_donequeue; | queue<int> m_spawnqueue, m_jobqueue, m_donequeue; | ||||
| #endif | |||||
| /* Debug information */ | |||||
| // Debug information | |||||
| Text *m_centertext, *m_mousetext, *m_zoomtext; | Text *m_centertext, *m_mousetext, *m_zoomtext; | ||||
| }; | }; | ||||
| @@ -88,7 +88,7 @@ liblol_core_sources = \ | |||||
| easymesh/shinydebuglighting.lolfx easymesh/shinydebugnormal.lolfx \ | easymesh/shinydebuglighting.lolfx easymesh/shinydebugnormal.lolfx \ | ||||
| easymesh/shinydebugUV.lolfx easymesh/shiny_SK.lolfx \ | easymesh/shinydebugUV.lolfx easymesh/shiny_SK.lolfx \ | ||||
| \ | \ | ||||
| base/assert.cpp base/log.cpp base/string.cpp \ | |||||
| base/assert.cpp base/features.cpp base/log.cpp base/string.cpp \ | |||||
| \ | \ | ||||
| math/vector.cpp math/matrix.cpp math/transform.cpp math/half.cpp \ | math/vector.cpp math/matrix.cpp math/transform.cpp math/half.cpp \ | ||||
| math/geometry.cpp math/real.cpp \ | math/geometry.cpp math/real.cpp \ | ||||
| @@ -0,0 +1,26 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net> | |||||
| // | |||||
| // Lol Engine is free software. It comes without any warranty, to | |||||
| // the extent permitted by applicable law. You can redistribute it | |||||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||||
| // See http://www.wtfpl.net/ for more details. | |||||
| // | |||||
| #include <lol/engine-internal.h> | |||||
| namespace lol | |||||
| { | |||||
| bool has_threads() | |||||
| { | |||||
| static char const *var = getenv("LOL_NOTHREADS"); | |||||
| static bool const disable_threads = var && var[0]; | |||||
| return !disable_threads && std::thread::hardware_concurrency() > 1; | |||||
| } | |||||
| } // namespace lol | |||||
| @@ -29,13 +29,14 @@ class ticker_data | |||||
| public: | public: | ||||
| ticker_data() | ticker_data() | ||||
| : DEPRECATED_nentities(0), | |||||
| m_frame(0), m_recording(0), deltatime(0), bias(0), fps(0), | |||||
| #if LOL_BUILD_DEBUG | |||||
| keepalive(0), | |||||
| #endif | |||||
| m_quit(0), m_quitframe(0), m_quitdelay(20), m_panic(0) | |||||
| { | { | ||||
| if (has_threads()) | |||||
| { | |||||
| gamethread = std::make_unique<thread>(std::bind(&ticker_data::GameThreadMain, this)); | |||||
| drawtick.push(1); | |||||
| diskthread = std::make_unique<thread>(std::bind(&ticker_data::DiskThreadMain, this)); | |||||
| } | |||||
| } | } | ||||
| ~ticker_data() | ~ticker_data() | ||||
| @@ -46,13 +47,14 @@ public: | |||||
| "still %d autoreleased entities\n", DEPRECATED_m_autolist.count()); | "still %d autoreleased entities\n", DEPRECATED_m_autolist.count()); | ||||
| msg::debug("%d frames required to quit\n", m_frame - m_quitframe); | msg::debug("%d frames required to quit\n", m_frame - m_quitframe); | ||||
| #if LOL_FEATURE_THREADS | |||||
| gametick.push(0); | |||||
| disktick.push(0); | |||||
| gamethread.release(); | |||||
| diskthread.release(); | |||||
| ASSERT(drawtick.size() == 0); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| gametick.push(0); | |||||
| disktick.push(0); | |||||
| gamethread.release(); | |||||
| diskthread.release(); | |||||
| ASSERT(drawtick.size() == 0); | |||||
| } | |||||
| } | } | ||||
| void handle_shutdown(); | void handle_shutdown(); | ||||
| @@ -68,14 +70,14 @@ private: | |||||
| array<entity *> DEPRECATED_m_todolist, DEPRECATED_m_todolist_delayed, DEPRECATED_m_autolist; | array<entity *> DEPRECATED_m_todolist, DEPRECATED_m_todolist_delayed, DEPRECATED_m_autolist; | ||||
| array<entity *> DEPRECATED_m_list[(int)tickable::group::all::end]; | array<entity *> DEPRECATED_m_list[(int)tickable::group::all::end]; | ||||
| array<int> DEPRECATED_m_scenes[(int)tickable::group::all::end]; | array<int> DEPRECATED_m_scenes[(int)tickable::group::all::end]; | ||||
| int DEPRECATED_nentities; | |||||
| int DEPRECATED_nentities = 0; | |||||
| /* Fixed framerate management */ | /* Fixed framerate management */ | ||||
| int m_frame, m_recording; | |||||
| int m_frame = 0, m_recording = 0; | |||||
| timer m_timer; | timer m_timer; | ||||
| float deltatime, bias, fps; | |||||
| float deltatime = 0.f, bias = 0.f, fps = 0.f; | |||||
| #if LOL_BUILD_DEBUG | #if LOL_BUILD_DEBUG | ||||
| float keepalive; | |||||
| float keepalive = 0; | |||||
| #endif | #endif | ||||
| /* The three main functions (for now) */ | /* The three main functions (for now) */ | ||||
| @@ -83,17 +85,15 @@ private: | |||||
| static void DrawThreadTick(); | static void DrawThreadTick(); | ||||
| static void DiskThreadTick(); | static void DiskThreadTick(); | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* The associated background threads */ | /* The associated background threads */ | ||||
| void GameThreadMain(); | void GameThreadMain(); | ||||
| void DrawThreadMain(); /* unused for now */ | void DrawThreadMain(); /* unused for now */ | ||||
| void DiskThreadMain(); | void DiskThreadMain(); | ||||
| std::unique_ptr<thread> gamethread, diskthread; | std::unique_ptr<thread> gamethread, diskthread; | ||||
| queue<int> gametick, drawtick, disktick; | queue<int> gametick, drawtick, disktick; | ||||
| #endif | |||||
| /* Shutdown management */ | /* Shutdown management */ | ||||
| int m_quit, m_quitframe, m_quitdelay, m_panic; | |||||
| int m_quit = 0, m_quitframe = 0, m_quitdelay = 20, m_panic = 0; | |||||
| }; | }; | ||||
| static std::unique_ptr<ticker_data> data; | static std::unique_ptr<ticker_data> data; | ||||
| @@ -169,7 +169,6 @@ int Ticker::Unref(entity *entity) | |||||
| return --entity->m_ref; | return --entity->m_ref; | ||||
| } | } | ||||
| #if LOL_FEATURE_THREADS | |||||
| void ticker_data::GameThreadMain() | void ticker_data::GameThreadMain() | ||||
| { | { | ||||
| #if LOL_BUILD_DEBUG | #if LOL_BUILD_DEBUG | ||||
| @@ -193,9 +192,7 @@ void ticker_data::GameThreadMain() | |||||
| msg::debug("ticker game thread terminated\n"); | msg::debug("ticker game thread terminated\n"); | ||||
| #endif | #endif | ||||
| } | } | ||||
| #endif /* LOL_FEATURE_THREADS */ | |||||
| #if LOL_FEATURE_THREADS | |||||
| void ticker_data::DrawThreadMain() /* unused */ | void ticker_data::DrawThreadMain() /* unused */ | ||||
| { | { | ||||
| #if LOL_BUILD_DEBUG | #if LOL_BUILD_DEBUG | ||||
| @@ -217,15 +214,12 @@ void ticker_data::DrawThreadMain() /* unused */ | |||||
| msg::debug("ticker draw thread terminated\n"); | msg::debug("ticker draw thread terminated\n"); | ||||
| #endif | #endif | ||||
| } | } | ||||
| #endif /* LOL_FEATURE_THREADS */ | |||||
| #if LOL_FEATURE_THREADS | |||||
| void ticker_data::DiskThreadMain() | void ticker_data::DiskThreadMain() | ||||
| { | { | ||||
| /* FIXME: temporary hack to avoid crashes on the PS3 */ | /* FIXME: temporary hack to avoid crashes on the PS3 */ | ||||
| disktick.pop(); | disktick.pop(); | ||||
| } | } | ||||
| #endif /* LOL_FEATURE_THREADS */ | |||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||
| void ticker_data::GameThreadTick() | void ticker_data::GameThreadTick() | ||||
| @@ -565,13 +559,6 @@ void ticker::setup(float fps) | |||||
| { | { | ||||
| data = std::make_unique<ticker_data>(); | data = std::make_unique<ticker_data>(); | ||||
| data->fps = fps; | data->fps = fps; | ||||
| #if LOL_FEATURE_THREADS | |||||
| data->gamethread = std::make_unique<thread>(std::bind(&ticker_data::GameThreadMain, data.get())); | |||||
| data->drawtick.push(1); | |||||
| data->diskthread = std::make_unique<thread>(std::bind(&ticker_data::DiskThreadMain, data.get())); | |||||
| #endif | |||||
| } | } | ||||
| void ticker::teardown() | void ticker::teardown() | ||||
| @@ -581,24 +568,24 @@ void ticker::teardown() | |||||
| void ticker::tick_draw() | void ticker::tick_draw() | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| int n = data->drawtick.pop(); | |||||
| if (n == 0) | |||||
| return; | |||||
| #else | |||||
| ticker_data::GameThreadTick(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| int n = data->drawtick.pop(); | |||||
| if (n == 0) | |||||
| return; | |||||
| } | |||||
| else | |||||
| ticker_data::GameThreadTick(); | |||||
| ticker_data::DrawThreadTick(); | ticker_data::DrawThreadTick(); | ||||
| Profiler::Start(Profiler::STAT_TICK_BLIT); | Profiler::Start(Profiler::STAT_TICK_BLIT); | ||||
| /* Signal game thread that it can carry on */ | /* Signal game thread that it can carry on */ | ||||
| #if LOL_FEATURE_THREADS | |||||
| data->gametick.push(1); | |||||
| #else | |||||
| ticker_data::DiskThreadTick(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| data->gametick.push(1); | |||||
| else | |||||
| ticker_data::DiskThreadTick(); | |||||
| /* Clamp FPS */ | /* Clamp FPS */ | ||||
| Profiler::Stop(Profiler::STAT_TICK_BLIT); | Profiler::Stop(Profiler::STAT_TICK_BLIT); | ||||
| @@ -106,6 +106,7 @@ | |||||
| <ClCompile Include="audio\sample.cpp" /> | <ClCompile Include="audio\sample.cpp" /> | ||||
| <ClCompile Include="camera.cpp" /> | <ClCompile Include="camera.cpp" /> | ||||
| <ClCompile Include="base\assert.cpp" /> | <ClCompile Include="base\assert.cpp" /> | ||||
| <ClCompile Include="base\features.cpp" /> | |||||
| <ClCompile Include="base\log.cpp" /> | <ClCompile Include="base\log.cpp" /> | ||||
| <ClCompile Include="base\string.cpp" /> | <ClCompile Include="base\string.cpp" /> | ||||
| <ClCompile Include="debug\fps.cpp" /> | <ClCompile Include="debug\fps.cpp" /> | ||||
| @@ -14,6 +14,9 @@ | |||||
| <ClCompile Include="base\assert.cpp"> | <ClCompile Include="base\assert.cpp"> | ||||
| <Filter>base</Filter> | <Filter>base</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="base\features.cpp"> | |||||
| <Filter>base</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="base\log.cpp"> | <ClCompile Include="base\log.cpp"> | ||||
| <Filter>base</Filter> | <Filter>base</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -17,16 +17,6 @@ | |||||
| // ----------------------- | // ----------------------- | ||||
| // | // | ||||
| /* | |||||
| * System, CPU and compiler features. | |||||
| */ | |||||
| #define LOL_FEATURE_THREADS 1 | |||||
| #if defined __EMSCRIPTEN__ | |||||
| # undef LOL_FEATURE_THREADS | |||||
| #endif | |||||
| /* | /* | ||||
| * Check for C++11 and later features. | * Check for C++11 and later features. | ||||
| */ | */ | ||||
| @@ -168,12 +158,15 @@ static inline int isnan(float f) | |||||
| #endif | #endif | ||||
| /* | |||||
| * A handy endianness test function | |||||
| */ | |||||
| // | |||||
| // Some feature test functions | |||||
| // | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| extern bool has_threads(); | |||||
| // A handy endianness test function | |||||
| static inline bool is_big_endian() | static inline bool is_big_endian() | ||||
| { | { | ||||
| union { int i; char c; } u; | union { int i; char c; } u; | ||||
| @@ -19,13 +19,9 @@ | |||||
| #include <functional> | #include <functional> | ||||
| #if LOL_FEATURE_THREADS | |||||
| # include <thread> | |||||
| # include <mutex> | |||||
| # include <condition_variable> | |||||
| #else | |||||
| /* Nothing */ | |||||
| #endif | |||||
| #include <thread> | |||||
| #include <mutex> | |||||
| #include <condition_variable> | |||||
| /* XXX: workaround for a bug in Visual Studio 2012 and 2013! | /* XXX: workaround for a bug in Visual Studio 2012 and 2013! | ||||
| * https://connect.microsoft.com/VisualStudio/feedback/details/747145 */ | * https://connect.microsoft.com/VisualStudio/feedback/details/747145 */ | ||||
| @@ -52,38 +48,18 @@ | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| // This is like std::mutex but we can add debug information to it | |||||
| class mutex | class mutex | ||||
| { | { | ||||
| public: | public: | ||||
| // Will block the thread if another has already locked | |||||
| void lock() | |||||
| { | |||||
| #if LOL_FEATURE_THREADS | |||||
| m_mutex.lock(); | |||||
| #endif | |||||
| } | |||||
| inline void lock() { m_mutex.lock(); } | |||||
| // Will not block if another thread has already locked | |||||
| bool try_lock() | |||||
| { | |||||
| #if LOL_FEATURE_THREADS | |||||
| return m_mutex.try_lock(); | |||||
| #else | |||||
| return false; | |||||
| #endif | |||||
| } | |||||
| inline bool try_lock() { return m_mutex.try_lock(); } | |||||
| void unlock() | |||||
| { | |||||
| #if LOL_FEATURE_THREADS | |||||
| m_mutex.unlock(); | |||||
| #endif | |||||
| } | |||||
| inline void unlock() { m_mutex.unlock(); } | |||||
| private: | private: | ||||
| #if LOL_FEATURE_THREADS | |||||
| std::mutex m_mutex; | std::mutex m_mutex; | ||||
| #endif | |||||
| }; | }; | ||||
| // A FIFO queue for threads | // A FIFO queue for threads | ||||
| @@ -91,58 +67,52 @@ template<typename T, int N = 128> | |||||
| class queue | class queue | ||||
| { | { | ||||
| public: | public: | ||||
| queue() | |||||
| : m_start(0), | |||||
| m_count(0) | |||||
| {} | |||||
| int size() const { return m_count; } | int size() const { return m_count; } | ||||
| // Will block the thread if another has already locked | // Will block the thread if another has already locked | ||||
| void push(T value) | void push(T value) | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Wait for the mutex availability or non-fullness */ | |||||
| std::unique_lock<std::mutex> uni_lock(m_mutex); | std::unique_lock<std::mutex> uni_lock(m_mutex); | ||||
| m_full_cond.wait(uni_lock, [&]{ return m_count < CAPACITY; }); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| // Wait for the mutex availability or non-fullness | |||||
| m_full_cond.wait(uni_lock, [&]{ return m_count < CAPACITY; }); | |||||
| } | |||||
| do_push(value); /* Push value */ | do_push(value); /* Push value */ | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Release lock and notify empty condition var (in that order) */ | |||||
| uni_lock.unlock(); | |||||
| m_empty_cond.notify_one(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| // Release lock and notify empty condition var (in that order) | |||||
| uni_lock.unlock(); | |||||
| m_empty_cond.notify_one(); | |||||
| } | |||||
| } | } | ||||
| // Will not block if another has already locked | // Will not block if another has already locked | ||||
| bool try_push(T value) | bool try_push(T value) | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Same as Push(), except .... */ | |||||
| std::unique_lock<std::mutex> uni_lock(m_mutex, std::try_to_lock); | |||||
| /* Bail on fail try_lock fail */ | |||||
| if (!uni_lock.owns_lock()) | |||||
| return false; | |||||
| /* Bail on max CAPACITY */ | |||||
| if (m_count == CAPACITY) | |||||
| std::unique_lock<std::mutex> uni_lock(m_mutex, std::defer_lock); | |||||
| if (has_threads()) | |||||
| { | { | ||||
| uni_lock.unlock(); | |||||
| return false; | |||||
| // Try to lock, bail out if we fail | |||||
| if (!uni_lock.try_lock()) | |||||
| return false; | |||||
| } | } | ||||
| #else | |||||
| if (m_count == CAPACITY) | if (m_count == CAPACITY) | ||||
| return false; | |||||
| #endif | |||||
| return false; // unlocks uni_lock | |||||
| do_push(value); /* Push value */ | |||||
| do_push(value); | |||||
| #if LOL_FEATURE_THREADS | |||||
| /* Release lock and notify empty condition var (in that order) */ | |||||
| uni_lock.unlock(); | |||||
| m_empty_cond.notify_one(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| // Release lock and notify empty condition var (in that order) | |||||
| uni_lock.unlock(); | |||||
| m_empty_cond.notify_one(); | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -150,21 +120,17 @@ public: | |||||
| // Will block the thread if another has already locked | // Will block the thread if another has already locked | ||||
| T pop() | T pop() | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Wait for the mutex availability or non-emptiness */ | |||||
| ASSERT(has_threads(), "Pop should only be used with threads. Use try_pop instead."); | |||||
| // Wait for the mutex availability or non-emptiness | |||||
| std::unique_lock<std::mutex> uni_lock(m_mutex); | std::unique_lock<std::mutex> uni_lock(m_mutex); | ||||
| m_empty_cond.wait(uni_lock, [&]{return m_count > 0; }); | m_empty_cond.wait(uni_lock, [&]{return m_count > 0; }); | ||||
| #else | |||||
| ASSERT(0, "Pop should only be used with threads. Use try_pop instead."); | |||||
| #endif | |||||
| T ret = do_pop(); /* Pop value */ | |||||
| T ret = do_pop(); | |||||
| #if LOL_FEATURE_THREADS | |||||
| /* Release lock and notify full condition var (in that order) */ | |||||
| // Release lock and notify full condition var (in that order) | |||||
| uni_lock.unlock(); | uni_lock.unlock(); | ||||
| m_full_cond.notify_one(); | m_full_cond.notify_one(); | ||||
| #endif | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -172,30 +138,25 @@ public: | |||||
| // Will not block if another has already locked | // Will not block if another has already locked | ||||
| bool try_pop(T &ret) | bool try_pop(T &ret) | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Same as Pop(), except .... */ | |||||
| std::unique_lock<std::mutex> uni_lock(m_mutex, std::try_to_lock); | |||||
| /* Bail on fail try_lock fail */ | |||||
| if (!uni_lock.owns_lock()) | |||||
| return false; | |||||
| /* Bail on zero count */ | |||||
| if (m_count == 0) | |||||
| std::unique_lock<std::mutex> uni_lock(m_mutex, std::defer_lock); | |||||
| if (has_threads()) | |||||
| { | { | ||||
| uni_lock.unlock(); | |||||
| return false; | |||||
| if (!uni_lock.try_lock()) | |||||
| return false; | |||||
| } | } | ||||
| #else | |||||
| if (m_count == 0) | if (m_count == 0) | ||||
| return false; | return false; | ||||
| #endif | |||||
| ret = do_pop(); /* Pop value */ | ret = do_pop(); /* Pop value */ | ||||
| #if LOL_FEATURE_THREADS | |||||
| /* Release lock and notify full condition var (in that order) */ | |||||
| uni_lock.unlock(); | |||||
| m_full_cond.notify_one(); | |||||
| #endif | |||||
| if (has_threads()) | |||||
| { | |||||
| // Release lock and notify full condition var (in that order) | |||||
| uni_lock.unlock(); | |||||
| m_full_cond.notify_one(); | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -219,11 +180,10 @@ private: | |||||
| private: | private: | ||||
| static int const CAPACITY = N; | static int const CAPACITY = N; | ||||
| T m_values[CAPACITY]; | T m_values[CAPACITY]; | ||||
| int m_start, m_count; | |||||
| #if LOL_FEATURE_THREADS | |||||
| int m_start = 0, m_count = 0; | |||||
| std::mutex m_mutex; | std::mutex m_mutex; | ||||
| std::condition_variable m_empty_cond, m_full_cond; | std::condition_variable m_empty_cond, m_full_cond; | ||||
| #endif | |||||
| }; | }; | ||||
| // Base class for threads | // Base class for threads | ||||
| @@ -233,36 +193,28 @@ public: | |||||
| thread(std::function<void(thread*)> fn) | thread(std::function<void(thread*)> fn) | ||||
| : m_function(fn) | : m_function(fn) | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| m_thread = std::thread(trampoline, this); | m_thread = std::thread(trampoline, this); | ||||
| #endif | |||||
| } | } | ||||
| ~thread() | ~thread() | ||||
| { | { | ||||
| #if LOL_FEATURE_THREADS | |||||
| # if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND | |||||
| #if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND | |||||
| m_thread.detach(); | m_thread.detach(); | ||||
| # else | |||||
| #else | |||||
| m_thread.join(); | m_thread.join(); | ||||
| # endif | |||||
| #endif | #endif | ||||
| } | } | ||||
| private: | private: | ||||
| #if LOL_FEATURE_THREADS | |||||
| static void trampoline(thread *that) | static void trampoline(thread *that) | ||||
| { | { | ||||
| that->m_function(that); | that->m_function(that); | ||||
| # if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND | |||||
| #if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND | |||||
| ExitThread(0); | ExitThread(0); | ||||
| # endif | |||||
| } | |||||
| #endif | #endif | ||||
| } | |||||
| #if LOL_FEATURE_THREADS | |||||
| std::thread m_thread; | std::thread m_thread; | ||||
| #endif | |||||
| std::function<void(thread*)> m_function; | std::function<void(thread*)> m_function; | ||||
| }; | }; | ||||