33#define LELY_EV_LOOP_INLINE extern inline
46#ifndef LELY_EV_LOOP_CTX_MAX_UNUSED
48#define LELY_EV_LOOP_CTX_MAX_UNUSED 16
91static void ev_loop_ctx_task_func(
struct ev_task *
task);
94static void ev_loop_ctx_free(
struct ev_loop_ctx *ctx);
96static void ev_loop_ctx_release(
struct ev_loop_ctx *ctx);
100static void ev_loop_ctx_destroy(
struct ev_loop_ctx *ctx);
104static size_t ev_loop_ctx_wait_one_until(
struct ev_loop_ctx **pctx,
106 const struct timespec *abs_time);
108static int ev_loop_ctx_kill(
struct ev_loop_ctx *ctx,
int stop);
124static void ev_loop_std_exec_impl_on_task_init(ev_std_exec_impl_t *impl);
125static void ev_loop_std_exec_impl_on_task_fini(ev_std_exec_impl_t *impl);
126static void ev_loop_std_exec_impl_post(
127 ev_std_exec_impl_t *impl,
struct ev_task *task);
128static size_t ev_loop_std_exec_impl_abort(
129 ev_std_exec_impl_t *impl,
struct ev_task *task);
133 &ev_loop_std_exec_impl_on_task_init,
134 &ev_loop_std_exec_impl_on_task_fini,
135 &ev_loop_std_exec_impl_post,
136 &ev_loop_std_exec_impl_abort
170#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
172#elif _WIN64 && !defined(__MINGW32__)
174#elif _WIN32 && !defined(__MINGW32__)
198static inline ev_loop_t *ev_loop_from_impl(
const ev_std_exec_impl_t *impl);
219ev_loop_free(
void *ptr)
243 if (loop->
poll && poll_task)
246#if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
274 ev_loop_ctx_free(ctx);
350 ev_loop_do_stop(
loop);
390 while (ev_loop_ctx_wait_one(&ctx,
loop,
future))
392 ev_loop_ctx_destroy(ctx);
398 const struct timespec *abs_time)
402 while (ev_loop_ctx_wait_one_until(&ctx,
loop,
future, abs_time))
404 ev_loop_ctx_destroy(ctx);
412 size_t n = ev_loop_ctx_wait_one(&ctx,
loop,
future);
413 ev_loop_ctx_destroy(ctx);
419 const struct timespec *abs_time)
422 size_t n = ev_loop_ctx_wait_one_until(&ctx,
loop,
future, abs_time);
423 ev_loop_ctx_destroy(ctx);
451 if ((result = ev_loop_ctx_kill(thr->
ctx, 1)) == -1)
465ev_loop_ctx_task_func(
struct ev_task *task)
480 ev_loop_ctx_kill(ctx, 0);
485 ev_loop_ctx_release(ctx);
489ev_loop_ctx_alloc(
void)
498 goto error_malloc_ctx;
512 goto error_init_cond;
581 ev_loop_ctx_free(ctx);
605 ctx = ev_loop_ctx_alloc();
651 ev_loop_ctx_release(ctx);
680 if (ev_loop_empty(
loop) && !ev_loop_ntasks(
loop)
682 ev_loop_do_stop(
loop);
687 if (task && task == &loop->
task) {
712 ctx = *pctx = ev_loop_ctx_create(loop, future);
725 if (ev_loop_can_poll(loop)) {
767 ev_loop_kill_any(loop, 1);
770 ev_loop_kill_any(loop, 0);
783 ev_future_t *future,
const struct timespec *abs_time)
789#if LELY_NO_THREADS && LELY_NO_TIMEOUT
803 if (ev_loop_empty(
loop) && !ev_loop_ntasks(
loop)
805 ev_loop_do_stop(
loop);
810 if (task && task == &loop->
task) {
835 ctx = *pctx = ev_loop_ctx_create(loop, future);
848 if (ev_loop_can_poll(loop)) {
862 if (empty && abs_time) {
863 struct timespec now = { 0, 0 };
874 else if (msec > INT_MAX)
892#if !LELY_NO_THREADS && !LELY_NO_TIMEOUT
893 }
else if (abs_time) {
898 &ctx->
cond, &loop->
mtx, abs_time);
918 ev_loop_kill_any(loop, 1);
921 ev_loop_kill_any(loop, 0);
955ev_loop_std_exec_impl_on_task_init(ev_std_exec_impl_t *impl)
957 ev_loop_t *loop = ev_loop_from_impl(impl);
959#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
961#elif _WIN64 && !defined(__MINGW32__)
962 InterlockedIncrementNoFence64(&loop->
ntasks);
963#elif _WIN32 && !defined(__MINGW32__)
964 InterlockedIncrementNoFence(&loop->
ntasks);
971ev_loop_std_exec_impl_on_task_fini(ev_std_exec_impl_t *impl)
973 ev_loop_t *loop = ev_loop_from_impl(impl);
975#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
977#elif _WIN64 && !defined(__MINGW32__)
978 if (!InterlockedDecrementRelease64(&loop->
ntasks)) {
980#elif _WIN32 && !defined(__MINGW32__)
981 if (!InterlockedDecrementRelease(&loop->
ntasks)) {
991 if (ev_loop_empty(loop))
992 ev_loop_do_stop(loop);
1000ev_loop_std_exec_impl_post(ev_std_exec_impl_t *impl,
struct ev_task *task)
1002 ev_loop_t *loop = ev_loop_from_impl(impl);
1011 ev_loop_kill_any(loop, 1);
1018ev_loop_std_exec_impl_abort(ev_std_exec_impl_t *impl,
struct ev_task *task)
1020 ev_loop_t *loop = ev_loop_from_impl(impl);
1053ev_loop_from_impl(
const ev_std_exec_impl_t *impl)
1069 return node == &loop->
task._node && node->
next == NULL;
1077#if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
1096 ev_loop_ctx_kill(ctx, 1);
1102 ev_loop_ctx_kill(ctx, 1);
1117 return ev_loop_ctx_kill(ctx, 0);
1123 return ev_loop_ctx_kill(ctx, 0);
This header file is part of the utilities library; it contains the doubly-linked list declarations.
void dllist_init(struct dllist *list)
Initializes a doubly-linked list.
int dllist_empty(const struct dllist *list)
Returns 1 if the doubly-linked list is empty, and 0 if not.
#define dllist_foreach(list, node)
Iterates in order over each node in a doubly-linked list.
void dllist_push_front(struct dllist *list, struct dlnode *node)
Pushes a node to the front of a doubly-linked list.
struct dlnode * dllist_first(const struct dllist *list)
Returns a pointer to the first node in a doubly-linked list.
void dlnode_init(struct dlnode *node)
Initializes a node in a doubly-linked list.
void dllist_remove(struct dllist *list, struct dlnode *node)
Removes a node from a doubly-linked list.
This header file is part of the utilities library; it contains the native and platform-independent er...
@ ERRNUM_TIMEDOUT
Connection timed out.
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.
void * ev_poll_self(const ev_poll_t *poll)
Returns the identifier of the calling thread.
const struct ev_poll_vtbl *const ev_poll_t
The abstract polling interface.
int ev_poll_kill(ev_poll_t *poll, void *thr)
Interrupts a polling wait on the specified thread.
int ev_poll_wait(ev_poll_t *poll, int timeout)
Waits for at most timeout milliseconds while polling for new events.
This header file is part of the event library; it contains the abstract task executor interface.
void ev_exec_run(ev_exec_t *exec, struct ev_task *task)
Invokes the task function in *task as if the task is being executed by *exec.
#define _Thread_local
An object whose identifier is declared with the storage-class specifier _Thread_local has thread stor...
size_t ev_future_cancel(ev_future_t *future, struct ev_task *task)
Cancels the specified task submitted with ev_future_submit(), if it has not yet been scheduled for ex...
void ev_future_submit(ev_future_t *future, struct ev_task *task)
Submits a task to be executed once the specified future is ready.
void ev_future_release(ev_future_t *future)
Releases a reference to a future.
ev_future_t * ev_future_acquire(ev_future_t *future)
Acquires a reference to a future.
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.
int timespec_get(struct timespec *ts, int base)
Sets the interval at ts to hold the current calendar time based on the specified time base.
#define TIME_UTC
An integer constant greater than 0 that designates the UTC time base.
ev_loop_t * ev_loop_create(ev_poll_t *poll, size_t npoll, int poll_task)
Creates a new polling event loop.
size_t ev_loop_wait_one(ev_loop_t *loop, ev_future_t *future)
If the event loop has pending tasks, runs a single task.
void ev_loop_destroy(ev_loop_t *loop)
Destroys a polling event loop.
void * ev_loop_self(void)
Returns the identifier of the calling thread.
#define LELY_EV_LOOP_CTX_MAX_UNUSED
The maximum number of unused contexts per event loop.
int ev_loop_kill(ev_loop_t *loop, void *thr_)
Interrupts an event loop running on the specified thread.
ev_poll_t * ev_loop_get_poll(const ev_loop_t *loop)
Returns a pointer to the polling instance used by the event loop, or NULL if the loop does not poll.
ev_exec_t * ev_loop_get_exec(const ev_loop_t *loop)
Returns a pointer to the executor corresponding to the event loop.
void ev_loop_stop(ev_loop_t *loop)
Stops the event loop.
size_t ev_loop_wait(ev_loop_t *loop, ev_future_t *future)
Equivalent to.
size_t ev_loop_wait_one_until(ev_loop_t *loop, ev_future_t *future, const struct timespec *abs_time)
If the event loop has pending tasks, runs a single task.
size_t ev_loop_wait_until(ev_loop_t *loop, ev_future_t *future, const struct timespec *abs_time)
Equivalent to.
int ev_loop_stopped(const ev_loop_t *loop)
Returns 1 if the event loop is stopped, and 0 if not.
void ev_loop_restart(ev_loop_t *loop)
Restarts an event loop.
This header file is part of the event library; it contains the polling event loop declarations.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
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.
struct slnode * sllist_first(const struct sllist *list)
Returns a pointer to the first node in a singly-linked list.
This is the internal header file of the event library.
This header file is part of the event library; it contains the standard executor declarations.
This header file is part of the C11 and POSIX compatibility library; it includes <stdatomic....
@ memory_order_release
A store operation performs a release operation on the affected memory location.
@ memory_order_relaxed
No operation orders memory.
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
#define atomic_fetch_add_explicit(object, operand, order)
Atomically replaces the value at object with *object + operand.
#define atomic_load_explicit(object, order)
Atomically returns the value at object.
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
#define atomic_init(obj, value)
Initializes the atomic object at obj with the value value.
#define atomic_fetch_sub_explicit(object, operand, order)
Atomically replaces the value at object with *object - operand.
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....
A node in a doubly-linked list.
unsigned polling
A flag indicating if a thread is polling.
unsigned ready
A flag indicating if future is ready.
struct ev_loop_ctx * next
A pointer to the next context in the list of running or unused contexts.
struct dlnode node
The node of this context in the list of waiting or polling contexts.
ev_future_t * future
The future on which the loop is waiting.
struct ev_task task
The task to be executed once the future is ready.
void * thr
The thread identifier of the polling instance.
cnd_t cond
The condition variable used by threads to wait for a task to be submitted to the event loop or for th...
ev_loop_t * loop
A pointer to the event loop managing this context.
size_t refcnt
The number of references to this context.
unsigned waiting
A flag indicating if a thread is waiting on cond.
int * pstopped
The address of the stopped flag of the thread.
struct ev_loop_ctx * ctx
A pointer to the event loop context for this thread.
int stopped
A flag used to interrupt the event loop on this thread.
size_t npoll
The number of threads allowed to poll simultaneously.
struct ev_task task
The task used to trigger polling.
const struct ev_std_exec_impl_vtbl * impl_vptr
A pointer to the virtual table containing the interface used by the standard executor (exec).
struct dllist polling
The list of polling contexts.
struct dllist waiting
The list of waiting contexts.
struct ev_std_exec exec
The executor corresponding to the event loop.
struct ev_loop_ctx * unused
The list of unused contexts.
atomic_size_t ntasks
The number of pending tasks.
size_t nunused
The number of unused contexts.
ev_poll_t * poll
A pointer to the interface used to poll for events (can be NULL).
mtx_t mtx
The mutex protecting the task queue.
int stopped
A flag specifying whether the event loop is stopped.
size_t npolling
The number of polling contexts.
struct sllist queue
The queue of pending tasks.
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
A node in a singly-linked list.
struct slnode * next
A pointer to the next node in the 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 cnd_init(cnd_t *cond)
Creates a condition variable.
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
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.
pthread_cond_t cnd_t
A complete object type that holds an identifier for a condition variable.
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
int cnd_wait(cnd_t *cond, mtx_t *mtx)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
@ thrd_timedout
Indicates that the time specified in the call was reached without acquiring the requested resource.
@ thrd_success
Indicates that the requested operation succeeded.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
int cnd_signal(cnd_t *cond)
Unblocks one of the threads that are blocked on the condition variable at cond at the time of the cal...
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
This header file is part of the utilities library; it contains the time function declarations.
int timespec_cmp(const void *p1, const void *p2)
Compares two times.
int_least64_t timespec_diff_msec(const struct timespec *t1, const struct timespec *t2)
Returns the time difference (in milliseconds) between *t1 and *t2.