From c45a494ad5e58b21af160d33dd980349d6f91971 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 24 Feb 2020 08:03:06 +0100 Subject: [PATCH] base: re-add the threading and getopt classes. --- include/lol/base/core.h | 43 +++++++ {legacy/lol/sys => include/lol/base}/getopt.h | 0 include/lol/base/string.h | 1 + {legacy/lol/sys => include/lol/base}/thread.h | 105 ++++++++++-------- include/lol/math/polynomial.h | 2 + include/lol/math/real.h | 1 + legacy/lol/base/features.h | 2 - 7 files changed, 107 insertions(+), 47 deletions(-) create mode 100644 include/lol/base/core.h rename {legacy/lol/sys => include/lol/base}/getopt.h (100%) rename {legacy/lol/sys => include/lol/base}/thread.h (79%) diff --git a/include/lol/base/core.h b/include/lol/base/core.h new file mode 100644 index 00000000..bdbd4ba1 --- /dev/null +++ b/include/lol/base/core.h @@ -0,0 +1,43 @@ +// +// Lol Engine +// +// Copyright © 2010—2020 Sam Hocevar +// +// 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. +// + +#pragma once + +#include // _dupenv_s / std::getenv + +namespace lol +{ + +namespace os +{ + +static inline std::string getenv(std::string const &var) +{ +#if _MSC_VER + char *buf = nullptr; + size_t count = 0; + if (_dupenv_s(&buf, &count, var.c_str()) == 0 && buf) + { + std::string ret(buf); + free(buf); + return ret; + } +#else + if (auto val = std::getenv(var.c_str())) + return std::string(val); +#endif + return std::string(); +} + +} // namespace os + +} // namespace lol diff --git a/legacy/lol/sys/getopt.h b/include/lol/base/getopt.h similarity index 100% rename from legacy/lol/sys/getopt.h rename to include/lol/base/getopt.h diff --git a/include/lol/base/string.h b/include/lol/base/string.h index 9d7a7498..51428493 100644 --- a/include/lol/base/string.h +++ b/include/lol/base/string.h @@ -20,6 +20,7 @@ // #include +#include #include #include diff --git a/legacy/lol/sys/thread.h b/include/lol/base/thread.h similarity index 79% rename from legacy/lol/sys/thread.h rename to include/lol/base/thread.h index f52e320d..f60117f8 100644 --- a/legacy/lol/sys/thread.h +++ b/include/lol/base/thread.h @@ -1,7 +1,7 @@ // // Lol Engine // -// Copyright © 2010—2019 Sam Hocevar +// Copyright © 2010—2020 Sam Hocevar // // Lol Engine is free software. It comes without any warranty, to // the extent permitted by applicable law. You can redistribute it @@ -14,14 +14,17 @@ // // The Threading classes -// --------------------- +// ————————————————————— // -#include +#include +#include +#include // std::function #include #include #include +#include // assert() /* XXX: workaround for a bug in Visual Studio 2012 and 2013! * https://connect.microsoft.com/VisualStudio/feedback/details/747145 */ @@ -38,9 +41,9 @@ /* XXX: workaround for missing std::thread in mingw */ #if _GLIBCXX_MUTEX && !_GLIBCXX_HAS_GTHREADS && _WIN32 -# include "mingw.thread.h" -# include "mingw.mutex.h" -# include "mingw.condition_variable.h" +# include "../3rdparty/mingw-std-threads/mingw.thread.h" +# include "../3rdparty/mingw-std-threads/mingw.mutex.h" +# include "../3rdparty/mingw-std-threads/mingw.condition_variable.h" # undef near /* Fuck Microsoft */ # undef far /* Fuck Microsoft again */ #endif @@ -48,6 +51,50 @@ namespace lol { +// Base class for threads +class thread +{ +public: + thread(std::function fn) + : m_function(fn) + { + m_thread = std::thread(trampoline, this); + } + + ~thread() + { +#if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND + m_thread.detach(); +#else + m_thread.join(); +#endif + } + + // FIXME: move to os::has_threads? + static bool has_threads() + { + static bool const disable_threads = os::getenv("LOL_NOTHREADS").size() > 0; +#if defined __EMSCRIPTEN__ && !defined __EMSCRIPTEN_PTHREADS__ + // For some reason hardware_concurrency() will return the actual number + // of threads/cores even though the system cannot spawn threads. + return false; +#endif + return !disable_threads && std::thread::hardware_concurrency() > 1; + } + +private: + static void trampoline(thread *that) + { + that->m_function(that); +#if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND + ExitThread(0); +#endif + } + + std::thread m_thread; + std::function m_function; +}; + // This is like std::mutex but we can add debug information to it class mutex { @@ -74,7 +121,7 @@ public: { std::unique_lock uni_lock(m_mutex); - if (has_threads()) + if (thread::has_threads()) { // Wait for the mutex availability or non-fullness m_full_cond.wait(uni_lock, [&]{ return m_count < CAPACITY; }); @@ -82,7 +129,7 @@ public: do_push(value); /* Push value */ - if (has_threads()) + if (thread::has_threads()) { // Release lock and notify empty condition var (in that order) uni_lock.unlock(); @@ -95,7 +142,7 @@ public: { std::unique_lock uni_lock(m_mutex, std::defer_lock); - if (has_threads()) + if (thread::has_threads()) { // Try to lock, bail out if we fail if (!uni_lock.try_lock()) @@ -107,7 +154,7 @@ public: do_push(value); - if (has_threads()) + if (thread::has_threads()) { // Release lock and notify empty condition var (in that order) uni_lock.unlock(); @@ -120,7 +167,7 @@ public: // Will block the thread if another has already locked T pop() { - ASSERT(has_threads(), "Pop should only be used with threads. Use try_pop instead."); + assert(thread::has_threads()); // Wait for the mutex availability or non-emptiness std::unique_lock uni_lock(m_mutex); @@ -140,7 +187,7 @@ public: { std::unique_lock uni_lock(m_mutex, std::defer_lock); - if (has_threads()) + if (thread::has_threads()) { if (!uni_lock.try_lock()) return false; @@ -151,7 +198,7 @@ public: ret = do_pop(); /* Pop value */ - if (has_threads()) + if (thread::has_threads()) { // Release lock and notify full condition var (in that order) uni_lock.unlock(); @@ -186,37 +233,5 @@ private: std::condition_variable m_empty_cond, m_full_cond; }; -// Base class for threads -class thread -{ -public: - thread(std::function fn) - : m_function(fn) - { - m_thread = std::thread(trampoline, this); - } - - ~thread() - { -#if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND - m_thread.detach(); -#else - m_thread.join(); -#endif - } - -private: - static void trampoline(thread *that) - { - that->m_function(that); -#if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND - ExitThread(0); -#endif - } - - std::thread m_thread; - std::function m_function; -}; - } /* namespace lol */ diff --git a/include/lol/math/polynomial.h b/include/lol/math/polynomial.h index f5cfeea0..7a93f8c1 100644 --- a/include/lol/math/polynomial.h +++ b/include/lol/math/polynomial.h @@ -20,6 +20,8 @@ // #include +#include + #include // std::tuple #include // assert() diff --git a/include/lol/math/real.h b/include/lol/math/real.h index ccdaf05c..e9cf0601 100644 --- a/include/lol/math/real.h +++ b/include/lol/math/real.h @@ -18,6 +18,7 @@ // #include +#include #include #include diff --git a/legacy/lol/base/features.h b/legacy/lol/base/features.h index 7bacd9da..f542ce9d 100644 --- a/legacy/lol/base/features.h +++ b/legacy/lol/base/features.h @@ -118,8 +118,6 @@ static inline int isnan(float f) namespace lol { - extern bool has_threads(); - // A handy endianness test function static inline bool is_big_endian() {