]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Use thread pool for map generation
authorElias Fleckenstein <eliasfleckenstein@web.de>
Sun, 13 Feb 2022 20:12:52 +0000 (21:12 +0100)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Sun, 13 Feb 2022 20:12:52 +0000 (21:12 +0100)
deps/dragonstd
snapshot.sh
src/client/client_map.c
src/server/server_config.c
src/server/server_config.h
src/server/server_map.c
src/server/server_map.h

index 04c93844e4e4185d91950f0f5473bc88a84b5461..0f30ec889c7a70ab7f7b79836d1a34ddf8659a47 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 04c93844e4e4185d91950f0f5473bc88a84b5461
+Subproject commit 0f30ec889c7a70ab7f7b79836d1a34ddf8659a47
index f03ceed2d3d602307eff5c5de688232c2e205484..6d4363d42485154a00bf6273194a174b7c52cac8 100755 (executable)
@@ -11,7 +11,7 @@ if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="\"\"" &&
 fi
 cp Dragonblocks DragonblocksServer ..
 cd ..
-rm -rf .git* deps src build BUILDING.md snapshot.sh upload.sh DragonblocksAlpha-*.zip screenshot-*.png
+rm -rf .git* deps src build BUILDING.md snapshot.sh upload.sh DragonblocksAlpha-*.zip DragonblocksAlpha screenshot-*.png
 cd ..
 mv .build DragonblocksAlpha
 VERSION=`git tag --points-at HEAD`
index 5d2d50eab6ea2d279c0bbeb6acd42aeb69d36007..f61734102b905900af3d99254c37241f02d81f89 100644 (file)
@@ -168,7 +168,7 @@ void client_map_init()
 
        client_map.meshgen_threads = malloc(sizeof *client_map.meshgen_threads * client_config.meshgen_threads);
        for (unsigned int i = 0; i < client_config.meshgen_threads; i++)
-               client_map.meshgen_threads[i] = 0;
+               client_map.meshgen_threads[i] = 0; // why
 }
 
 // ClientMap singleton destructor
index ec79abc226f3e8f1ab2b92e5eb19aa04443334f8..e4d146ee871a1828103020fd4736cdcae3d38abe 100644 (file)
@@ -3,6 +3,7 @@
 
 struct ServerConfig server_config = {
        .simulation_distance = 10,
+       .mapgen_threads = 4,
 };
 
 __attribute__((constructor)) static void server_config_init()
@@ -13,6 +14,11 @@ __attribute__((constructor)) static void server_config_init()
                        .key = "simulation_distance",
                        .value = &server_config.simulation_distance,
                },
-       }, 1);
+               {
+                       .type = CT_UINT,
+                       .key = "mapgen_threads",
+                       .value = &server_config.mapgen_threads,
+               },
+       }, 2);
 }
 
index 992a3c8b2c9e82b09282ba0fa0bef29d24ee828a..4effe332b164a086fb38de8b585116c0c16a1ce2 100644 (file)
@@ -3,6 +3,7 @@
 
 extern struct ServerConfig {
        unsigned int simulation_distance;
+       unsigned int mapgen_threads;
 } server_config;
 
 #endif
index 3cadbc19b3568f4a23e57af1a18683caa14bdaac..854afe15d548e8820a5a04e893a41ae90b11215e 100644 (file)
@@ -10,6 +10,7 @@
 #include "server/server_map.h"
 #include "util.h"
 
+// this file is too long
 struct ServerMap server_map;
 
 // utility functions
@@ -68,15 +69,15 @@ static void list_send_block(void *key, unused void *value, unused void *arg)
        pthread_mutex_unlock(&block->mtx);
 }
 
-// pthread start routine for mapgen thread
-static void *mapgen_thread(void *arg)
+// me when the
+static void mapgen_step()
 {
-       MapBlock *block = arg;
-       MapBlockExtraData *extra = block->extra;
+       MapBlock *block = queue_dequeue(server_map.mapgen_tasks);
 
-       pthread_mutex_lock(&block->mtx);
-       extra->state = MBS_GENERATING;
-       pthread_mutex_unlock(&block->mtx);
+       if (! block)
+               return;
+
+       MapBlockExtraData *extra = block->extra;
 
        List changed_blocks = list_create(NULL);
        list_put(&changed_blocks, block, NULL);
@@ -89,32 +90,33 @@ static void *mapgen_thread(void *arg)
 
        list_clear_func(&changed_blocks, &list_send_block, NULL);
 
-       pthread_mutex_lock(&server_map.joining_threads_mtx);
-       if (! server_map.joining_threads) {
-               pthread_mutex_lock(&server_map.mapgen_threads_mtx);
-               list_delete(&server_map.mapgen_threads, &extra->mapgen_thread);
-               pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
-       }
-       pthread_mutex_unlock(&server_map.joining_threads_mtx);
-
-       return NULL;
+       pthread_mutex_lock(&server_map.num_blocks_mtx);
+       server_map.num_blocks--;
+       pthread_mutex_unlock(&server_map.num_blocks_mtx);
 }
 
