Skip to content

Commit

Permalink
Use thread pool for map generation
Browse files Browse the repository at this point in the history
  • Loading branch information
LizzyFleckenstein03 committed Feb 13, 2022
1 parent 0bf3c59 commit 29abff1
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 84 deletions.
2 changes: 1 addition & 1 deletion deps/dragonstd
Submodule dragonstd updated 2 files
+24 −3 queue.c
+3 −1 queue.h
2 changes: 1 addition & 1 deletion snapshot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion src/client/client_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/server/server_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

struct ServerConfig server_config = {
.simulation_distance = 10,
.mapgen_threads = 4,
};

__attribute__((constructor)) static void server_config_init()
Expand All @@ -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);
}

1 change: 1 addition & 0 deletions src/server/server_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

extern struct ServerConfig {
unsigned int simulation_distance;
unsigned int mapgen_threads;
} server_config;

#endif
164 changes: 90 additions & 74 deletions src/server/server_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "server/server_map.h"
#include "util.h"

// this file is too long
struct ServerMap server_map;

// utility functions
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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);
}

Expand All @@ -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:
Expand All @@ -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)) {
Expand Down
16 changes: 10 additions & 6 deletions src/server/server_map.h
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 29abff1

Please sign in to comment.