Rework memory management, use per-thread arenas

This commit is contained in:
kamkow1
2025-06-28 01:29:49 +02:00
parent 2badc915d6
commit 2988a5b3d6
9 changed files with 202 additions and 195 deletions

149
main.c
View File

@ -9,23 +9,39 @@
#include "mongoose/mongoose.h"
#define STB_DS_IMPLEMENTATION
#include "stb/stb_ds.h"
#include "md5-c/md5.h"
#include "routes.h"
#include "baked.h"
#include "timer.h"
#include "CONFIG.h"
#include "clonestr.h"
#include "locked.h"
static locked(Route *) route_hashtable = locked_init(nil);
static locked(char *) baked_dump_path = locked_init(nil);
char *clonestr_alloc(Allocator *alloc, char *s)
{
char *p = gebs_malloc(alloc, strlen(s)+1);
strcpy(p, s);
return p;
}
void *zmalloc_alloc(Allocator *alloc, size_t size)
{
void *p = gebs_malloc(alloc, size);
memset(p, 0, size);
return p;
}
void run_in_thread(void *(*f)(void *), void *p)
{
pthread_t tid = 0;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, f, p);
pthread_attr_destroy(&attr);
}
@ -33,60 +49,61 @@ void run_in_thread(void *(*f)(void *), void *p)
void *route_thread_function(void *param)
{
Route_Thread_Data *data = (Route_Thread_Data *)param;
Arena *arena = data->arena;
struct mg_http_message http_msg = {0};
int r = mg_http_parse(data->message.buf, data->message.len, &http_msg);
if (r <= 0) {
Route_Result result = {0};
result.status_code = 400;
result.type = ROUTE_RESULT_DYNAMIC;
/* list_append(&result.headers, clonestr("Content-Type: text/plain")); */
sb_append_nstr(&result.body, "Could not parse HTTP request");
sb_finish(&result.body);
Route_Result *result = zmalloc_alloc((Allocator *)arena, sizeof(*result));
result->arena = arena;
result->status_code = 400;
result->type = ROUTE_RESULT_DYNAMIC;
sb_append_nstr_alloc(arena, &result->body, "Could not parse HTTP request");
sb_finish_alloc(arena, &result->body);
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
free(data->message.buf);
free(data);
return nil;
pthread_exit(nil);
} else {
if (mg_match(http_msg.uri, mg_str("/bakedres/*"), nil)) {
Route_Result *result = zmalloc_alloc((Allocator *)arena, sizeof(*result));
result->arena = arena;
result->type = ROUTE_RESULT_STATIC;
char *p = gebs_malloc(arena, http_msg.uri.len+1);
strncpy(p, http_msg.uri.buf, http_msg.uri.len);
p[http_msg.uri.len] = 0;
char *file = basename(p);
char *full_path = gebs_malloc(arena, PATH_MAX);
lockx(&baked_dump_path);
snprintf(full_path, PATH_MAX, "%s/%s", baked_dump_path.value, file);
unlockx(&baked_dump_path);
sb_append_nstr_alloc(arena, &result->body, full_path);
sb_finish_alloc(arena, &result->body);
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
free(data->message.buf);
free(data);
pthread_exit(nil);
} else {
char key[MG_PATH_MAX] = {0};
strncpy(key, http_msg.uri.buf, http_msg.uri.len);
lockx(&route_hashtable);
ssize_t idx = shgeti(route_hashtable.value, key);
Route_Result *result = zmalloc_alloc((Allocator *)arena, sizeof(*result));
result->arena = arena;
route_hashtable.value[idx].value((Allocator *)arena, &http_msg, result, route_hashtable.value[idx].context_data);
unlockx(&route_hashtable);
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
free(data->message.buf);
free(data);
pthread_exit(nil);
}
}
if (mg_match(http_msg.uri, mg_str("/bakedres/*"), nil)) {
Route_Result result = {0};
result.type = ROUTE_RESULT_STATIC;
char *p = malloc(http_msg.uri.len+1);
strncpy(p, http_msg.uri.buf, http_msg.uri.len);
p[http_msg.uri.len] = 0;
char *file = basename(p);
char *full_path = malloc(PATH_MAX);
lockx(&baked_dump_path);
snprintf(full_path, PATH_MAX, "%s/%s", baked_dump_path.value, file);
unlockx(&baked_dump_path);
sb_append_nstr(&result.body, full_path);
sb_finish(&result.body);
free(full_path);
free(p);
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
free(data->message.buf);
free(data);
return nil;
}
char key[MG_PATH_MAX] = {0};
strncpy(key, http_msg.uri.buf, http_msg.uri.len);
lockx(&route_hashtable);
ssize_t idx = shgeti(route_hashtable.value, key);
Route_Result result = {0};
route_hashtable.value[idx].value(&http_msg, &result, route_hashtable.value[idx].context_data);
unlockx(&route_hashtable);
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
free(data->message.buf);
free(data);
return nil;
}
@ -99,18 +116,20 @@ void event_handler(struct mg_connection *conn, int ev, void *ev_data)
data->message = mg_strdup(msg->message);
data->conn_id = conn->id;
data->mgr = conn->mgr;
data->arena = malloc(sizeof(*data->arena));
*data->arena = arena_get();
run_in_thread(&route_thread_function, data);
} else if (ev == MG_EV_WAKEUP) {
struct mg_str *data = (struct mg_str *)ev_data;
Route_Result *result = (Route_Result *)data->buf;
Route_Result *result = *(Route_Result **)data->buf;
Arena *arena = result->arena;
Gebs_String_Builder sb = {0};
defer { sb_free(&sb); }
nsl_join(&result->headers, &sb, "\r\n");
nsl_join_alloc(arena, &result->headers, &sb, "\r\n");
if (result->headers.count > 0) {
sb_append_nstr(&sb, "\r\n");
sb_append_nstr_alloc(arena, &sb, "\r\n");
}
sb_finish(&sb);
sb_finish_alloc(arena, &sb);
if (result->type == ROUTE_RESULT_DYNAMIC) {
mg_http_reply(conn, result->status_code, sb.items, "%s", result->body.items);
@ -119,11 +138,8 @@ void event_handler(struct mg_connection *conn, int ev, void *ev_data)
mg_http_serve_file(conn, ev_data, path, &(struct mg_http_serve_opts){0});
}
for (size_t i = 0; i < result->headers.count; i++) {
free(result->headers.items[i]);
}
list_free(&result->headers);
sb_free(&result->body);
arena_destroy(arena);
free(arena);
}
}
@ -143,11 +159,11 @@ void init_route_hashtable(void)
{
lockx(&route_hashtable);
shdefault(route_hashtable.value, &route_page_not_found);
shput(route_hashtable.value, clonestr("/"), &route_home);
shput(route_hashtable.value, clonestr("/page-missing"), &route_page_not_found);
shput(route_hashtable.value, clonestr("/blog"), &route_blog);
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/"), &route_home);
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/page-missing"), &route_page_not_found);
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/blog"), &route_blog);
#if MY_DEBUG
shput(route_hashtable.value, clonestr("/build-id"), &route_build_id);
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/build-id"), &route_build_id);
#endif
baked_resource_each(&route_hashtable_put_blogs, nil);
@ -250,13 +266,18 @@ void populate_baked_dump(char *baked_dump)
unlock_baked_resources();
}
volatile bool alive = true;
volatile sig_atomic_t alive = true;
void graceful_shutdown(int no) { alive = false; }
int main(int argc, char ** argv)
{
signal(SIGINT, &graceful_shutdown);
struct sigaction sa;
sa.sa_handler = &graceful_shutdown;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, nil);
start_timer();
init_baked_resources();