From a033f2783a4587239dc1aa5c4b24163f928770e3 Mon Sep 17 00:00:00 2001 From: Lawrence Stubbs Date: Fri, 29 Nov 2024 19:16:36 -0500 Subject: [PATCH] various bug fixes, corrections, update dependency - `thrd_for` example now execute as expected --- CMakeLists.txt | 4 ++-- README.md | 4 ++-- docs/index.md | 4 ++-- examples/thrd_for.c | 11 ++++----- include/raii.h | 26 ++++++++-------------- src/except.c | 1 + src/future.c | 54 +++++++++++++++++++++++++++++++++------------ src/raii.c | 28 ++++++++++++++++++----- 8 files changed, 85 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 088f63d..3c1020b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,8 +65,8 @@ else() endif() FetchContent_Declare(threads - URL https://github.com/zelang-dev/cthread/archive/refs/tags/v4.1.0.0.zip - URL_MD5 b94418e2efd06782e7ddf81a7c1a7e40 + URL https://github.com/zelang-dev/cthread/archive/refs/tags/v4.1.0.1.zip + URL_MD5 5392e7fac2638e1e54e5920ebf289096 ) FetchContent_MakeAvailable(threads) diff --git a/README.md b/README.md index ad4a3fb..2561b3d 100644 --- a/README.md +++ b/README.md @@ -318,8 +318,8 @@ C_API uintptr_t thrd_self(void); C_API raii_values_t *thrd_value(uintptr_t value); C_API future_t *thrd_for(thrd_func_t fn, size_t times, const char *desc, ...); -C_API thrd_values *thrd_sync(future_t *); -C_API values_type thrd_then(result_func_t callback, thrd_values *iter, void_t result); +C_API thrd_values_t *thrd_sync(future_t *); +C_API values_type thrd_then(result_func_t callback, thrd_values_t *iter, void_t result); C_API bool thrd_is_finish(future_t *); C_API future_t thrd_add(future_t *, thrd_func_t routine, const char *desc, ...); C_API void thrd_destroy(future_t *); diff --git a/docs/index.md b/docs/index.md index 4c0301a..08f14ba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -313,8 +313,8 @@ C_API uintptr_t thrd_self(void); C_API raii_values_t *thrd_value(uintptr_t value); C_API future_t *thrd_for(thrd_func_t fn, size_t times, const char *desc, ...); -C_API thrd_values *thrd_sync(future_t *); -C_API values_type thrd_then(result_func_t callback, thrd_values *iter, void_t result); +C_API thrd_values_t *thrd_sync(future_t *); +C_API values_type thrd_then(result_func_t callback, thrd_values_t *iter, void_t result); C_API bool thrd_is_finish(future_t *); C_API future_t thrd_add(future_t *, thrd_func_t routine, const char *desc, ...); C_API void thrd_destroy(future_t *); diff --git a/examples/thrd_for.c b/examples/thrd_for.c index 532ee2c..d15e720 100644 --- a/examples/thrd_for.c +++ b/examples/thrd_for.c @@ -2,7 +2,7 @@ void *is_prime(args_t arg) { int i, x = get_args(arg, 0).integer; - printf("\nThread #%zx, received: %d\n", thrd_self(), x); + printf("Thread #%zx, received: %d\n", thrd_self(), x); for (i = 2; i < x; ++i) if (x % i == 0) return thrd_value(false); return thrd_value(true); @@ -10,11 +10,11 @@ void *is_prime(args_t arg) { void_t check_primes(void_t result, size_t id, values_type iter) { if (iter.boolean) - printf("Number %zu is prime.\n", id); + printf("Thread %zu: is prime.\n", id); else - printf("Number %zu is not prime.\n", id); + printf("Thread %zu: is not prime.\n", id); - return iter.object; + return 0; } int main(int argc, char **argv) { @@ -25,7 +25,8 @@ int main(int argc, char **argv) { if (!thrd_is_finish(fut)) printf("checking...\n"); - result->object = thrd_then(check_primes, thrd_sync(fut), result).object; + thrd_then(check_primes, thrd_sync(fut), result); + thrd_destroy(fut); return 0; } diff --git a/include/raii.h b/include/raii.h index 3d46670..08780a6 100644 --- a/include/raii.h +++ b/include/raii.h @@ -119,7 +119,6 @@ typedef union { typedef struct { values_type value; - raii_type type; } raii_values_t; typedef struct { @@ -167,15 +166,12 @@ struct memory_s { typedef struct args_s { raii_type type; - bool defer_set; - bool data_set; + int defer_set; + unique_t *context; + size_t args_size; /* total number of args in set */ size_t n_args; - size_t data_size; - - unique_t *context; - void_t data; /* allocated array of arguments */ raii_values_t *args; @@ -184,7 +180,6 @@ typedef struct args_s { typedef void_t (*thrd_func_t)(args_t); typedef void_t (*result_func_t)(void_t result, size_t id, values_type iter); typedef void (*wait_func)(void); -make_atomic(c89atomic_spinlock, atomic_spinlock) typedef struct _promise { raii_type type; int id; @@ -198,7 +193,7 @@ typedef struct { int id; size_t value_count; raii_values_t **values; -} thrd_values; +} thrd_values_t; typedef struct _future_arg future_arg; typedef struct future_deque future_deque_t; @@ -227,6 +222,7 @@ struct future_deque { typedef struct future_pool { raii_type type; int thread_count; + memory_t *scope; future **futures; future_deque_t queue[1]; } future_t; @@ -237,7 +233,6 @@ struct _future { thrd_t thread; thrd_func_t func; promise *value; - future_t *pool; }; /* Calls fn (with args as arguments) in separate thread, returning without waiting @@ -260,14 +255,11 @@ C_API uintptr_t thrd_self(void); C_API raii_values_t *thrd_value(uintptr_t value); C_API future_t *thrd_for(thrd_func_t fn, size_t times, const char *desc, ...); -C_API thrd_values *thrd_sync(future_t *); -C_API values_type thrd_then(result_func_t callback, thrd_values *iter, void_t result); -C_API bool thrd_is_finish(future_t *); -C_API future_t thrd_add(future_t *, thrd_func_t routine, const char *desc, ...); +C_API thrd_values_t *thrd_sync(future_t *); +C_API int thrd_add(future_t *, thrd_func_t routine, const char *desc, ...); +C_API void thrd_then(result_func_t callback, thrd_values_t *iter, void_t result); C_API void thrd_destroy(future_t *); - -#define atomic_lock(mutex) c89atomic_spinlock_lock((atomic_spinlock *)mutex) -#define atomic_unlock(mutex) c89atomic_spinlock_unlock((atomic_spinlock *)mutex) +C_API bool thrd_is_finish(future_t *); /** * `Release/free` allocated memory, must be called if not using `get_args()` function. diff --git a/src/except.c b/src/except.c index f714fd3..46f15bd 100644 --- a/src/except.c +++ b/src/except.c @@ -8,6 +8,7 @@ EX_EXCEPTION(invalid_type); EX_EXCEPTION(range_error); EX_EXCEPTION(divide_by_zero); EX_EXCEPTION(logic_error); +EX_EXCEPTION(future_error); EX_EXCEPTION(system_error); EX_EXCEPTION(domain_error); EX_EXCEPTION(length_error); diff --git a/src/future.c b/src/future.c index fba5409..962c6d5 100644 --- a/src/future.c +++ b/src/future.c @@ -71,12 +71,13 @@ static int raii_wrapper(void_t arg) { } static void thrd_start(future *f, promise *value, void_t arg) { - future_arg *f_arg = try_malloc(sizeof(future_arg)); + future_arg *f_arg = try_calloc(1, sizeof(future_arg)); f_arg->func = f->func; f_arg->arg = arg; f_arg->value = value; f_arg->type = RAII_FUTURE_ARG; - int r = thrd_create(&f->thread, raii_wrapper, f_arg); + if (thrd_create(&f->thread, raii_wrapper, f_arg) != thrd_success) + throw(future_error); } future *thrd_async(thrd_func_t fn, void_t args) { @@ -120,27 +121,46 @@ RAII_INLINE uintptr_t thrd_self(void) { } future_t *thrd_for(thrd_func_t fn, size_t times, const char *desc, ...) { - future_t *pool = (future_t *)calloc_default(1, sizeof(future_t)); - pool->futures = (future **)calloc_default(times, sizeof(pool->futures[0]) * 2); - args_t params; + unique_t *scope = unique_init(); + future_t *pool = (future_t *)calloc_full(scope, 1, sizeof(future_t), RAII_FREE); + future **futures = (future **)calloc_default(times, sizeof(futures[0]) * 2); va_list args; + args_t params; size_t i; + va_start(args, desc); + params = raii_args_ex(nullptr, desc, args); + params->defer_set = true; + va_end(args); + + scope->arena = pool; + pool->scope = scope; + raii_deferred(scope, (func_t)args_free, params); + for (i = 0; i < times; i++) { - va_start(args, desc); - params = raii_args_ex(nullptr, desc, args); - pool->futures[i] = thrd_async(fn, (void_t)params); + promise *p = promise_create(); + future *f = future_create(fn); + future_arg *f_arg = try_calloc(1, sizeof(future_arg)); + f_arg->func = f->func; + f_arg->arg = params; + f_arg->value = p; + f_arg->type = RAII_FUTURE_ARG; + f->value = p; + if (thrd_create(&f->thread, raii_wrapper, f_arg) != thrd_success) + throw(future_error); + + futures[i] = f; } - va_end(args); pool->thread_count = times; + pool->futures = futures; pool->type = RAII_POOL; return pool; } -thrd_values *thrd_sync(future_t *v) { +thrd_values_t *thrd_sync(future_t *v) { if (is_type(v, RAII_POOL)) { - thrd_values *summary = (thrd_values *)calloc_default(v->thread_count, sizeof(thrd_values)); + thrd_values_t *summary = (thrd_values_t *)calloc_default(1, sizeof(thrd_values_t)); summary->values = (raii_values_t **)calloc_default(v->thread_count, sizeof(summary->values[0]) * 2); size_t i; @@ -158,14 +178,20 @@ thrd_values *thrd_sync(future_t *v) { throw(logic_error); } -values_type thrd_then(result_func_t callback, thrd_values *iter, void_t result) { +void thrd_then(result_func_t callback, thrd_values_t *iter, void_t result) { size_t i, max = iter->value_count; for (i = 0; i < max; i++) result = callback(result, i, iter->values[i]->value); - iter->values[max]->value.object = result; - return iter->values[max]->value; + raii_deferred_clean(); +} + +void thrd_destroy(future_t *f) { + if (is_type(f, RAII_POOL)) { + f->type = -1; + raii_delete(f->scope); + } } RAII_INLINE bool thrd_is_finish(future_t *f) { diff --git a/src/raii.c b/src/raii.c index 03a2fee..01cf7e8 100644 --- a/src/raii.c +++ b/src/raii.c @@ -592,9 +592,14 @@ RAII_INLINE values_type args_in(args_t params, size_t index) { } args_t raii_args_ex(memory_t *scope, const char *desc, va_list argp) { - size_t i, count = simd_strlen(desc); - args_t params = try_calloc(1, sizeof(args_t)); - params->args = try_calloc(count, sizeof(raii_values_t)); + size_t i, len, count = simd_strlen(desc); + args_t params = try_calloc(1, sizeof(struct args_s)); + uintptr_t **a; + void_t p; + string s; + params->args_size = sizeof(raii_values_t); + params->args = try_calloc(count, params->args_size); + params->args_size = params->args_size * count; for (i = 0; i < count; i++) { switch (*desc++) { @@ -624,7 +629,15 @@ args_t raii_args_ex(memory_t *scope, const char *desc, va_list argp) { break; case 's': // string argument - params->args[i].value.char_ptr = (char *)va_arg(argp, char *); + s = (char *)va_arg(argp, char *); + len = simd_strlen(s); + if (len > sizeof(raii_values_t)) { + params->args_size += len + 1; + params->args = try_realloc(params->args, params->args_size); + strncpy(params->args[i].value.char_ptr, s, len); + } else { + params->args[i].value.char_ptr = s; + } break; case 'a': // array argument @@ -640,8 +653,13 @@ args_t raii_args_ex(memory_t *scope, const char *desc, va_list argp) { break; case 'p': // void pointer (any arbitrary pointer) argument - default: params->args[i].value.object = va_arg(argp, void *); + default: + p = va_arg(argp, void *); + len = sizeof(p); + params->args_size += len; + params->args = try_realloc(params->args, params->args_size); + memcpy(params->args[i].value.object, p, sizeof(p)); break; } }