aboutsummaryrefslogtreecommitdiff
path: root/src/server/resources.hh
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 18:05:18 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 18:05:18 +1100
commit1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (patch)
tree222dfcd07a1e40716127a347bbfd7119ce3d0984 /src/server/resources.hh
initial commit
Diffstat (limited to 'src/server/resources.hh')
-rw-r--r--src/server/resources.hh119
1 files changed, 119 insertions, 0 deletions
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 <memory>
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+
+#include <boost/asio.hpp>
+#include <boost/thread/thread_pool.hpp>
+
+#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 <typename T>
+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 <typename T>
+class low_priority_lock : public lock_base<T> {
+public:
+ low_priority_lock(T& t) noexcept : lock_base<T>(t) {
+ lock_base<T>::low_priority_mutex.lock();
+ lock_base<T>::next_mutex.lock();
+ lock_base<T>::data_mutex.lock();
+ lock_base<T>::next_mutex.unlock();
+ }
+ virtual ~low_priority_lock() noexcept {
+ lock_base<T>::data_mutex.unlock();
+ lock_base<T>::low_priority_mutex.unlock();
+ }
+};
+
+template <typename T>
+class high_priority_lock : public lock_base<T> {
+public:
+ high_priority_lock(T& t) noexcept : lock_base<T>(t) {
+ lock_base<T>::next_mutex.lock();
+ lock_base<T>::data_mutex.lock();
+ lock_base<T>::next_mutex.unlock();
+ }
+ virtual ~high_priority_lock() noexcept {
+ lock_base<T>::data_mutex.unlock();
+ }
+};
+
+using chunk_map_key = shared::math::coords;
+using chunk_map_value = std::unique_ptr<chunk_data>;
+using chunk_map = std::unordered_map<chunk_map_key, chunk_map_value,
+ decltype(&shared::world::chunk::hash),
+ decltype(&shared::world::chunk::equal)>;
+
+using client_map_key = shared::player::index_t;
+using client_map_value = std::unique_ptr<server::client>;
+using client_map = std::unordered_map<client_map_key, client_map_value>;
+
+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<resources> get_resources_lock() noexcept;
+high_priority_lock<resources> 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