41#ifndef LELY_EV_FIBER_MAX_UNUSED
43#define LELY_EV_FIBER_MAX_UNUSED 16
78static void ev_fiber_exec_on_task_init(
ev_exec_t *exec);
79static void ev_fiber_exec_on_task_fini(
ev_exec_t *exec);
87 &ev_fiber_exec_on_task_init,
88 &ev_fiber_exec_on_task_fini,
89 &ev_fiber_exec_dispatch,
119static void ev_fiber_exec_func(
struct ev_task *task);
124static int ev_fiber_exec_post_ctx(
struct ev_fiber_exec *exec);
144static void ev_fiber_ctx_destroy(
struct ev_fiber_ctx *ctx);
147static void ev_fiber_ctx_task_func(
struct ev_task *task);
152static void ev_fiber_return(
void);
203static void ev_fiber_cnd_wake(
struct slnode *node);
241 while ((ctx = thr->
unused)) {
250ev_fiber_exec_alloc(
void)
252 struct ev_fiber_exec *exec = malloc(
sizeof(*exec));
266ev_fiber_exec_free(
void *ptr)
269 free(ev_fiber_exec_from_exec(ptr));
275 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
277 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
284 exec->inner_exec, &ev_fiber_exec_func);
305 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
306 assert(exec->
thr == &ev_fiber_thrd);
308 ev_fiber_exec_abort(exec_, NULL);
316 assert(exec->
posted == 0);
335 ev_exec_t *tmp = ev_fiber_exec_init(exec, inner_exec);
345 ev_fiber_exec_free((
void *)exec);
355 ev_fiber_exec_fini(exec);
356 ev_fiber_exec_free((
void *)exec);
452 assert(impl->
locked < SIZE_MAX);
458 ev_fiber_mtx_lock_func, impl);
460 assert(impl->
locked == 1);
463 assert(impl->
ctx == NULL);
500 assert(impl->
locked < SIZE_MAX);
513 assert(impl->
ctx == NULL);
621 ev_fiber_cnd_wake(node);
646 ev_fiber_cnd_wake(node);
686 assert(impl->
locked == 1);
695ev_fiber_exec_on_task_init(
ev_exec_t *exec_)
697 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
703ev_fiber_exec_on_task_fini(
ev_exec_t *exec_)
705 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
711ev_fiber_exec_dispatch(
ev_exec_t *exec_,
struct ev_task *task)
713 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
714 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
716 assert(!task->
exec || task->
exec == exec_);
719 struct ev_fiber_ctx *ctx = thr->
curr;
720 if (!ctx || ctx->
exec != exec) {
721 ev_fiber_exec_post(exec_, task);
736ev_fiber_exec_post(
ev_exec_t *exec_,
struct ev_task *task)
738 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
739 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
741 assert(!task->
exec || task->
exec == exec_);
745 ev_fiber_exec_on_task_init(exec_);
752 int post = !exec->
posted && exec->
thr != thr;
762 ev_fiber_exec_post_ctx(exec);
769ev_fiber_exec_defer(
ev_exec_t *exec_,
struct ev_task *task)
771 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
772 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
774 assert(!task->
exec || task->
exec == exec_);
777 struct ev_fiber_ctx *ctx = thr->
curr;
778 if (!ctx || ctx->
exec != exec) {
779 ev_fiber_exec_post(exec_, task);
785 ev_fiber_exec_on_task_init(exec_);
792ev_fiber_exec_abort(
ev_exec_t *exec_,
struct ev_task *task)
794 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
795 struct ev_fiber_exec *exec = ev_fiber_exec_from_exec(exec_);
800 struct ev_fiber_ctx *ctx = thr->
curr;
801 if (ctx && ctx->
exec == exec) {
823 ev_fiber_exec_on_task_fini(exec_);
830ev_fiber_exec_func(
struct ev_task *task)
833 struct ev_fiber_exec *exec =
structof(task,
struct ev_fiber_exec, task);
834 assert(exec->
thr == &ev_fiber_thrd);
847 ev_fiber_exec_post_ctx(exec);
850static inline struct ev_fiber_exec *
851ev_fiber_exec_from_exec(
const ev_exec_t *exec)
855 return structof(exec,
struct ev_fiber_exec, exec_vptr);
859ev_fiber_exec_post_ctx(
struct ev_fiber_exec *exec)
862 struct ev_fiber_ctx *ctx = ev_fiber_ctx_create(exec);
876static struct ev_fiber_ctx *
877ev_fiber_ctx_create(
struct ev_fiber_exec *exec)
879 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
882 assert(exec->
thr == thr);
885 struct ev_fiber_ctx *ctx = thr->
unused;
893 thr->
flags,
sizeof(
struct ev_fiber_ctx),
898 *ctx = (
struct ev_fiber_ctx){
907 exec->inner_exec, &ev_fiber_ctx_task_func);
913ev_fiber_ctx_destroy(
struct ev_fiber_ctx *ctx)
915 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
931ev_fiber_ctx_fiber_func(
fiber_t *fiber,
void *arg)
933 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
939 struct ev_task *task = NULL;
967 ev_fiber_exec_on_task_fini(exec);
981ev_fiber_ctx_task_func(
struct ev_task *task)
983 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
985 struct ev_fiber_ctx *ctx =
structof(task,
struct ev_fiber_ctx, task);
993static struct ev_fiber_ctx *
996 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
998 struct ev_fiber_ctx *ctx = thr->
curr;
1004 struct ev_fiber_exec *exec = ctx->
exec;
1014 ev_fiber_exec_post_ctx(exec);
1021ev_fiber_await_func(
fiber_t *fiber,
void *arg)
1025 struct ev_fiber_ctx *ctx = ev_fiber_resume(fiber);
1036ev_fiber_return(
void)
1038 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
1045ev_fiber_return_func(
fiber_t *fiber,
void *arg)
1047 struct ev_fiber_thrd *thr = &ev_fiber_thrd;
1050 struct ev_fiber_ctx *ctx = thr->
curr;
1055 ev_fiber_ctx_destroy(ctx);
1061ev_fiber_mtx_lock_func(
fiber_t *fiber,
void *arg)
1063 struct ev_fiber_mtx_impl *impl = arg;
1066 struct ev_fiber_ctx *ctx = ev_fiber_resume(fiber);
1079ev_fiber_cnd_wait_func(
fiber_t *fiber,
void *arg)
1083 ev_fiber_cnd_t *cond = wait->
cond;
1085 struct ev_fiber_cnd_impl *cond_impl = cond->_impl;
1087 ev_fiber_mtx_t *mtx = wait->
mtx;
1088 struct ev_fiber_mtx_impl *mtx_impl = mtx->_impl;
1091 struct ev_fiber_ctx *ctx = ev_fiber_resume(fiber);
1103 mtx_impl->
ctx = NULL;
1104 assert(mtx_impl->
locked == 1);
1106 struct ev_task *task =
1121ev_fiber_cnd_wake(
struct slnode *node)
1126 ev_fiber_mtx_t *mtx = wait->
mtx;
1128 struct ev_fiber_mtx_impl *impl = mtx->_impl;
1130 struct ev_task *task = wait->
task;
This header file is part of the utilities library; it contains the native and platform-independent er...
@ ERRNUM_PERM
Operation not permitted.
@ ERRNUM_INVAL
Invalid argument.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
This header file is part of the event library; it contains the abstract task executor interface.
size_t ev_exec_abort(ev_exec_t *exec, struct ev_task *task)
Aborts the specified task submitted to *exec, if it has not yet begun executing, or all pending tasks...
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
void ev_exec_on_task_fini(ev_exec_t *exec)
Undoes the effect of a previous call to ev_exec_on_task_init().
void ev_exec_on_task_init(ev_exec_t *exec)
Indicates to the specified executor that a task will be submitted for execution in the future.
#define _Thread_local
An object whose identifier is declared with the storage-class specifier _Thread_local has thread stor...
fiber_t * fiber_resume_with(fiber_t *fiber, fiber_func_t *func, void *arg)
Suspends the calling fiber and resumes the specified fiber, optionally executing a function before re...
#define FIBER_GUARD_STACK
A flag specifying a fiber to add a guard page when allocating the stack frame so that the kernel gene...
void * fiber_data(const fiber_t *fiber)
Returns a pointer to the data region of the specified fiber, or of the calling fiber if fiber is NULL...
int fiber_thrd_init(int flags)
Initializes the fiber associated with the calling thread.
fiber_t * fiber_create(fiber_func_t *func, void *arg, int flags, size_t data_size, size_t stack_size)
Creates a new fiber, allocates a stack and sets up a calling environment to begin executing the speci...
void fiber_thrd_fini(void)
Finalizes the fiber associated with the calling thread.
fiber_t * fiber_resume(fiber_t *fiber)
Equivalent to fiber_resume_with(fiber, NULL, NULL).
struct fiber fiber_t
The opaque fiber data type.
void fiber_destroy(fiber_t *fiber)
Destroys the specified fiber.
int ev_fiber_mtx_lock(ev_fiber_mtx_t *mtx)
Suspends the currently running fiber until it locks the fiber mutex at mtx.
void ev_fiber_thrd_fini(void)
Finalizes the calling thread and prevents further use by fiber executors.
int ev_fiber_mtx_init(ev_fiber_mtx_t *mtx, int type)
Creates a fiber mutex object with properties indicated by type, which must have one of the four value...
int ev_fiber_thrd_init(int flags, size_t stack_size, size_t max_unused)
Initializes the calling thread for use by fiber executors.
int ev_fiber_mtx_unlock(ev_fiber_mtx_t *mtx)
Unlocks the fiber mutex at mtx.
void ev_fiber_cnd_destroy(ev_fiber_cnd_t *cond)
Releases all resources used by the fiber condition variable at cond.
void ev_fiber_mtx_destroy(ev_fiber_mtx_t *mtx)
Releases any resources used by the fiber mutex at mtx.
int ev_fiber_cnd_signal(ev_fiber_cnd_t *cond)
Unblocks one of the fibers that are blocked on the fiber condition variable at cond at the time of th...
int ev_fiber_cnd_broadcast(ev_fiber_cnd_t *cond)
Unblocks all of the fibers that are blocked on the fiber condition variable at cond at the time of th...
int ev_fiber_cnd_init(ev_fiber_cnd_t *cond)
Creates a fiber condition variable.
void ev_fiber_exec_destroy(ev_exec_t *exec)
Destroys a fiber executor.
void ev_fiber_await(ev_future_t *future)
Suspends a currently running fiber until the specified future becomes ready (or is cancelled).
#define LELY_EV_FIBER_MAX_UNUSED
The maximum number of unused fibers per thread.
int ev_fiber_cnd_wait(ev_fiber_cnd_t *cond, ev_fiber_mtx_t *mtx)
Atomically unlocks the fiber mutex at mtx and endeavors to block until the fiber condition variable a...
int ev_fiber_mtx_trylock(ev_fiber_mtx_t *mtx)
Endeavors to lock the fiber mutex at mtx.
ev_exec_t * ev_fiber_exec_get_inner_exec(const ev_exec_t *exec_)
Returns a pointer to the inner executor of a fiber executor.
ev_exec_t * ev_fiber_exec_create(ev_exec_t *inner_exec)
Creates a fiber executor.
This header file is part of the event library; it contains the fiber executor, mutex and condition va...
@ ev_fiber_nomem
Indicates that the requested operation failed because it was unable to allocate memory.
@ ev_fiber_busy
Indicates that the requested operation failed because a resource requested by a test and return funct...
@ ev_fiber_error
Indicates that the requested operation failed.
@ ev_fiber_success
Indicates that the requested operation succeeded.
@ ev_fiber_mtx_recursive
A fiber mutex type that supports recursive locking.
struct ev_future ev_future_t
An object providing access to the result of an asynchronous operation.
void ev_future_submit(ev_future_t *future, struct ev_task *task)
Submits a task to be executed once the specified future is ready.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
This is the internal header file of the event library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdint....
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
The implementation of a fiber condition variable.
struct sllist queue
The queue of fibers waiting for the condition variable to be signaled.
mtx_t mtx
The mutex protecting queue.
A synchronization primitive (similar to the standard C11 condition variable) that can be used to bloc...
The context of a wait operation on a fiber condition variable.
struct slnode node
The node in the queue of fibers waiting on cond.
ev_fiber_cnd_t * cond
A pointer to the condition variable passed to ev_fiber_cnd_wait().
ev_fiber_mtx_t * mtx
A pointer to the mutex passed to ev_fiber_cnd_wait().
struct ev_task * task
A pointer to the task (in ev_fiber_ctx) used to wake up the fiber.
The context of a fiber used for executing tasks.
struct sllist queue
The queue of deferred tasks.
fiber_t * fiber
A pointer to the fiber containing this context.
struct ev_fiber_ctx * next
A pointer to the next fiber in the list of unused fibers.
struct ev_task task
The task used to resume the fiber.
struct ev_fiber_exec * exec
The executor using this fiber.
The implementation of a fiber executor.
struct ev_fiber_thrd * thr
A pointer to the ev_fiber_thrd instance for this executor.
ev_exec_t * inner_exec
A pointer to the inner executor.
struct sllist queue
The queue of tasks submitted to this executor.
int posted
A flag indicating whether task has been posted to inner_exec.
struct ev_task task
The task used to create new fibers.
const struct ev_exec_vtbl * exec_vptr
A pointer to the virtual table for the executor interface.
mtx_t mtx
The mutex protecting posted and queue.
size_t pending
The number of pending fibers available to execute a task.
The implementation of a fiber mutex.
int type
The type of mutex: ev_fiber_mtx_plain or ev_fiber_mtx_recursive.
struct sllist queue
The queue of fibers waiting to acquire the lock.
struct ev_fiber_ctx * ctx
A pointer to the fiber holding the lock.
size_t locked
The number of times the mutex has been recursively locked.
mtx_t mtx
The mutex protecting locked and queue.
A synchronization primitive (similar to the standard C11 mutex) that can be used to protect shared da...
The parameters used for creating fibers on this thread and the list of unused fibers.
size_t max_unused
The maximum number of unused fibers for this thread.
size_t num_unused
The number of unused fibers.
size_t stack_size
The size (in bytes) of the stack frame allocated for each fiber.
struct ev_fiber_ctx * curr
A pointer to the currently running fiber.
struct ev_fiber_ctx * unused
The list of unused fibers.
fiber_t * prev
A pointer to the previously running (suspended) fiber.
size_t refcnt
The number of invocations of ev_fiber_thrd_init() minus the the number of invocation of ev_fiber_thrd...
int flags
The flags used when creating each fiber.
ev_task_func_t * func
The function to be invoked when the task is run.
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
A node in a singly-linked list.
This header file is part of the event library; it contains the task declarations.
struct ev_task * ev_task_from_node(struct slnode *node)
Converts a pointer to a node in a queue to the address of the task containing the node.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
This header file is part of the C11 and POSIX compatibility library; it includes <threads....
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values:
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
@ thrd_success
Indicates that the requested operation succeeded.
@ thrd_nomem
Indicates that the requested operation failed because it was unable to allocate memory.
@ thrd_error
Indicates that the requested operation failed.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.