From f0cc06c7388acb32b86301965c5b2547e4e3b919 Mon Sep 17 00:00:00 2001 From: untodesu Date: Thu, 11 Sep 2025 13:51:50 +0500 Subject: Displace threading into core (qfortress graft) --- core/CMakeLists.txt | 4 +- core/pch.hh | 2 + core/threading.cc | 127 ++++++++++++++++++++++++++++++++++++++ core/threading.hh | 50 +++++++++++++++ game/client/main.cc | 2 +- game/client/world/chunk_mesher.cc | 3 +- game/server/main.cc | 2 +- game/server/world/worldgen.cc | 3 +- game/shared/CMakeLists.txt | 4 +- game/shared/pch.hh | 2 - game/shared/threading.cc | 127 -------------------------------------- game/shared/threading.hh | 50 --------------- 12 files changed, 189 insertions(+), 187 deletions(-) create mode 100644 core/threading.cc create mode 100644 core/threading.hh delete mode 100644 game/shared/threading.cc delete mode 100644 game/shared/threading.hh diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index edcab85..16cc4f0 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -6,12 +6,14 @@ configure_file("${CMAKE_CURRENT_LIST_DIR}/version.cc.in" "${CMAKE_CURRENT_LIST_D add_library(core STATIC "${CMAKE_CURRENT_LIST_DIR}/pch.hh" + "${CMAKE_CURRENT_LIST_DIR}/threading.cc" + "${CMAKE_CURRENT_LIST_DIR}/threading.hh" "${CMAKE_CURRENT_LIST_DIR}/version.cc" "${CMAKE_CURRENT_LIST_DIR}/version.hh") target_compile_features(core PUBLIC cxx_std_20) target_include_directories(core PUBLIC "${PROJECT_SOURCE_DIR}") target_precompile_headers(core PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pch.hh") -target_link_libraries(core PUBLIC enet emhash glm physfs spdlog stb) +target_link_libraries(core PUBLIC enet emhash glm physfs spdlog stb thread_pool) add_subdirectory(config) add_subdirectory(io) diff --git a/core/pch.hh b/core/pch.hh index 924b1dd..3a013bd 100644 --- a/core/pch.hh +++ b/core/pch.hh @@ -25,6 +25,8 @@ #include #include +#include + #include #include diff --git a/core/threading.cc b/core/threading.cc new file mode 100644 index 0000000..4c7f8c8 --- /dev/null +++ b/core/threading.cc @@ -0,0 +1,127 @@ +#include "core/pch.hh" + +#include "core/threading.hh" + +#include "core/io/cmdline.hh" +#include "core/math/constexpr.hh" + +constexpr static std::string_view DEFAULT_POOL_SIZE_ARG = "4"; + +static BS::light_thread_pool* thread_pool; +static std::deque task_deque; + +static void task_process(Task* task) +{ + task->set_status(task_status::PROCESSING); + task->process(); + + if(task->get_status() == task_status::PROCESSING) { + // If the task status is still PROCESSING + // it can be deduced it hasn't been cancelled + task->set_status(task_status::COMPLETED); + } +} + +task_status Task::get_status(void) const +{ + return m_status; +} + +void Task::set_status(task_status status) +{ + m_status = status; +} + +void threading::init(void) +{ + auto argument = io::cmdline::get("threads", DEFAULT_POOL_SIZE_ARG); + auto num_concurrent_threads = std::thread::hardware_concurrency(); + unsigned int thread_pool_size; + + if(num_concurrent_threads && 0 == argument.compare("max")) { + // Use the maximum available number of concurrent + // hardware threads provided by the implementation + thread_pool_size = num_concurrent_threads; + } + else { + if(num_concurrent_threads) { + auto result = std::from_chars(argument.data(), argument.data() + argument.size(), thread_pool_size); + + if(result.ec == std::errc()) { + thread_pool_size = math::clamp(thread_pool_size, 1U, num_concurrent_threads); + } + else { + thread_pool_size = 4U; + } + } + else { + auto result = std::from_chars(argument.data(), argument.data() + argument.size(), thread_pool_size); + + if(result.ec == std::errc()) { + thread_pool_size = math::max(thread_pool_size, 1U); + } + else { + thread_pool_size = 4U; + } + } + } + + spdlog::info("threading: using {} threads for pooling tasks", thread_pool_size); + + thread_pool = new BS::light_thread_pool(thread_pool_size); + + task_deque.clear(); +} + +void threading::shutdown(void) +{ + for(auto task : task_deque) { + auto status = task->get_status(); + if((status != task_status::CANCELLED) || (status != task_status::COMPLETED)) { + task->set_status(task_status::CANCELLED); + } + } + + thread_pool->purge(); + thread_pool->wait(); + + for(auto task : task_deque) + delete task; + task_deque.clear(); + + delete thread_pool; +} + +void threading::update(void) +{ + auto task_iter = task_deque.cbegin(); + + while(task_iter != task_deque.cend()) { + auto task_ptr = *task_iter; + auto status = task_ptr->get_status(); + + if(status == task_status::CANCELLED) { + delete task_ptr; + task_iter = task_deque.erase(task_iter); + continue; + } + + if(status == task_status::COMPLETED) { + task_ptr->finalize(); + delete task_ptr; + task_iter = task_deque.erase(task_iter); + continue; + } + + task_iter = std::next(task_iter); + } +} + +void threading::detail::submit_new(Task* task) +{ + task->set_status(task_status::ENQUEUED); + + static_cast(thread_pool->submit_task(std::bind(&task_process, task))); + + task_deque.push_back(task); +} diff --git a/core/threading.hh b/core/threading.hh new file mode 100644 index 0000000..bd359ad --- /dev/null +++ b/core/threading.hh @@ -0,0 +1,50 @@ +#ifndef CORE_THREADING_HH +#define CORE_THREADING_HH 1 +#pragma once + +enum class task_status : unsigned int { + ENQUEUED = 0x0000U, + PROCESSING = 0x0001U, + COMPLETED = 0x0002U, + CANCELLED = 0x0004U, +}; + +class Task { +public: + virtual ~Task(void) = default; + virtual void process(void) = 0; + virtual void finalize(void) = 0; + + task_status get_status(void) const; + void set_status(task_status status); + +protected: + std::atomic m_status; + std::future m_future; +}; + +namespace threading +{ +void init(void); +void shutdown(void); +void update(void); +} // namespace threading + +namespace threading::detail +{ +void submit_new(Task* task); +} // namespace threading::detail + +namespace threading +{ +template +void submit(AT&&... args); +} // namespace threading + +template +inline void threading::submit(AT&&... args) +{ + threading::detail::submit_new(new T(args...)); +} + +#endif // CORE_THREADING_HH diff --git a/game/client/main.cc b/game/client/main.cc index 06a0da2..51d4670 100644 --- a/game/client/main.cc +++ b/game/client/main.cc @@ -7,11 +7,11 @@ #include "core/resource/resource.hh" #include "core/utils/epoch.hh" +#include "core/threading.hh" #include "core/version.hh" #include "shared/game.hh" #include "shared/splash.hh" -#include "shared/threading.hh" #include "client/gui/window_title.hh" #include "client/io/glfw.hh" diff --git a/game/client/world/chunk_mesher.cc b/game/client/world/chunk_mesher.cc index 9f5ce6c..53c4882 100644 --- a/game/client/world/chunk_mesher.cc +++ b/game/client/world/chunk_mesher.cc @@ -4,12 +4,13 @@ #include "core/math/crc64.hh" +#include "core/threading.hh" + #include "shared/world/chunk.hh" #include "shared/world/dimension.hh" #include "shared/world/voxel_registry.hh" #include "shared/coord.hh" -#include "shared/threading.hh" #include "client/world/chunk_quad.hh" #include "client/world/voxel_atlas.hh" diff --git a/game/server/main.cc b/game/server/main.cc index deb0f97..872307b 100644 --- a/game/server/main.cc +++ b/game/server/main.cc @@ -9,11 +9,11 @@ #include "core/resource/resource.hh" #include "core/utils/epoch.hh" +#include "core/threading.hh" #include "core/version.hh" #include "shared/game.hh" #include "shared/protocol.hh" -#include "shared/threading.hh" #include "server/game.hh" #include "server/globals.hh" diff --git a/game/server/world/worldgen.cc b/game/server/world/worldgen.cc index 99e9a78..8b02b52 100644 --- a/game/server/world/worldgen.cc +++ b/game/server/world/worldgen.cc @@ -4,11 +4,12 @@ #include "core/io/cmdline.hh" +#include "core/threading.hh" + #include "shared/world/chunk.hh" #include "shared/world/dimension.hh" #include "shared/protocol.hh" -#include "shared/threading.hh" #include "server/world/inhabited.hh" diff --git a/game/shared/CMakeLists.txt b/game/shared/CMakeLists.txt index 8a6fb57..d4cb6d8 100644 --- a/game/shared/CMakeLists.txt +++ b/game/shared/CMakeLists.txt @@ -14,14 +14,12 @@ add_library(shared STATIC "${CMAKE_CURRENT_LIST_DIR}/protocol.hh" "${CMAKE_CURRENT_LIST_DIR}/splash.cc" "${CMAKE_CURRENT_LIST_DIR}/splash.hh" - "${CMAKE_CURRENT_LIST_DIR}/threading.cc" - "${CMAKE_CURRENT_LIST_DIR}/threading.hh" "${CMAKE_CURRENT_LIST_DIR}/types.hh") target_compile_features(shared PUBLIC cxx_std_20) target_include_directories(shared PRIVATE "${PROJECT_SOURCE_DIR}") target_include_directories(shared PRIVATE "${PROJECT_SOURCE_DIR}/game") target_precompile_headers(shared PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pch.hh") -target_link_libraries(shared PUBLIC core enet entt FNL miniz parson thread_pool) +target_link_libraries(shared PUBLIC core enet entt FNL miniz parson) add_subdirectory(entity) add_subdirectory(world) diff --git a/game/shared/pch.hh b/game/shared/pch.hh index d3c09d7..95ee6d0 100644 --- a/game/shared/pch.hh +++ b/game/shared/pch.hh @@ -6,8 +6,6 @@ #include -#include - #include #include diff --git a/game/shared/threading.cc b/game/shared/threading.cc deleted file mode 100644 index 209bd3c..0000000 --- a/game/shared/threading.cc +++ /dev/null @@ -1,127 +0,0 @@ -#include "shared/pch.hh" - -#include "shared/threading.hh" - -#include "core/io/cmdline.hh" -#include "core/math/constexpr.hh" - -constexpr static std::string_view DEFAULT_POOL_SIZE_ARG = "4"; - -static BS::light_thread_pool* thread_pool; -static std::deque task_deque; - -static void task_process(Task* task) -{ - task->set_status(task_status::PROCESSING); - task->process(); - - if(task->get_status() == task_status::PROCESSING) { - // If the task status is still PROCESSING - // it can be deduced it hasn't been cancelled - task->set_status(task_status::COMPLETED); - } -} - -task_status Task::get_status(void) const -{ - return m_status; -} - -void Task::set_status(task_status status) -{ - m_status = status; -} - -void threading::init(void) -{ - auto argument = io::cmdline::get("threads", DEFAULT_POOL_SIZE_ARG); - auto num_concurrent_threads = std::thread::hardware_concurrency(); - unsigned int thread_pool_size; - - if(num_concurrent_threads && 0 == argument.compare("max")) { - // Use the maximum available number of concurrent - // hardware threads provided by the implementation - thread_pool_size = num_concurrent_threads; - } - else { - if(num_concurrent_threads) { - auto result = std::from_chars(argument.data(), argument.data() + argument.size(), thread_pool_size); - - if(result.ec == std::errc()) { - thread_pool_size = math::clamp(thread_pool_size, 1U, num_concurrent_threads); - } - else { - thread_pool_size = 4U; - } - } - else { - auto result = std::from_chars(argument.data(), argument.data() + argument.size(), thread_pool_size); - - if(result.ec == std::errc()) { - thread_pool_size = math::max(thread_pool_size, 1U); - } - else { - thread_pool_size = 4U; - } - } - } - - spdlog::info("threading: using {} threads for pooling tasks", thread_pool_size); - - thread_pool = new BS::light_thread_pool(thread_pool_size); - - task_deque.clear(); -} - -void threading::shutdown(void) -{ - for(auto task : task_deque) { - auto status = task->get_status(); - if((status != task_status::CANCELLED) || (status != task_status::COMPLETED)) { - task->set_status(task_status::CANCELLED); - } - } - - thread_pool->purge(); - thread_pool->wait(); - - for(auto task : task_deque) - delete task; - task_deque.clear(); - - delete thread_pool; -} - -void threading::update(void) -{ - auto task_iter = task_deque.cbegin(); - - while(task_iter != task_deque.cend()) { - auto task_ptr = *task_iter; - auto status = task_ptr->get_status(); - - if(status == task_status::CANCELLED) { - delete task_ptr; - task_iter = task_deque.erase(task_iter); - continue; - } - - if(status == task_status::COMPLETED) { - task_ptr->finalize(); - delete task_ptr; - task_iter = task_deque.erase(task_iter); - continue; - } - - task_iter = std::next(task_iter); - } -} - -void threading::detail::submit_new(Task* task) -{ - task->set_status(task_status::ENQUEUED); - - static_cast(thread_pool->submit_task(std::bind(&task_process, task))); - - task_deque.push_back(task); -} diff --git a/game/shared/threading.hh b/game/shared/threading.hh deleted file mode 100644 index 02903d5..0000000 --- a/game/shared/threading.hh +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef SHARED_THREADING_HH -#define SHARED_THREADING_HH 1 -#pragma once - -enum class task_status : unsigned int { - ENQUEUED = 0x0000U, - PROCESSING = 0x0001U, - COMPLETED = 0x0002U, - CANCELLED = 0x0004U, -}; - -class Task { -public: - virtual ~Task(void) = default; - virtual void process(void) = 0; - virtual void finalize(void) = 0; - - task_status get_status(void) const; - void set_status(task_status status); - -protected: - std::atomic m_status; - std::future m_future; -}; - -namespace threading -{ -void init(void); -void shutdown(void); -void update(void); -} // namespace threading - -namespace threading::detail -{ -void submit_new(Task* task); -} // namespace threading::detail - -namespace threading -{ -template -void submit(AT&&... args); -} // namespace threading - -template -inline void threading::submit(AT&&... args) -{ - threading::detail::submit_new(new T(args...)); -} - -#endif // SHARED_THREADING_HH -- cgit