Lely core libraries
2.3.4
|
Go to the documentation of this file.
33 #define LELY_EV_LOOP_INLINE extern inline
46 #ifndef LELY_EV_LOOP_CTX_MAX_UNUSED
47 #define LELY_EV_LOOP_CTX_MAX_UNUSED 16
91 static void ev_loop_ctx_task_func(
struct ev_task *
task);
94 static void ev_loop_ctx_free(
struct ev_loop_ctx *ctx);
96 static void ev_loop_ctx_release(
struct ev_loop_ctx *ctx);
100 static void ev_loop_ctx_destroy(
struct ev_loop_ctx *ctx);
104 static size_t ev_loop_ctx_wait_one_until(
struct ev_loop_ctx **pctx,
106 const struct timespec *abs_time);
108 static int ev_loop_ctx_kill(
struct ev_loop_ctx *ctx,
int stop);
124 static void ev_loop_std_exec_impl_on_task_init(ev_std_exec_impl_t *impl);
125 static void ev_loop_std_exec_impl_on_task_fini(ev_std_exec_impl_t *impl);
126 static void ev_loop_std_exec_impl_post(
127 ev_std_exec_impl_t *impl,
struct ev_task *task);
128 static 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__)
198 static inline ev_loop_t *ev_loop_from_impl(
const ev_std_exec_impl_t *impl);
219 ev_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)
465 ev_loop_ctx_task_func(
struct ev_task *task)
480 ev_loop_ctx_kill(ctx, 0);
485 ev_loop_ctx_release(ctx);
489 ev_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);
662 ev_loop_ctx_wait_one(
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)) {
748 #else // !LELY_NO_THREADS
757 #endif // !LELY_NO_THREADS
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)
877 #endif // !LELY_NO_TIMEOUT
892 #if !LELY_NO_THREADS && !LELY_NO_TIMEOUT
893 }
else if (abs_time) {
898 &ctx->
cond, &loop->
mtx, abs_time);
906 #endif // !LELY_NO_THREADS
918 ev_loop_kill_any(loop, 1);
921 ev_loop_kill_any(loop, 0);
933 ev_loop_ctx_kill(
struct ev_loop_ctx *ctx,
int stop)
955 ev_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);
971 ev_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);
1000 ev_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);
1005 #if !LELY_NO_THREADS
1011 ev_loop_kill_any(loop, 1);
1012 #if !LELY_NO_THREADS
1018 ev_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);
1025 #if !LELY_NO_THREADS
1042 #if !LELY_NO_THREADS
1053 ev_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__))
1092 #if !LELY_NO_THREADS
1096 ev_loop_ctx_kill(ctx, 1);
1102 ev_loop_ctx_kill(ctx, 1);
1113 #if !LELY_NO_THREADS
1117 return ev_loop_ctx_kill(ctx, 0);
1123 return ev_loop_ctx_kill(ctx, 0);
1128 #endif // !LELY_NO_MALLOC
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...
size_t refcnt
The number of references to this context.
void dllist_init(struct dllist *list)
Initializes 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 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.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
@ memory_order_relaxed
No operation orders memory.
int stopped
A flag specifying whether the event loop is stopped.
void ev_future_submit(ev_future_t *future, struct ev_task *task)
Submits a task to be executed once the specified future is ready.
struct slnode * sllist_first(const struct sllist *list)
Returns a pointer to the first node in a singly-linked list.
void dllist_remove(struct dllist *list, struct dlnode *node)
Removes a node from a doubly-linked list.
int * pstopped
The address of the stopped flag of the thread.
struct slnode * next
A pointer to the next node in the list.
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.
struct ev_loop_ctx * ctx
A pointer to the event loop context for this thread.
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
#define atomic_init(obj, value)
Initializes the atomic object at obj with the value value.
#define dllist_foreach(list, node)
Iterates in order over each node in a doubly-linked list.
void ev_loop_destroy(ev_loop_t *loop)
Destroys a polling event loop.
size_t ev_loop_wait(ev_loop_t *loop, ev_future_t *future)
Equivalent to.
void ev_loop_stop(ev_loop_t *loop)
Stops the event loop.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
int timespec_cmp(const void *p1, const void *p2)
Compares two times.
void * ev_loop_self(void)
Returns the identifier of the calling thread.
@ memory_order_release
A store operation performs a release operation on the affected memory location.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
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.
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...
struct ev_std_exec exec
The executor corresponding to the event loop.
int ev_loop_kill(ev_loop_t *loop, void *thr_)
Interrupts an event loop running on the specified thread.
ev_future_t * ev_future_acquire(ev_future_t *future)
Acquires a reference to a future.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
pthread_cond_t cnd_t
A complete object type that holds an identifier for a condition variable.
void ev_loop_restart(ev_loop_t *loop)
Restarts an event loop.
@ thrd_success
Indicates that the requested operation succeeded.
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...
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 nunused
The number of unused contexts.
const struct ev_std_exec_impl_vtbl * impl_vptr
A pointer to the virtual table containing the interface used by the standard executor (exec).
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
struct dlnode node
The node of this context in the list of waiting or polling contexts.
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.
struct sllist queue
The queue of pending tasks.
void ev_future_release(ev_future_t *future)
Releases a reference to a future.
size_t npolling
The number of polling contexts.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
unsigned ready
A flag indicating if future is ready.
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...
cnd_t cond
The condition variable used by threads to wait for a task to be submitted to the event loop or for th...
struct ev_loop_ctx * next
A pointer to the next context in the list of running or unused contexts.
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
void * thr
The thread identifier of the polling instance.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
#define atomic_fetch_add_explicit(object, operand, order)
Atomically replaces the value at object with *object + operand.
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
@ thrd_timedout
Indicates that the time specified in the call was reached without acquiring the requested resource.
int cnd_init(cnd_t *cond)
Creates a condition variable.
struct dllist polling
The list of polling contexts.
size_t npoll
The number of threads allowed to poll simultaneously.
ev_poll_t * poll
A pointer to the interface used to poll for events (can be NULL).
#define LELY_EV_LOOP_CTX_MAX_UNUSED
The maximum number of unused contexts per event loop.
struct ev_task task
The task to be executed once the future is ready.
int dllist_empty(const struct dllist *list)
Returns 1 if the doubly-linked list is empty, and 0 if not.
unsigned waiting
A flag indicating if a thread is waiting on cond.
int ev_poll_wait(ev_poll_t *poll, int timeout)
Waits for at most timeout milliseconds while polling for new events.
atomic_size_t ntasks
The number of pending tasks.
unsigned polling
A flag indicating if a thread is polling.
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.
struct ev_task task
The task used to trigger polling.
size_t ev_loop_wait_until(ev_loop_t *loop, ev_future_t *future, const struct timespec *abs_time)
Equivalent to.
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.
A node in a doubly-linked list.
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
ev_future_t * future
The future on which the loop is waiting.
int_least64_t timespec_diff_msec(const struct timespec *t1, const struct timespec *t2)
Returns the time difference (in milliseconds) between *t1 and *t2.
int stopped
A flag used to interrupt the event loop on this 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.
void * ev_poll_self(const ev_poll_t *poll)
Returns the identifier of the calling thread.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
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.
@ ERRNUM_TIMEDOUT
Connection timed out.
#define _Thread_local
An object whose identifier is declared with the storage-class specifier _Thread_local has thread stor...
struct ev_loop_ctx * unused
The list of unused contexts.
#define atomic_fetch_sub_explicit(object, operand, order)
Atomically replaces the value at object with *object - operand.
int ev_loop_stopped(const ev_loop_t *loop)
Returns 1 if the event loop is stopped, and 0 if not.
ev_loop_t * ev_loop_create(ev_poll_t *poll, size_t npoll, int poll_task)
Creates a new polling event loop.
A node in a singly-linked list.
struct dllist waiting
The list of waiting contexts.
mtx_t mtx
The mutex protecting the task queue.
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
ev_loop_t * loop
A pointer to the event loop managing this context.
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:
#define atomic_load_explicit(object, order)
Atomically returns the value at object.
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.