-// launch mapgen thread for block
-// block mutex has to be locked
-static void launch_mapgen_thread(MapBlock *block)
+// there was a time when i wrote actually useful comments lol
+static void *mapgen_thread(unused void *arg)
 {
-       pthread_mutex_lock(&server_map.mapgen_threads_mtx);
-       pthread_t *thread_ptr = &((MapBlockExtraData *) block->extra)->mapgen_thread;
-       pthread_create(thread_ptr, NULL, mapgen_thread, block);
-       list_put(&server_map.mapgen_threads, thread_ptr, NULL);
-       pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
+       while (! server_map.cancel)
+               mapgen_step();
+
+       return NULL;
 }
 
-// list_clear_func callback used to join running generator threads on shutdown
-static void list_join_thread(void *key, unused void *value, unused void *arg)
+// enqueue block
+static void generate_block(MapBlock *block)
 {
-       pthread_join(*(pthread_t *) key, NULL);
+       if (server_map.cancel)
+               return;
+
+       pthread_mutex_lock(&server_map.num_blocks_mtx);
+       server_map.num_blocks++;
+       pthread_mutex_unlock(&server_map.num_blocks_mtx);
+
+       MapBlockExtraData *extra = block->extra;
+       extra->state = MBS_GENERATING;
+       queue_enqueue(server_map.mapgen_tasks, block);
 }
 
 // map callbacks
@@ -194,22 +196,6 @@ static void on_after_set_node(MapBlock *block, unused v3u8 offset, void *arg)
                send_block_to_near(block);
 }
 
-// join all map generation threads
-static void join_mapgen_threads()
-{
-       pthread_mutex_lock(&server_map.joining_threads_mtx);
-       server_map.joining_threads = true;
-       pthread_mutex_unlock(&server_map.joining_threads_mtx);
-
-       pthread_mutex_lock(&server_map.mapgen_threads_mtx);
-       list_clear_func(&server_map.mapgen_threads, &list_join_thread, NULL);
-       pthread_mutex_unlock(&server_map.mapgen_threads_mtx);
-
-       pthread_mutex_lock(&server_map.joining_threads_mtx);
-       server_map.joining_threads = false;
-       pthread_mutex_unlock(&server_map.joining_threads_mtx);
-}
-
 // generate a hut for new players to spawn in
 static void generate_spawn_hut()
 {
@@ -290,18 +276,30 @@ void server_map_init()
                .set_node = &on_set_node,
                .after_set_node = &on_after_set_node,
        });
-       server_map.joining_threads = false;
-       server_map.mapgen_threads = list_create(NULL);
-       pthread_mutex_init(&server_map.joining_threads_mtx, NULL);
-       pthread_mutex_init(&server_map.mapgen_threads_mtx, NULL);
+
+       server_map.cancel = false;
+       server_map.mapgen_tasks = queue_create();
+       server_map.mapgen_threads = malloc(sizeof *server_map.mapgen_threads * server_config.mapgen_threads);
+       server_map.num_blocks = 0;
+       pthread_mutex_init(&server_map.num_blocks_mtx, NULL);
+
+       for (unsigned int i = 0; i < server_config.mapgen_threads; i++)
+               pthread_create(&server_map.mapgen_threads[i], NULL, &mapgen_thread, NULL);
 }
 
 // ServerMap singleton destructor
 void server_map_deinit()
 {
-       join_mapgen_threads();
-       pthread_mutex_destroy(&server_map.joining_threads_mtx);
-       pthread_mutex_destroy(&server_map.mapgen_threads_mtx);
+       queue_finish(server_map.mapgen_tasks);
+       server_map.cancel = true;
+       queue_cancel(server_map.mapgen_tasks);
+
+       for (unsigned int i = 0; i < server_config.mapgen_threads; i++)
+               pthread_join(server_map.mapgen_threads[i], NULL);
+       free(server_map.mapgen_threads);
+
+       pthread_mutex_destroy(&server_map.num_blocks_mtx);
+       queue_delete(server_map.mapgen_tasks);
        map_delete(server_map.map);
 }
 
@@ -312,11 +310,11 @@ void server_map_requested_block(ServerPlayer *player, v3s32 pos)
                MapBlock *block = map_get_block(server_map.map, pos, true);
 
                pthread_mutex_lock(&block->mtx);
-               MapBlockExtraData *extra = block->extra;
 
