summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt13
-rw-r--r--source/kit/async_function.h219
-rw-r--r--source/kit/dynamic_array.c3
-rw-r--r--source/test/unittests/async_function.test.c138
4 files changed, 97 insertions, 276 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6bd3356..b199e4d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,10 +6,11 @@ if(NOT DEFINED CMAKE_BUILD_PARALLEL_LEVEL)
set(CMAKE_BUILD_PARALLEL_LEVEL 4 CACHE STRING "" FORCE)
endif()
-option(KIT_DISABLE_SYSTEM_MALLOC "Disable system memory allocator" OFF)
-option(KIT_DISABLE_SYSTEM_THREADS "Disable system threads" OFF)
-option(KIT_ENABLE_CUSTOM_ALLOC_DISPATCH "Enable custom allocator dispatch" OFF)
-option(KIT_ENABLE_TESTING "Enable testing" ON)
+option(KIT_DISABLE_SYSTEM_MALLOC "Disable system memory allocator" OFF)
+option(KIT_DISABLE_SYSTEM_THREADS "Disable system threads" OFF)
+option(KIT_ENABLE_CUSTOM_ALLOC_DISPATCH "Enable custom allocator dispatch" OFF)
+option(KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH "Enable custom async function dispatch" OFF)
+option(KIT_ENABLE_TESTING "Enable testing" ON)
project(
kit
@@ -118,6 +119,10 @@ if(KIT_ENABLE_CUSTOM_ALLOC_DISPATCH)
target_compile_definitions(kit PUBLIC KIT_ENABLE_CUSTOM_ALLOC_DISPATCH)
endif()
+if(KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH)
+ target_compile_definitions(kit PUBLIC KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH)
+endif()
+
if(NOT KIT_DISABLE_SYSTEM_THREADS)
find_package(Threads REQUIRED)
target_link_libraries(kit PUBLIC Threads::Threads)
diff --git a/source/kit/async_function.h b/source/kit/async_function.h
index 6bb2e83..6b4616d 100644
--- a/source/kit/async_function.h
+++ b/source/kit/async_function.h
@@ -7,32 +7,16 @@
extern "C" {
#endif
-enum {
- KIT_AF_REQUEST_EXECUTE = 0,
- KIT_AF_REQUEST_RESUME = 1,
- KIT_AF_REQUEST_JOIN = 2,
- KIT_AF_REQUEST_RESUME_AND_JOIN = 3
-};
-
typedef struct {
int _;
} kit_af_void;
-typedef void (*kit_af_state_machine)(void *self_void_, int request_);
-typedef void (*kit_af_execute)(void *state, void *coro_state,
- int request);
+typedef void (*kit_af_state_machine)(void *self_void_);
-typedef struct {
- long long _internal;
- void *state;
- kit_af_execute execute;
-} kit_af_execution_context;
-
-#define KIT_AF_STATE_DATA \
- struct { \
- int _index; \
- kit_af_state_machine _state_machine; \
- kit_af_execution_context _context; \
+#define KIT_AF_STATE_DATA \
+ struct { \
+ int _index; \
+ kit_af_state_machine _state_machine; \
}
typedef struct {
@@ -41,6 +25,21 @@ typedef struct {
#define KIT_AF_INTERNAL(coro_) (*((kit_af_type_void *) (coro_)))
+#ifdef KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH
+/* Application should implement this function if custom async
+ * function dispatch is enabled.
+ *
+ * See KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH macro.
+ */
+void kit_async_function_dispatch(void *promise);
+#else
+static void kit_async_function_dispatch(void *promise) {
+ /* Dynamic dispatch by default.
+ */
+ KIT_AF_INTERNAL(promise)._state_machine(promise);
+}
+#endif
+
#define KIT_AF_STATE(ret_type_, name_, ...) \
struct name_##_coro_state_ { \
KIT_AF_STATE_DATA; \
@@ -48,22 +47,13 @@ typedef struct {
__VA_ARGS__ \
}
-#define KIT_AF_DECL(name_) void name_(void *self_void_, int request_)
-
-#define KIT_CORO_IMPL(name_) \
- KIT_AF_DECL(name_) { \
- struct name_##_coro_state_ *self = \
- (struct name_##_coro_state_ *) self_void_; \
- if (request_ != KIT_AF_REQUEST_EXECUTE) { \
- if (self->_context.execute != NULL) \
- self->_context.execute(self->_context.state, self_void_, \
- request_); \
- else if (request_ == KIT_AF_REQUEST_JOIN || \
- request_ == KIT_AF_REQUEST_RESUME_AND_JOIN) \
- self->_state_machine(self_void_, KIT_AF_REQUEST_EXECUTE); \
- return; \
- } \
- switch (self->_index) { \
+#define KIT_AF_DECL(name_) void name_(void *self_void_)
+
+#define KIT_CORO_IMPL(name_) \
+ KIT_AF_DECL(name_) { \
+ struct name_##_coro_state_ *self = \
+ (struct name_##_coro_state_ *) self_void_; \
+ switch (self->_index) { \
case 0:;
#define KIT_AF_LINE_() __LINE__
@@ -94,6 +84,12 @@ typedef struct {
#define KIT_STATIC_CORO_VOID(name_, ...) \
KIT_STATIC_CORO(kit_af_void, name_, __VA_ARGS__)
+#define KIT_AF_EXECUTE(promise_) \
+ kit_async_function_dispatch(&(promise_))
+
+#define KIT_AF_NEXT(promise_) \
+ (kit_async_function_dispatch(&(promise_)), (promise_).return_value)
+
#define KIT_AF_YIELD(...) \
do { \
self->_index = KIT_AF_LINE_(); \
@@ -122,44 +118,40 @@ typedef struct {
return; \
} while (0)
-#define KIT_AF_AWAIT(promise_) \
- do { \
- case KIT_AF_LINE_(): \
- if ((promise_)._index != -1) { \
- self->_index = KIT_AF_LINE_(); \
- (promise_)._state_machine(&(promise_), \
- KIT_AF_REQUEST_RESUME_AND_JOIN); \
- } \
- if ((promise_)._index != -1) \
- return; \
+#define KIT_AF_AWAIT(promise_) \
+ do { \
+ case KIT_AF_LINE_(): \
+ if ((promise_)._index != -1) { \
+ self->_index = KIT_AF_LINE_(); \
+ kit_async_function_dispatch(&(promise_)); \
+ } \
+ if ((promise_)._index != -1) \
+ return; \
} while (0)
-#define KIT_AF_YIELD_AWAIT(promise_) \
- do { \
- case KIT_AF_LINE_(): \
- if ((promise_)._index != -1) { \
- self->_index = KIT_AF_LINE_(); \
- (promise_)._state_machine(&(promise_), \
- KIT_AF_REQUEST_RESUME_AND_JOIN); \
- self->return_value = (promise_).return_value; \
- return; \
- } \
+#define KIT_AF_YIELD_AWAIT(promise_) \
+ do { \
+ case KIT_AF_LINE_(): \
+ if ((promise_)._index != -1) { \
+ self->_index = KIT_AF_LINE_(); \
+ kit_async_function_dispatch(&(promise_)); \
+ self->return_value = (promise_).return_value; \
+ return; \
+ } \
} while (0)
#define KIT_AF_TYPE(coro_) struct coro_##_coro_state_
-#define KIT_AF_INITIAL(coro_) \
- ._index = 0, ._state_machine = (coro_), \
- ._context = { .state = NULL, .execute = NULL }
+#define KIT_AF_INITIAL(coro_) ._index = 0, ._state_machine = (coro_)
#define KIT_AF_CREATE(promise_, coro_, ...) \
KIT_AF_TYPE(coro_) \
promise_ = { KIT_AF_INITIAL(coro_), __VA_ARGS__ }
-#define KIT_AF_INIT(promise_, coro_, ...) \
- do { \
- KIT_AF_CREATE(kit_af_temp_, coro_, __VA_ARGS__); \
- (promise_) = kit_af_temp_; \
+#define KIT_AF_INIT(promise_, coro_, ...) \
+ do { \
+ KIT_AF_CREATE(kit_af_temp_, coro_, __VA_ARGS__); \
+ memcpy(&(promise_), &kit_af_temp_, sizeof kit_af_temp_); \
} while (0)
#define KIT_AF_INIT_EXPLICIT(promise_, size_, coro_func_) \
@@ -168,59 +160,6 @@ typedef struct {
(promise_)._state_machine = (coro_func_); \
} while (0)
-#define KIT_AF_EXECUTION_CONTEXT(promise_, ...) \
- do { \
- kit_af_execution_context kit_af_temp_ = { ._internal = 0, \
- __VA_ARGS__ }; \
- (promise_)._context = kit_af_temp_; \
- } while (0)
-
-#define KIT_AF_RESUME(promise_) \
- (promise_)._state_machine(&(promise_), KIT_AF_REQUEST_RESUME)
-
-#define KIT_AF_RESUME_N(promises_, size_) \
- do { \
- int kit_af_index_; \
- for (kit_af_index_ = 0; kit_af_index_ < (size_); \
- kit_af_index_++) \
- KIT_AF_RESUME((promises_)[kit_af_index_]); \
- } while (0)
-
-#define KIT_AF_JOIN(promise_) \
- ((promise_)._state_machine(&(promise_), KIT_AF_REQUEST_JOIN), \
- (promise_).return_value)
-
-#define KIT_AF_JOIN_N(promises_, size_) \
- do { \
- int kit_af_index_; \
- for (kit_af_index_ = 0; kit_af_index_ < (size_); \
- kit_af_index_++) \
- (void) KIT_AF_JOIN((promises_)[kit_af_index_]); \
- } while (0)
-
-#define KIT_AF_RESUME_AND_JOIN(promise_) \
- ((promise_)._state_machine(&(promise_), \
- KIT_AF_REQUEST_RESUME_AND_JOIN), \
- (promise_).return_value)
-
-#define KIT_AF_RESUME_AND_JOIN_N(promises_, size_) \
- do { \
- KIT_AF_RESUME_N((promises_), (size_)); \
- KIT_AF_JOIN_N((promises_), (size_)); \
- } while (0)
-
-#define KIT_AF_RESUME_ALL(promises_) \
- KIT_AF_RESUME_N((promises_), \
- sizeof(promises_) / sizeof((promises_)[0]))
-
-#define KIT_AF_JOIN_ALL(promises_) \
- KIT_AF_JOIN_N((promises_), \
- sizeof(promises_) / sizeof((promises_)[0]))
-
-#define KIT_AF_RESUME_AND_JOIN_ALL(promises_) \
- KIT_AF_RESUME_AND_JOIN_N((promises_), sizeof(promises_) / \
- sizeof((promises_)[0]))
-
#define KIT_AF_FINISHED(promise_) ((promise_)._index == -1)
#define KIT_AF_FINISHED_N(return_, promises_, size_) \
@@ -239,43 +178,12 @@ typedef struct {
KIT_AF_FINISHED_N((return_), (promises_), \
sizeof(promises_) / sizeof((promises_)[0]))
-#define KIT_AF_AWAIT_N(promises_, size_) \
- do { \
- int kit_af_done_; \
- case KIT_AF_LINE_(): \
- self->_index = KIT_AF_LINE_(); \
- KIT_AF_RESUME_AND_JOIN_N((promises_), (size_)); \
- KIT_AF_FINISHED_N(kit_af_done_, (promises_), (size_)); \
- if (!kit_af_done_) \
- return; \
- } while (0)
-
-#define KIT_AF_AWAIT_ALL(promises_) \
- KIT_AF_AWAIT_N((promises_), \
- sizeof(promises_) / sizeof((promises_)[0]))
-
-#define KIT_AF_EXECUTE(promise_) \
- KIT_AF_INTERNAL(promise_)._state_machine((promise_), \
- KIT_AF_REQUEST_EXECUTE)
-
#ifndef KIT_DISABLE_SHORT_NAMES
-# ifndef KIT_DISABLE_AF_SELF_SHORTCUT
-# define af self->
-# endif
-
-# define af_request kit_af_request
-# define AF_REQUEST_EXECUTE KIT_AF_REQUEST_EXECUTE
-# define AF_REQUEST_RESUME KIT_AF_REQUEST_RESUME
-# define AF_REQUEST_JOIN KIT_AF_REQUEST_JOIN
-# define AF_REQUEST_RESUME_AND_JOIN KIT_AF_REQUEST_RESUME_AND_JOIN
# define af_void kit_af_void
# define af_state_machine kit_af_state_machine
-# define af_execute kit_af_execute
-# define af_execution_context kit_af_execution_context
# define af_type_void kit_af_type_void
# define AF_STATE_DATA KIT_AF_STATE_DATA
-# define AF_INTERNAL KIT_AF_INTERNAL
# define AF_STATE KIT_AF_STATE
# define AF_DECL KIT_AF_DECL
# define CORO_IMPL KIT_CORO_IMPL
@@ -286,6 +194,8 @@ typedef struct {
# define STATIC_CORO KIT_STATIC_CORO
# define STATIC_CORO_VOID KIT_STATIC_CORO_VOID
# define CORO_VOID KIT_CORO_VOID
+# define AF_EXECUTE KIT_AF_EXECUTE
+# define AF_NEXT KIT_AF_NEXT
# define AF_YIELD KIT_AF_YIELD
# define AF_YIELD_VOID KIT_AF_YIELD_VOID
# define AF_RETURN KIT_AF_RETURN
@@ -297,22 +207,9 @@ typedef struct {
# define AF_CREATE KIT_AF_CREATE
# define AF_INIT KIT_AF_INIT
# define AF_INIT_EXPLICIT KIT_AF_INIT_EXPLICIT
-# define AF_EXECUTION_CONTEXT KIT_AF_EXECUTION_CONTEXT
-# define AF_RESUME KIT_AF_RESUME
-# define AF_RESUME_N KIT_AF_RESUME_N
-# define AF_JOIN KIT_AF_JOIN
-# define AF_JOIN_N KIT_AF_JOIN_N
-# define AF_RESUME_AND_JOIN KIT_AF_RESUME_AND_JOIN
-# define AF_RESUME_AND_JOIN_N KIT_AF_RESUME_AND_JOIN_N
-# define AF_RESUME_ALL KIT_AF_RESUME_ALL
-# define AF_JOIN_ALL KIT_AF_JOIN_ALL
-# define AF_RESUME_AND_JOIN_ALL KIT_AF_RESUME_AND_JOIN_ALL
# define AF_FINISHED KIT_AF_FINISHED
# define AF_FINISHED_N KIT_AF_FINISHED_N
# define AF_FINISHED_ALL KIT_AF_FINISHED_ALL
-# define AF_AWAIT_N KIT_AF_AWAIT_N
-# define AF_AWAIT_ALL KIT_AF_AWAIT_ALL
-# define AF_EXECUTE KIT_AF_EXECUTE
#endif
#ifdef __cplusplus
diff --git a/source/kit/dynamic_array.c b/source/kit/dynamic_array.c
index d3eaf29..aece99e 100644
--- a/source/kit/dynamic_array.c
+++ b/source/kit/dynamic_array.c
@@ -8,7 +8,6 @@ void kit_da_init(kit_da_void_t *array, ptrdiff_t element_size,
assert(array != NULL);
assert(element_size > 0);
assert(size >= 0);
- assert(alloc.allocate != NULL);
memset(array, 0, sizeof(kit_da_void_t));
@@ -44,8 +43,6 @@ void kit_da_resize(kit_da_void_t *array, ptrdiff_t element_size,
} else {
ptrdiff_t capacity = eval_capacity(array->capacity, size);
- assert(array->alloc.allocate != NULL);
-
void *bytes = kit_alloc_dispatch(
array->alloc, KIT_ALLOCATE, element_size * capacity, 0, NULL);
diff --git a/source/test/unittests/async_function.test.c b/source/test/unittests/async_function.test.c
index 5adc0e7..a10dbff 100644
--- a/source/test/unittests/async_function.test.c
+++ b/source/test/unittests/async_function.test.c
@@ -21,8 +21,9 @@ CORO_IMPL(test_bar) {
CORO_END
STATIC_CORO(int, test_gen, int i; int min; int max;) {
- for (af i = af min; af i < af max; af i++) AF_YIELD(af i);
- AF_RETURN(af max);
+ for (self->i = self->min; self->i < self->max; self->i++)
+ AF_YIELD(self->i);
+ AF_RETURN(self->max);
}
CORO_END
@@ -34,54 +35,19 @@ STATIC_CORO_VOID(test_task, ) {
CORO_END
STATIC_CORO_VOID(test_nest_task, AF_TYPE(test_task) promise;) {
- AF_INIT(af promise, test_task, );
- AF_AWAIT(af promise);
- AF_AWAIT(af promise);
- AF_AWAIT(af promise);
+ AF_INIT(self->promise, test_task, );
+ AF_AWAIT(self->promise);
+ AF_AWAIT(self->promise);
+ AF_AWAIT(self->promise);
}
CORO_END
STATIC_CORO(int, test_nest_generator, AF_TYPE(test_gen) promise;) {
- AF_INIT(af promise, test_gen, .min = 1, .max = 3);
- AF_YIELD_AWAIT(af promise);
+ AF_INIT(self->promise, test_gen, .min = 1, .max = 3);
+ AF_YIELD_AWAIT(self->promise);
}
CORO_END
-STATIC_CORO(int, test_join_multiple, AF_TYPE(test_bar) promises[3];) {
- int i;
- for (i = 0; i < 3; i++)
- AF_INIT(af promises[i], test_bar, .return_value = 0);
- AF_RESUME_AND_JOIN_ALL(af promises);
- AF_RETURN(af promises[0].return_value +
- af promises[1].return_value +
- af promises[2].return_value);
-}
-CORO_END
-
-STATIC_CORO(int, test_await_multiple,
- AF_TYPE(test_bar) promises[3];) {
- int i;
- for (i = 0; i < 3; i++)
- AF_INIT(af promises[i], test_bar, .return_value = 0);
- AF_AWAIT_ALL(af promises);
- AF_RETURN(af promises[0].return_value +
- af promises[1].return_value +
- af promises[2].return_value);
-}
-CORO_END
-
-void test_execute_lazy(void *_, void *coro, int request) {
- if (request == AF_REQUEST_RESUME)
- return;
- AF_EXECUTE(coro);
-}
-
-void test_execute_immediate(void *_, void *coro, int request) {
- if (request == AF_REQUEST_JOIN)
- return;
- AF_EXECUTE(coro);
-}
-
TEST("coroutine create") {
AF_CREATE(promise, test_foo, );
REQUIRE(!AF_FINISHED(promise));
@@ -106,111 +72,67 @@ TEST("coroutine init with value") {
REQUIRE(!AF_FINISHED(promise));
}
-TEST("coroutine resume") {
+TEST("coroutine create with value") {
AF_CREATE(promise, test_foo, .return_value = -1);
- AF_RESUME(promise);
REQUIRE(promise.return_value == -1);
REQUIRE(!AF_FINISHED(promise));
}
-TEST("coroutine resume and join") {
+TEST("coroutine execute and return") {
AF_CREATE(promise, test_foo, );
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 42);
+ REQUIRE(AF_NEXT(promise) == 42);
REQUIRE(AF_FINISHED(promise));
}
-TEST("coroutine resume and join manually") {
- AF_CREATE(promise, test_foo, );
- AF_RESUME(promise);
- REQUIRE(AF_JOIN(promise) == 42);
- REQUIRE(AF_FINISHED(promise));
-}
-
-TEST("coroutine suspend") {
+TEST("coroutine execute two steps") {
AF_CREATE(promise, test_bar, .return_value = 0);
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 0);
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 42);
+ AF_EXECUTE(promise);
+ REQUIRE(promise.return_value == 0);
+ AF_EXECUTE(promise);
+ REQUIRE(promise.return_value == 42);
}
TEST("coroutine generator") {
int i;
AF_CREATE(promise, test_gen, .min = 10, .max = 15);
- for (i = 0; i <= 5; i++)
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 10 + i);
+ for (i = 0; i <= 5; i++) REQUIRE(AF_NEXT(promise) == 10 + i);
}
TEST("coroutine status finished") {
AF_CREATE(promise, test_bar, );
REQUIRE(!AF_FINISHED(promise));
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(!AF_FINISHED(promise));
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(AF_FINISHED(promise));
}
TEST("coroutine task") {
AF_CREATE(promise, test_task, );
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(!AF_FINISHED(promise));
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(!AF_FINISHED(promise));
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(AF_FINISHED(promise));
}
TEST("coroutine nested task") {
AF_CREATE(promise, test_nest_task, );
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(!AF_FINISHED(promise));
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(!AF_FINISHED(promise));
- (void) AF_RESUME_AND_JOIN(promise);
+ AF_EXECUTE(promise);
REQUIRE(AF_FINISHED(promise));
}
TEST("coroutine nested generator") {
AF_CREATE(promise, test_nest_generator, );
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 1);
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 2);
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 3);
+ REQUIRE(AF_NEXT(promise) == 1);
+ REQUIRE(AF_NEXT(promise) == 2);
+ REQUIRE(AF_NEXT(promise) == 3);
REQUIRE(!AF_FINISHED(promise));
- (void) AF_RESUME_AND_JOIN(promise);
- REQUIRE(AF_FINISHED(promise));
-}
-
-TEST("coroutine join multiple") {
- AF_CREATE(promise, test_join_multiple, );
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 0);
- REQUIRE(AF_FINISHED(promise));
-}
-
-TEST("coroutine await multiple") {
- AF_CREATE(promise, test_await_multiple, );
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 0);
- REQUIRE(AF_RESUME_AND_JOIN(promise) == 42 * 3);
- REQUIRE(AF_FINISHED(promise));
-}
-
-TEST("coroutine custom execution context lazy") {
- AF_CREATE(promise, test_foo, .return_value = 0);
- AF_EXECUTION_CONTEXT(promise, .state = NULL,
- .execute = test_execute_lazy);
- AF_RESUME(promise);
- REQUIRE(promise.return_value == 0);
- REQUIRE(!AF_FINISHED(promise));
- (void) AF_JOIN(promise);
- REQUIRE(promise.return_value == 42);
- REQUIRE(AF_FINISHED(promise));
-}
-
-TEST("coroutine custom execution context immediate") {
- AF_CREATE(promise, test_foo, .return_value = 0);
- AF_EXECUTION_CONTEXT(promise, .state = NULL,
- .execute = test_execute_immediate);
- AF_RESUME(promise);
- REQUIRE(promise.return_value == 42);
- REQUIRE(AF_FINISHED(promise));
- (void) AF_JOIN(promise);
- REQUIRE(promise.return_value == 42);
+ AF_EXECUTE(promise);
REQUIRE(AF_FINISHED(promise));
}