30 #define LELY_EV_LOOP_INLINE extern inline
43 #ifndef LELY_EV_LOOP_CTX_MAX_UNUSED
45 #define LELY_EV_LOOP_CTX_MAX_UNUSED 16
88 static void ev_loop_ctx_task_func(
struct ev_task *
task);
91 static void ev_loop_ctx_free(
struct ev_loop_ctx *ctx);
93 static void ev_loop_ctx_release(
struct ev_loop_ctx *ctx);
97 static void ev_loop_ctx_destroy(
struct ev_loop_ctx *ctx);
101 static size_t ev_loop_ctx_wait_one_until(
struct ev_loop_ctx **pctx,
103 const struct timespec *abs_time);
105 static int ev_loop_ctx_kill(
struct ev_loop_ctx *ctx,
int stop);
121 static void ev_loop_std_exec_impl_on_task_init(ev_std_exec_impl_t *impl);
122 static void ev_loop_std_exec_impl_on_task_fini(ev_std_exec_impl_t *impl);
123 static void ev_loop_std_exec_impl_post(
124 ev_std_exec_impl_t *impl,
struct ev_task *task);
125 static size_t ev_loop_std_exec_impl_abort(
126 ev_std_exec_impl_t *impl,
struct ev_task *task);
130 &ev_loop_std_exec_impl_on_task_init,
131 &ev_loop_std_exec_impl_on_task_fini,
132 &ev_loop_std_exec_impl_post,
133 &ev_loop_std_exec_impl_abort
167 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
169 #elif _WIN64 && !defined(__MINGW32__)
171 #elif _WIN32 && !defined(__MINGW32__)
195 static inline ev_loop_t *ev_loop_from_impl(
const ev_std_exec_impl_t *impl);
214 ev_loop_free(
void *ptr)
238 if (loop->
poll && poll_task)
241 #if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
244 atomic_init(&loop->
ntasks, 0);
269 ev_loop_ctx_free(ctx);
345 ev_loop_do_stop(
loop);
385 while (ev_loop_ctx_wait_one(&ctx,
loop,
future))
387 ev_loop_ctx_destroy(ctx);
393 const struct timespec *abs_time)
397 while (ev_loop_ctx_wait_one_until(&ctx,
loop,
future, abs_time))
399 ev_loop_ctx_destroy(ctx);
407 size_t n = ev_loop_ctx_wait_one(&ctx,
loop,
future);
408 ev_loop_ctx_destroy(ctx);
414 const struct timespec *abs_time)
417 size_t n = ev_loop_ctx_wait_one_until(&ctx,
loop,
future, abs_time);
418 ev_loop_ctx_destroy(ctx);
446 if ((result = ev_loop_ctx_kill(thr->
ctx, 1)) == -1)
460 ev_loop_ctx_task_func(
struct ev_task *task)
475 ev_loop_ctx_kill(ctx, 0);
480 ev_loop_ctx_release(ctx);
484 ev_loop_ctx_alloc(
void)
491 goto error_malloc_ctx;
505 goto error_init_cond;
574 ev_loop_ctx_free(ctx);
598 ctx = ev_loop_ctx_alloc();
644 ev_loop_ctx_release(ctx);
649 ev_loop_ctx_wait_one(
667 if (ev_loop_empty(
loop) && !ev_loop_ntasks(
loop)
669 ev_loop_do_stop(
loop);
674 if (task && task == &loop->
task) {
699 ctx = *pctx = ev_loop_ctx_create(loop, future);
754 ev_loop_kill_any(loop, 1);
757 ev_loop_kill_any(loop, 0);
772 ev_future_t *future,
const struct timespec *abs_time)
778 #if LELY_NO_THREADS && LELY_NO_TIMEOUT
792 if (ev_loop_empty(
loop) && !ev_loop_ntasks(
loop)
794 ev_loop_do_stop(
loop);
799 if (task && task == &loop->
task) {
824 ctx = *pctx = ev_loop_ctx_create(loop, future);
851 if (empty && abs_time) {
852 struct timespec now = { 0, 0 };
863 else if (msec > INT_MAX)
881 #if !LELY_NO_THREADS && !LELY_NO_TIMEOUT
882 }
else if (abs_time) {
887 &ctx->
cond, &loop->
mtx, abs_time);
907 ev_loop_kill_any(loop, 1);
910 ev_loop_kill_any(loop, 0);
922 ev_loop_ctx_kill(
struct ev_loop_ctx *ctx,
int stop)
944 ev_loop_std_exec_impl_on_task_init(ev_std_exec_impl_t *impl)
946 ev_loop_t *loop = ev_loop_from_impl(impl);
948 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
950 #elif _WIN64 && !defined(__MINGW32__)
951 InterlockedIncrementNoFence64(&loop->
ntasks);
952 #elif _WIN32 && !defined(__MINGW32__)
953 InterlockedIncrementNoFence(&loop->
ntasks);
955 atomic_fetch_add_explicit(&loop->
ntasks, 1, memory_order_relaxed);
960 ev_loop_std_exec_impl_on_task_fini(ev_std_exec_impl_t *impl)
962 ev_loop_t *loop = ev_loop_from_impl(impl);
964 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
966 #elif _WIN64 && !defined(__MINGW32__)
967 if (!InterlockedDecrementRelease64(&loop->
ntasks)) {
969 #elif _WIN32 && !defined(__MINGW32__)
970 if (!InterlockedDecrementRelease(&loop->
ntasks)) {
973 if (atomic_fetch_sub_explicit(&loop->
ntasks, 1, memory_order_release)
975 atomic_thread_fence(memory_order_acquire);
980 if (ev_loop_empty(loop))
981 ev_loop_do_stop(loop);
989 ev_loop_std_exec_impl_post(ev_std_exec_impl_t *impl,
struct ev_task *task)
991 ev_loop_t *loop = ev_loop_from_impl(impl);
1000 ev_loop_kill_any(loop, 1);
1001 #if !LELY_NO_THREADS
1007 ev_loop_std_exec_impl_abort(ev_std_exec_impl_t *impl,
struct ev_task *task)
1009 ev_loop_t *loop = ev_loop_from_impl(impl);
1014 #if !LELY_NO_THREADS
1031 #if !LELY_NO_THREADS
1042 ev_loop_from_impl(
const ev_std_exec_impl_t *impl)
1058 return node == &loop->
task._node && node->
next == NULL;
1066 #if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
1069 return atomic_load_explicit(
1070 (atomic_size_t *)&loop->
ntasks, memory_order_relaxed);
1081 #if !LELY_NO_THREADS
1085 ev_loop_ctx_kill(ctx, 1);
1091 ev_loop_ctx_kill(ctx, 1);
1102 #if !LELY_NO_THREADS
1106 return ev_loop_ctx_kill(ctx, 0);
1112 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.
ev_future_t * ev_future_acquire(ev_future_t *future)
Acquires a reference to a future.
void ev_future_release(ev_future_t *future)
Releases 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_exec_t * ev_loop_get_exec(const ev_loop_t *loop)
Returns a pointer to the executor corresponding to the 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.
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.
#define LELY_EV_LOOP_CTX_MAX_UNUSED
The maximum number of unused contexts per event loop.
ev_loop_t * ev_loop_create(ev_poll_t *poll, size_t npoll, int poll_task)
Creates a new polling event loop.
void * ev_loop_self(void)
Returns the identifier of the calling thread.
int ev_loop_kill(ev_loop_t *loop, void *thr_)
Interrupts an event loop running on the specified thread.
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....
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 <stdio....
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.
size_t ntasks
The number of pending tasks.
struct ev_std_exec exec
The executor corresponding to the event loop.
struct ev_loop_ctx * unused
The list of unused contexts.
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.