From a532d5b03d64a0101048cfef5b0c1f15a4219400 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Mon, 16 Jun 2025 01:20:11 +0200 Subject: [PATCH] Make this bih multithreaded --- build.c | 6 ++-- main.c | 72 ++++++++++++++++++++++++++++++++++++------- routes.c | 93 ++++++++++++++++++++++++++++++++++++++++++-------------- routes.h | 32 +++++++++++++++---- 4 files changed, 162 insertions(+), 41 deletions(-) diff --git a/build.c b/build.c index 7d4dc9b..8a00c95 100644 --- a/build.c +++ b/build.c @@ -40,12 +40,14 @@ int main(int argc, char ** argv) CMD("cc", "-fPIC", "-ggdb", "-I.", "-DDEBUG=1", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX", "-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE", "-o", "./aboba", "./main.c", "./routes.c", "./baked.c", "./mongoose.o", "./cJSON/cJSON.c", - "./md5-c/md5.c"); + "./md5-c/md5.c", + "-lpthread"); #else CMD("cc", "-fPIC", "-I.", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX", "-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE", "-o", "./aboba", "./main.c", "./routes.c", "./baked.c", "./mongoose.o", "./cJSON/cJSON.c", - "./md5-c/md5.c"); + "./md5-c/md5.c", + "-lpthread"); #endif } } else if (strcmp(cmd, "clean") == 0) { diff --git a/main.c b/main.c index 0c6b77a..fc28730 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,5 @@ #include +#include #define GEBS_IMPLEMENTATION #include "gebs/gebs.h" @@ -9,24 +10,72 @@ #include "routes.h" #include "baked.h" -typedef void (*Route_Handler)(struct mg_connection *conn, struct mg_http_message *msg); - -typedef struct { - char *key; // path - Route_Handler value; -} Route; - Route *route_hashtable = NULL; +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); +} + +void *route_thread_function(void *param) +{ + Route_Thread_Data *data = (Route_Thread_Data *)param; + + 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; + mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result)); + return nil; + } + + char key[MG_PATH_MAX] = {0}; + strncpy(key, http_msg.uri.buf, http_msg.uri.len); + Route_Handler handler = shget(route_hashtable, key); + + Route_Result result = {0}; + handler(&http_msg, &result); + mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result)); + + free(data->message.buf); + free(data); + + return nil; +} + void event_handler(struct mg_connection *conn, int ev, void *ev_data) { if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *msg = (struct mg_http_message *)ev_data; - char key[MG_PATH_MAX] = {0}; - strncpy(key, msg->uri.buf, msg->uri.len); - Route_Handler handler = shget(route_hashtable, key); - handler(conn, msg); + Route_Thread_Data *data = calloc(1, sizeof(*data)); + data->message = mg_strdup(msg->message); + data->conn_id = conn->id; + data->mgr = conn->mgr; + 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; + defer { + list_free(&result->headers); + sb_free(&result->body); + } + + Gebs_String_Builder sb = {0}; + defer { sb_free(&sb); } + nsl_join(&result->headers, &sb, "\r\n"); + if (result->headers.count > 0) { + sb_append_nstr(&sb, "\r\n"); + } + sb_finish(&sb); + + mg_http_reply(conn, result->status_code, sb.items, "%s", result->body.items); } } @@ -50,6 +99,7 @@ int main(int argc, char ** argv) mg_mgr_init(&mgr); init_route_hashtable(); + mg_wakeup_init(&mgr); mg_http_listen(&mgr, "http://localhost:8080", &event_handler, NULL); for (;;) { diff --git a/routes.c b/routes.c index 2c90a55..4995d93 100644 --- a/routes.c +++ b/routes.c @@ -31,7 +31,7 @@ bool gpp_run(char *path, NString_List *env, String_Builder *out) return cmd_run_collect(&cmd, out) == 0; } -void route_build_id(struct mg_connection *conn, struct mg_http_message *msg) +void route_build_id(struct mg_http_message *msg, Route_Result *result) { cJSON *root = cJSON_CreateObject(); defer { cJSON_Delete(root); } @@ -53,10 +53,13 @@ void route_build_id(struct mg_connection *conn, struct mg_http_message *msg) char *root_text = cJSON_PrintUnformatted(root); defer { free(root_text); } - mg_http_reply(conn, 200, "Content-Type: application/json\r\n", root_text); + result->status_code = 200; + list_append(&result->headers, "Content-Type: application/json"); + sb_append_nstr(&result->body, root_text); + sb_finish(&result->body); } -void route_page_not_found(struct mg_connection *conn, struct mg_http_message *msg) +void route_page_not_found(struct mg_http_message *msg, Route_Result *result) { NString_List env = {0}; defer { list_free(&env); } @@ -68,7 +71,10 @@ void route_page_not_found(struct mg_connection *conn, struct mg_http_message *ms char path[PATH_MAX] = {0}; if (!get_baked_resource_path("page-missing.t", path, sizeof(path))) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } @@ -82,70 +88,104 @@ void route_page_not_found(struct mg_connection *conn, struct mg_http_message *ms sb_finish(&out); if (!ok) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); } else { - mg_http_reply(conn, 404, "Content-Type: text/html\r\n", out.items); + result->status_code = 200; + list_append(&result->headers, "Content-Type: text/html"); + sb_append_nstr(&result->body, out.items); + sb_finish(&result->body); } } -void route_simple_css(struct mg_connection *conn, struct mg_http_message *msg) +void route_simple_css(struct mg_http_message *msg, Route_Result *result) { char path[PATH_MAX] = {0}; if (!get_baked_resource_path("simple.min.css", path, sizeof(path))) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } String_Builder sb = {0}; defer { sb_free(&sb); } if (!sb_read_file(&sb, path)) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } sb_finish(&sb); - mg_http_reply(conn, 200, "Content-Type: text/css\r\n", "%s", sb.items); + result->status_code = 200; + list_append(&result->headers, "Content-Type: text/css"); + sb_append_nstr(&result->body, sb.items); + sb_finish(&result->body); } -void route_favicon(struct mg_connection *conn, struct mg_http_message *msg) +void route_favicon(struct mg_http_message *msg, Route_Result *result) { char path[PATH_MAX] = {0}; if (!get_baked_resource_path("favicon.ico", path, sizeof(path))) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } String_Builder sb = {0}; defer { sb_free(&sb); } if (!sb_read_file(&sb, path)) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } sb_finish(&sb); - mg_http_reply(conn, 200, "Content-Type: image/x-icon\r\n", "%s", sb.items); + result->status_code = 200; + list_append(&result->headers, "Content-Type: image/x-icon"); + sb_append_nstr(&result->body, sb.items); + sb_finish(&result->body); } -void route_hotreload_js(struct mg_connection *conn, struct mg_http_message *msg) +void route_hotreload_js(struct mg_http_message *msg, Route_Result *result) { char path[PATH_MAX] = {0}; if (!get_baked_resource_path("hotreload.js", path, sizeof(path))) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } String_Builder sb = {0}; defer { sb_free(&sb); } if (!sb_read_file(&sb, path)) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } sb_finish(&sb); - mg_http_reply(conn, 200, "Content-Type: text/javascript\r\n", "%s", sb.items); + + result->status_code = 200; + list_append(&result->headers, "Content-Type: text/javascript"); + sb_append_nstr(&result->body, sb.items); + sb_finish(&result->body); } -void route_home(struct mg_connection *conn, struct mg_http_message *msg) +void route_home(struct mg_http_message *msg, Route_Result *result) { NString_List env = {0}; defer { list_free(&env); } @@ -155,7 +195,10 @@ void route_home(struct mg_connection *conn, struct mg_http_message *msg) char path[PATH_MAX] = {0}; if (!get_baked_resource_path("home.t", path, sizeof(path))) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); return; } @@ -169,8 +212,14 @@ void route_home(struct mg_connection *conn, struct mg_http_message *msg) sb_finish(&out); if (!ok) { - mg_http_reply(conn, 500, "Content-Type: text/plain\r\n", INTERNAL_SERVER_ERROR_MSG); + result->status_code = 500; + list_append(&result->headers, "Content-Type: text/plain"); + sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG); + sb_finish(&result->body); } else { - mg_http_reply(conn, 200, "Content-Type: text/html\r\n", out.items); + result->status_code = 200; + list_append(&result->headers, "Content-Type: text/html"); + sb_append_nstr(&result->body, out.items); + sb_finish(&result->body); } } diff --git a/routes.h b/routes.h index 41bda17..591a6c2 100644 --- a/routes.h +++ b/routes.h @@ -1,13 +1,33 @@ #ifndef ROUTES_H_ #define ROUTES_H_ +#include "gebs/gebs.h" #include "mongoose/mongoose.h" -void route_page_not_found(struct mg_connection *conn, struct mg_http_message *msg); -void route_simple_css(struct mg_connection *conn, struct mg_http_message *msg); -void route_favicon(struct mg_connection *conn, struct mg_http_message *msg); -void route_hotreload_js(struct mg_connection *conn, struct mg_http_message *msg); -void route_home(struct mg_connection *conn, struct mg_http_message *msg); -void route_build_id(struct mg_connection *conn, struct mg_http_message *msg); +typedef struct { + int status_code; + NString_List headers; + String_Builder body; +} Route_Result; + +typedef struct { + struct mg_mgr *mgr; + ulong conn_id; + struct mg_str message; +} Route_Thread_Data; + +typedef void (*Route_Handler)(struct mg_http_message *msg, Route_Result *result); + +typedef struct { + char *key; // path + Route_Handler value; +} Route; + +void route_page_not_found(struct mg_http_message *msg, Route_Result *result); +void route_simple_css(struct mg_http_message *msg, Route_Result *result); +void route_favicon(struct mg_http_message *msg, Route_Result *result); +void route_hotreload_js(struct mg_http_message *msg, Route_Result *result); +void route_home(struct mg_http_message *msg, Route_Result *result); +void route_build_id(struct mg_http_message *msg, Route_Result *result); #endif // ROUTES_H_