@@ -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; | ||||
}; | }; | ||||