mirror of
https://github.com/jrcutler/threadless.io.git
synced 2024-07-07 10:35:49 +00:00
Adding coroutine_defer() (with test)
This commit is contained in:
parent
aca3db2b06
commit
9acc8a43b4
@ -29,6 +29,13 @@ enum {
|
||||
COROUTINE_ENDED = 1,
|
||||
};
|
||||
|
||||
typedef struct deferred deferred_t;
|
||||
struct deferred {
|
||||
allocation_t allocation;
|
||||
coroutine_deferred_function_t *function;
|
||||
void *data;
|
||||
deferred_t *next;
|
||||
};
|
||||
|
||||
struct coroutine {
|
||||
allocation_t allocation;
|
||||
@ -36,6 +43,7 @@ struct coroutine {
|
||||
ucontext_t caller;
|
||||
void *data;
|
||||
int status;
|
||||
deferred_t *deferred;
|
||||
};
|
||||
|
||||
|
||||
@ -78,6 +86,7 @@ coroutine_t *coroutine_create(allocator_t *allocator,
|
||||
coro = allocation.memory;
|
||||
memset(coro, 0, alloc_size);
|
||||
coro->allocation = allocation;
|
||||
coro->deferred = NULL;
|
||||
(void) getcontext(&coro->context);
|
||||
coro->context.uc_stack.ss_sp = coro + 1;
|
||||
coro->context.uc_stack.ss_size = stack_size;
|
||||
@ -94,9 +103,22 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static void coroutine_run_deferred(coroutine_t *coro)
|
||||
{
|
||||
deferred_t *deferred = coro->deferred;
|
||||
while (NULL != deferred) {
|
||||
allocation_t allocation = deferred->allocation;
|
||||
deferred->function(deferred->data);
|
||||
deferred = deferred->next;
|
||||
allocation_free(&allocation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void coroutine_destroy(coroutine_t *coro)
|
||||
{
|
||||
if (NULL != coro) {
|
||||
coroutine_run_deferred(coro);
|
||||
allocation_t allocation = coro->allocation;
|
||||
allocation_free(&allocation);
|
||||
}
|
||||
@ -129,3 +151,30 @@ void *coroutine_yield(coroutine_t *coro, void *value)
|
||||
(void) swapcontext(&coro->context, &coro->caller);
|
||||
return coro->data;
|
||||
}
|
||||
|
||||
|
||||
int coroutine_defer(coroutine_t *coro, coroutine_deferred_function_t *function,
|
||||
void *data)
|
||||
{
|
||||
int error;
|
||||
deferred_t *deferred = NULL;
|
||||
allocation_t allocation;
|
||||
|
||||
/* allocate memory */
|
||||
allocation_init(&allocation, coro->allocation.allocator);
|
||||
error = allocation_realloc_array(&allocation, 1, sizeof(*deferred));
|
||||
|
||||
if (!error) {
|
||||
/* initialize deferred work */
|
||||
deferred = allocation.memory;
|
||||
deferred->allocation = allocation;
|
||||
deferred->function = function;
|
||||
deferred->data = data;
|
||||
|
||||
/* push deferred work to front of list */
|
||||
deferred->next = coro->deferred;
|
||||
coro->deferred = deferred;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -52,10 +52,23 @@ static void *fibonacci_generator(coroutine_t *coro, void *data)
|
||||
}
|
||||
|
||||
|
||||
static void deferred_puts(void *data)
|
||||
{
|
||||
puts(data);
|
||||
}
|
||||
|
||||
|
||||
static void *output_coroutine(coroutine_t *coro, void *data)
|
||||
{
|
||||
size_t *value = data;
|
||||
|
||||
if (coroutine_defer(coro, deferred_puts, "deferred output 0")) {
|
||||
return NULL;
|
||||
}
|
||||
if (coroutine_defer(coro, deferred_puts, "deferred output 1")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (NULL != value) {
|
||||
printf("%zu\n", *value);
|
||||
value = coroutine_yield(coro, value);
|
||||
|
@ -29,6 +29,11 @@ typedef struct coroutine coroutine_t;
|
||||
*/
|
||||
typedef void *(coroutine_function_t)(coroutine_t *coro, void *data);
|
||||
|
||||
/** Coroutine deferred function type
|
||||
* @param[in,out] data user-defined data
|
||||
*/
|
||||
typedef void (coroutine_deferred_function_t)(void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@ -77,6 +82,18 @@ void *coroutine_resume(coroutine_t *coro, void *value);
|
||||
*/
|
||||
void *coroutine_yield(coroutine_t *coro, void *value);
|
||||
|
||||
/** Defer a function call until coroutine termination
|
||||
* @param[in,out] coro coroutine
|
||||
* @param function function to call when @p coro terminates
|
||||
* @param data user-defined point to pass to @p function
|
||||
* @retval 0 success
|
||||
* @retval -1 error
|
||||
* @post @p function will be called with @p data when @p coro terminates
|
||||
* @note Registered functions will be called in reverse order of registration
|
||||
*/
|
||||
int coroutine_defer(coroutine_t *coro, coroutine_deferred_function_t *function,
|
||||
void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
Loading…
x
Reference in New Issue
Block a user