Fix leaks, curious case of gebs blog post

This commit is contained in:
kamkow1
2025-06-18 10:38:26 +02:00
parent e9a95c2c54
commit ed1d61d976
6 changed files with 78 additions and 3 deletions

View File

@ -19,6 +19,7 @@ INCBIN(hotreload_js, "./etc/hotreload.js");
INCBIN(blog_welcome_md, "./blog/welcome.md"); INCBIN(blog_welcome_md, "./blog/welcome.md");
INCBIN(blog_weird_page_md, "./blog/weird-page.md"); INCBIN(blog_weird_page_md, "./blog/weird-page.md");
INCBIN(blog_curious_case_of_gebs_md, "./blog/curious-case-of-gebs.md");
Baked_Resource *baked_resources = NULL; Baked_Resource *baked_resources = NULL;
@ -45,6 +46,7 @@ void init_baked_resources(void)
add_baked_resource("hotreload.js", hotreload_js_data, hotreload_js_size); add_baked_resource("hotreload.js", hotreload_js_data, hotreload_js_size);
add_baked_resource("blog-welcome.md", blog_welcome_md_data, blog_welcome_md_size); add_baked_resource("blog-welcome.md", blog_welcome_md_data, blog_welcome_md_size);
add_baked_resource("blog-weird-page.md", blog_weird_page_md_data, blog_weird_page_md_size); add_baked_resource("blog-weird-page.md", blog_weird_page_md_data, blog_weird_page_md_size);
add_baked_resource("blog-curious-case-of-gebs.md", blog_curious_case_of_gebs_md_data, blog_curious_case_of_gebs_md_size);
} }
void free_baked_resources(void) void free_baked_resources(void)

View File

@ -16,6 +16,7 @@ INCBIN_EXTERN(hotreload_js);
INCBIN_EXTERN(blog_welcome_md); INCBIN_EXTERN(blog_welcome_md);
INCBIN_EXTERN(blog_weird_page_md); INCBIN_EXTERN(blog_weird_page_md);
INCBIN_EXTERN(blog_curious_case_of_gebs_md);
typedef struct { typedef struct {
char *key; // path char *key; // path

View File

@ -0,0 +1,60 @@
# GEBS - the Good Enough Build System
GEBS is a reiteration of my previous build system "MIBS" (or MIni Build System). It takes some inspiration from
[Tsoding's](https://twitch.tv/tsoding) [nobuild](https://github.com/tsoding/nobuild) and later on [nob.h](https://github.com/tsoding/nob.h).
The key difference is the way GEBS is implemented on the inside, which makes it more powerful and extensible than nob.h.
GEBS also includes a bunch of extra helper macros, which turn C into a language more akin to Go or Zig, but more on that later.
## So what makes GEBS different?
### Allocators
So one thing I've noticed is that nob.h is used alongside of [arena](https://github.com/tsoding/arena). If you look into the implementation
you can see some things, which are somewhat redundant like \`arena_sprintf()\` or \`arena_da_append()\`, \`arena_sb_append_cstr()\` and so on...
First of all, why is an arena library managing string builders and dynamic arrays? In my opinion it should be the other way around.
A string builder should rather accept a generic allocator interface, which it can then utilize to get it's memory. In GEBS this is done
via a \`Gebs_Allocator\` interface.
\`\`\`c
typedef struct {
void *(*malloc)(void *self, size_t size);
void (*free)(void *self, void *memory);
void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size);
} Gebs_Allocator;
// Wrapper macros
#define gebs_malloc(alloc, size) ((alloc)->malloc((void *)(alloc), (size)))
#define gebs_free(alloc, memory) ((alloc)->free((void *)(alloc), (memory)))
#define gebs_realloc(alloc, memory, prev_size, new_size) \
((alloc)->realloc((void *)(alloc), (memory), (prev_size), (new_size)))
\`\`\`
We then can implement an allocator that conforms to this interface and it will work with any dynamic structure.
This is my version of the \`XXX_da_append()\` macro:
\`\`\`c
#define gebs_list_append_alloc(alloc, list, item) \\
do { \\
if ((list)->items == nil) { \\
(list)->capacity = 1; \\
(list)->items = gebs_malloc((alloc), \\
sizeof(*(list)->items) * (list)->capacity); \\
} else { \\
if ((list)->count == (list)->capacity) { \\
size_t __prev_capacity = (list)->capacity; \\
(list)->capacity *= 2; \\
(list)->items = gebs_realloc((alloc), (list)->items, \\
sizeof(*(list)->items) * __prev_capacity, \\
sizeof(*(list)->items) * (list)->capacity); \\
} \\
} \\
(list)->items[(list)->count++] = (item); \\
} while(0)
#define gebs_list_append(list, item) \\
gebs_list_append_alloc(&gebs_default_allocator, (list), (item))
\`\`\`
This way a dynamic list can work with any kind of allocator - the default libc allocator, an arena or literally anything else.
We're not tied to the libc allocator and then have to implement the same macro of all other allocators.

View File

@ -36,7 +36,8 @@ int main(int argc, char ** argv)
"./etc/simple.min.css", "./etc/simple.min.css",
"./blog/welcome.md", "./blog/welcome.md",
"./blog/weird-page.md" "./blog/weird-page.md",
"./blog/curious-case-of-gebs.md"
) { ) {
RULE("./mongoose.o", "./mongoose/mongoose.c") { RULE("./mongoose.o", "./mongoose/mongoose.c") {

2
gebs

Submodule gebs updated: c3be4ce8ee...6db36114d5

13
main.c
View File

@ -108,6 +108,17 @@ void init_route_hashtable(void)
baked_resource_each(&put_blogs); baked_resource_each(&put_blogs);
} }
void free_route_hashtable(void)
{
for (size_t i = 0; i < shlen(route_hashtable); i++) {
if (strlen(route_hashtable[i].key) >= strlen("blog-")
&& strncmp(route_hashtable[i].key, "blog-", strlen("blog-")) == 0) {
free(route_hashtable[i].key);
}
}
shfree(route_hashtable);
}
int main(int argc, char ** argv) int main(int argc, char ** argv)
{ {
start_timer(); start_timer();
@ -118,6 +129,7 @@ int main(int argc, char ** argv)
struct mg_mgr mgr; struct mg_mgr mgr;
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
init_route_hashtable(); init_route_hashtable();
defer { free_route_hashtable(); }
mg_wakeup_init(&mgr); mg_wakeup_init(&mgr);
mg_http_listen(&mgr, "http://localhost:8080", &event_handler, NULL); mg_http_listen(&mgr, "http://localhost:8080", &event_handler, NULL);
@ -128,7 +140,6 @@ int main(int argc, char ** argv)
} }
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
shfree(route_hashtable);
free_baked_resources(); free_baked_resources();