+               MapBlockExtraData *extra = block->extra;
                switch (extra->state) {
                        case MBS_CREATED:
-                               launch_mapgen_thread(block);
+                               generate_block(block);
                                break;
 
                        case MBS_GENERATING:
@@ -325,47 +323,65 @@ void server_map_requested_block(ServerPlayer *player, v3s32 pos)
                        case MBS_READY:
                                send_block(player, block);
                };
+
                pthread_mutex_unlock(&block->mtx);
        }
 }
 
+static void update_percentage()
+{
+       static s32 total = 3 * 3 * 21;
+       static s32 done = -1;
+       static s32 last_percentage = -1;
+
+       if (done < total)
+               done++;
+
+       pthread_mutex_lock(&server_map.num_blocks_mtx);
+       s32 percentage = 100.0 * (done - server_map.num_blocks) / total;
+       pthread_mutex_unlock(&server_map.num_blocks_mtx);
+
+       if (percentage > last_percentage) {
+               last_percentage = percentage;
+               printf("Preparing spawn... %d%%\n", percentage);
+       }
+
+}
+
 // prepare spawn region
 void server_map_prepare_spawn()
 {
-       s32 done = 0;
-       s32 dist = server_config.simulation_distance;
-       s32 total = (dist * 2 + 1);
-       total *= total * total;
-       s32 last_percentage = -1;
-
-       for (s32 x = -dist; x <= (s32) dist; x++) {
-               for (s32 y = -dist; y <= (s32) dist; y++) {
-                       for (s32 z = -dist; z <= (s32) dist; z++) {
-                               if (interrupt->done) {
-                                       join_mapgen_threads();
+       update_percentage();
+
+       for (s32 x = -1; x <= (s32) 1; x++) {
+               for (s32 y = -10; y <= (s32) 10; y++) {
+                       for (s32 z = -1; z <= (s32) 1; z++) {
+                               if (interrupt->done)
                                        return;
-                               }
 
                                MapBlock *block = map_get_block(server_map.map, (v3s32) {x, y, z}, true);
 
                                pthread_mutex_lock(&block->mtx);
                                if (((MapBlockExtraData *) block->extra)->state == MBS_CREATED)
-                                       launch_mapgen_thread(block);
+                                       generate_block(block);
                                pthread_mutex_unlock(&block->mtx);
 
-                               done++;
-
-                               s32 percentage = 100.0 * done / total;
-
-                               if (percentage > last_percentage) {
-                                       last_percentage = percentage;
-                                       printf("Preparing spawn... %d%%\n", percentage);
-                               }
+                               update_percentage();
                        }
                }
        }
 
-       join_mapgen_threads();
+       while (true) {
+               pthread_mutex_lock(&server_map.num_blocks_mtx);
+               bool done = (server_map.num_blocks == 0);
+               pthread_mutex_unlock(&server_map.num_blocks_mtx);
+
+               if (done)
+                       break;
+
+               update_percentage();
+               sched_yield();
+       }
 
        s64 saved_spawn_height;
        if (database_load_meta("spawn_height", &saved_spawn_height)) {
index da7c2d4e96b0fe1d1e126b1ecca850d933717be5..68f3a3e044050448b213f1c8d6a18a4a563974b2 100644 (file)
@@ -1,8 +1,11 @@
 #ifndef _SERVER_MAP_H_
 #define _SERVER_MAP_H_
 
+#include <stdatomic.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <pthread.h>
+#include <dragonstd/queue.h>
 #include "map.h"
 #include "server/server_player.h"
 #include "types.h"
@@ -37,12 +40,13 @@ typedef struct
 } MapBlockExtraData;
 
 extern struct ServerMap {
-       Map *map;                            // map object, data is stored here
-       bool joining_threads;                // prevent threads from removing themselves from the thread list if thread list is being cleared anyway
-       pthread_mutex_t joining_threads_mtx; // mutex to protect joining threads
-       List mapgen_threads;                 // a list of mapgen threads (need to be joined before shutdown)
-       pthread_mutex_t mapgen_threads_mtx;  // mutex to protect mapgen thread list
-       s32 spawn_height;                    // height to spawn players at
+       atomic_bool cancel;             // remove the smooth
+       Map *map;                       // map object, data is stored here
+       Queue *mapgen_tasks;            // this is terry the fat shark
+       pthread_t *mapgen_threads;      // thread pool
+       s32 spawn_height;               // elevation to spawn players at
+       unsigned int num_blocks;        // number of enqueued / generating blocks
+       pthread_mutex_t num_blocks_mtx; // lock to protect the above
 } server_map; // ServerMap singleton
 
 void server_map_init();                                           // ServerMap singleton constructor