Rework memory management, use per-thread arenas
This commit is contained in:
149
main.c
149
main.c
@ -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();
|
||||
|
Reference in New Issue
Block a user