From 9c234846f4c83573f548fceca9152957f4d11ebe Mon Sep 17 00:00:00 2001 From: John Sanpe Date: Thu, 24 Apr 2025 04:14:42 +0800 Subject: [PATCH 1/4] feat guards: added class macros Signed-off-by: John Sanpe --- examples/guards/cleanup.c | 16 ++++++------- include/bfdev/guards.h | 49 ++++++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/examples/guards/cleanup.c b/examples/guards/cleanup.c index 463ccfcb..fc3491c3 100644 --- a/examples/guards/cleanup.c +++ b/examples/guards/cleanup.c @@ -7,7 +7,7 @@ #include #include -BFDEV_CLEAN_TEMPLATE(malloc, void *, +BFDEV_DEFINE_CLEAN(malloc, void *, if (_T) { printf("cleanup %p\n", _T); free(_T); @@ -15,19 +15,19 @@ BFDEV_CLEAN_TEMPLATE(malloc, void *, ) static void -test_gc_cleanup(void) +test_clean_gc(void) { - bfdev_clean(malloc) void *block; + BFDEV_CLEAN(malloc) void *block; block = malloc(8); (void)block; } static void * -test_gc_lasting(void) +test_clean_keep(void) { - bfdev_clean(malloc) void *block; + BFDEV_CLEAN(malloc) void *block; block = malloc(8); - bfdev_clean_return(block); + bfdev_return(block); } int @@ -35,8 +35,8 @@ main(int argc, const char *argv[]) { void *block; - test_gc_cleanup(); - block = test_gc_lasting(); + test_clean_gc(); + block = test_clean_keep(); free(block); return 0; diff --git a/include/bfdev/guards.h b/include/bfdev/guards.h index c79a186a..eb8e7c8d 100644 --- a/include/bfdev/guards.h +++ b/include/bfdev/guards.h @@ -12,7 +12,18 @@ BFDEV_BEGIN_DECLS -#define BFDEV_CLEAN_TEMPLATE(name, type, free) \ +/** + * Guards: + * + * The "goto error" pattern is notorious for introducing subtle resource + * leaks. It is tedious and error prone to add new resource acquisition + * constraints into code paths that already have several unwind + * conditions. The "cleanup" helpers enable the compiler to help with + * this tedium and can aid in maintaining LIFO (last in first out) + * unwind ordering to avoid unintentional leaks. + */ + +#define BFDEV_DEFINE_CLEAN(name, type, free) \ static inline void \ __bfdev_cleanup_##name(void *object) \ { \ @@ -20,16 +31,36 @@ __bfdev_cleanup_##name(void *object) \ free; \ } -#define bfdev_clean_lasting(object) ({ \ - __auto_type __ptr = (object); \ - (object) = BFDEV_NULL; __ptr; \ -}) - -#define bfdev_clean(name) \ +#define BFDEV_CLEAN(name) \ __bfdev_cleanup(__bfdev_cleanup_##name) -#define bfdev_clean_return(object) \ - return bfdev_clean_lasting(object) +#define BFDEV_DEFINE_CLASS(name, type, ctor, dtor, args...) \ +typedef type __bfdev_class_##name##_t; \ +static inline type \ +__bfdev_class_##name##_constructor(args) \ +{ \ + type __tmp = ctor; \ + return __tmp; \ +} \ +static inline void \ +__bfdev_class_##name##_destructor(type *p) \ +{ \ + type _T = *p; \ + dtor; \ +} + +#define BFDEV_CLASS(name, var) \ + __bfdev_class_##name##_t var \ + __bfdev_cleanup(__bfdev_class_##name##_destructor) = \ + __bfdev_class_##name##_constructor + +#define bfdev_lasting(object) ({ \ + __auto_type __ptr = (object); \ + (object) = BFDEV_NULL; __ptr; \ +}) + +#define bfdev_return(object) \ + return bfdev_lasting(object) BFDEV_END_DECLS From 79d75a6c2f09dc724d404c79a1d9df4631c35231 Mon Sep 17 00:00:00 2001 From: John Sanpe Date: Thu, 24 Apr 2025 04:15:09 +0800 Subject: [PATCH 2/4] feat guards: added class exmaple Signed-off-by: John Sanpe --- examples/guards/CMakeLists.txt | 6 ++++++ examples/guards/class.c | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 examples/guards/class.c diff --git a/examples/guards/CMakeLists.txt b/examples/guards/CMakeLists.txt index e3da55f9..6f7e1172 100644 --- a/examples/guards/CMakeLists.txt +++ b/examples/guards/CMakeLists.txt @@ -7,15 +7,21 @@ add_executable(guards-cleanup cleanup.c) target_link_libraries(guards-cleanup bfdev) add_test(guards-cleanup guards-cleanup) +add_executable(guards-class class.c) +target_link_libraries(guards-class bfdev) +add_test(guards-class guards-class) + if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") install(FILES cleanup.c + class.c DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples/guards ) install(TARGETS guards-cleanup + guards-class DESTINATION ${CMAKE_INSTALL_DOCDIR}/bin ) diff --git a/examples/guards/class.c b/examples/guards/class.c new file mode 100644 index 00000000..0612092d --- /dev/null +++ b/examples/guards/class.c @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2025 John Sanpe + */ + +#include +#include +#include +#include + +static const char * +test_ctor(void) +{ + return strdup("helloworld"); +} + +static void +test_dtor(const char *obj) +{ + free((void *)obj); +} + +BFDEV_DEFINE_CLASS(test, const char *, + test_ctor(), + test_dtor(_T) +) + +int +main(int argc, const char *argv[]) +{ + BFDEV_CLASS(test, str)(); + + if (!str) + return 1; + printf("%s\n", str); + + return 0; +} From 635f089fe3e99a67b078f5e517212db977bc8fa4 Mon Sep 17 00:00:00 2001 From: John Sanpe Date: Thu, 24 Apr 2025 04:15:31 +0800 Subject: [PATCH 3/4] feat allocator: added clean template Signed-off-by: John Sanpe --- include/bfdev/allocator.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/bfdev/allocator.h b/include/bfdev/allocator.h index 41ce3dd9..02a86205 100644 --- a/include/bfdev/allocator.h +++ b/include/bfdev/allocator.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include BFDEV_BEGIN_DECLS @@ -125,6 +127,11 @@ bfdev_realloc_array(const bfdev_alloc_t *alloc, return bfdev_realloc(alloc, block, size * nr); } +BFDEV_DEFINE_CLEAN(bfdev_free, void *, + if (!BFDEV_IS_INVAL(_T)) + bfdev_free(BFDEV_NULL, _T); +) + BFDEV_END_DECLS #endif /* _BFDEV_ALLOCATOR_H_ */ From e3f837c188798d02cf1255797ee5acf2e5ebd72d Mon Sep 17 00:00:00 2001 From: John Sanpe Date: Thu, 24 Apr 2025 04:46:28 +0800 Subject: [PATCH 4/4] feat array: added class template Signed-off-by: John Sanpe --- examples/array/simple.c | 8 ++------ include/bfdev/array.h | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/examples/array/simple.c b/examples/array/simple.c index 630ec9c2..2eb59596 100644 --- a/examples/array/simple.c +++ b/examples/array/simple.c @@ -14,17 +14,15 @@ int main(int argc, const char *argv[]) { - BFDEV_DEFINE_ARRAY(array, NULL, TEST_SIZE); + BFDEV_CLASS(bfdev_array, array)(NULL, TEST_SIZE); unsigned int count; - bfdev_array_append(&array, 0, 0); - for (count = 0; count < TEST_LOOP; ++count) { unsigned int num; void *buff; num = rand() % TEST_SIZE; - buff = bfdev_array_push(&array, num); + buff = bfdev_array_push(array, num); if (!buff) return 1; @@ -32,7 +30,5 @@ main(int argc, const char *argv[]) printf("array bfdev_array_push test: %02u: %u\n", count, num); } - bfdev_array_release(&array); - return 0; } diff --git a/include/bfdev/array.h b/include/bfdev/array.h index 960d1a2f..38d74f55 100644 --- a/include/bfdev/array.h +++ b/include/bfdev/array.h @@ -12,6 +12,7 @@ #include #include #include +#include BFDEV_BEGIN_DECLS @@ -207,6 +208,32 @@ bfdev_array_reserve(bfdev_array_t *array, unsigned long num); extern void bfdev_array_release(bfdev_array_t *array); +static inline bfdev_array_t * +bfdev_array_create(const bfdev_alloc_t *alloc, bfdev_size_t cells) +{ + bfdev_array_t *obj; + + obj = bfdev_malloc(alloc, sizeof(*obj)); + if (bfdev_unlikely(!obj)) + return BFDEV_NULL; + bfdev_array_init(obj, alloc, cells); + + return obj; +} + +static inline void +bfdev_array_destroy(bfdev_array_t *obj) +{ + bfdev_array_release(obj); + bfdev_free(obj->alloc, obj); +} + +BFDEV_DEFINE_CLASS(bfdev_array, bfdev_array_t *, + bfdev_array_create(alloc, cells), + bfdev_array_destroy(_T), + const bfdev_alloc_t *alloc, bfdev_size_t cells +) + BFDEV_END_DECLS #endif /* _BFDEV_ARRAY_H_ */