From 1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df Mon Sep 17 00:00:00 2001 From: Nicolas James Date: Wed, 12 Feb 2025 18:05:18 +1100 Subject: initial commit --- src/server/resources.hh | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/server/resources.hh (limited to 'src/server/resources.hh') diff --git a/src/server/resources.hh b/src/server/resources.hh new file mode 100644 index 0000000..578a248 --- /dev/null +++ b/src/server/resources.hh @@ -0,0 +1,119 @@ +#ifndef SERVER_RESOURCES_HH_ +#define SERVER_RESOURCES_HH_ + +#include +#include +#include +#include + +#include +#include + +#include "server/chunk_data.hh" +#include "server/client.hh" +#include "server/database.hh" +#include "server/world.hh" +#include "shared/player.hh" +#include "shared/world.hh" + +namespace server { +namespace resources { + +// Occasionally we need access to certain objects quickly. +// These classes enable the server to take priority over the thread pool's work +// when necessary. Construct a low_priority_lock when it can happen whenever, +// and a high_priority_lock when it should happen ~ now. +template +class lock_base { +private: + T& obj; + +protected: + static inline std::mutex data_mutex; + static inline std::mutex next_mutex; + static inline std::mutex low_priority_mutex; + +protected: + lock_base(T& obj) noexcept : obj(obj) {} + +public: + lock_base(const lock_base&) = delete; + lock_base(lock_base&&) = default; + virtual ~lock_base(){}; + + T& get() noexcept { return this->obj; } + T& operator*() noexcept { return this->get(); } + T* const operator->() noexcept { return &this->get(); } +}; + +// https://stackoverflow.com/questions/11666610/how-to-give-priority-to-privileged-thread-in-mutex-locking +// ty ecatmur! +template +class low_priority_lock : public lock_base { +public: + low_priority_lock(T& t) noexcept : lock_base(t) { + lock_base::low_priority_mutex.lock(); + lock_base::next_mutex.lock(); + lock_base::data_mutex.lock(); + lock_base::next_mutex.unlock(); + } + virtual ~low_priority_lock() noexcept { + lock_base::data_mutex.unlock(); + lock_base::low_priority_mutex.unlock(); + } +}; + +template +class high_priority_lock : public lock_base { +public: + high_priority_lock(T& t) noexcept : lock_base(t) { + lock_base::next_mutex.lock(); + lock_base::data_mutex.lock(); + lock_base::next_mutex.unlock(); + } + virtual ~high_priority_lock() noexcept { + lock_base::data_mutex.unlock(); + } +}; + +using chunk_map_key = shared::math::coords; +using chunk_map_value = std::unique_ptr; +using chunk_map = std::unordered_map; + +using client_map_key = shared::player::index_t; +using client_map_value = std::unique_ptr; +using client_map = std::unordered_map; + +using pool_t = boost::asio::thread_pool; + +struct resources { + client_map& clients; + chunk_map& chunks; + pool_t& pool; +}; + +void init() noexcept; +void quit() noexcept; + +low_priority_lock get_resources_lock() noexcept; +high_priority_lock get_resources_lock_immediate() noexcept; + +inline void associate_client_chunk(const shared::math::coords& coords, + client_map_value& client, + chunk_map_value& chunk) noexcept { + client->chunks.emplace(coords); + chunk->players.emplace(client->index); +} +inline void disassociate_client_chunk(const shared::math::coords& coords, + client_map_value& client, + chunk_map_value& chunk) noexcept { + client->chunks.erase(coords); + chunk->players.erase(client->index); +} + +} // namespace resources +} // namespace server + +#endif -- cgit v1.2.3