Lely core libraries
2.2.5
|
Go to the documentation of this file.
30 #define LELY_EV_LOOP_INLINE extern inline
43 #ifndef LELY_EV_LOOP_CTX_MAX_UNUSED
44 #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);
735 #else // !LELY_NO_THREADS
744 #endif // !LELY_NO_THREADS
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)
866 #endif // !LELY_NO_TIMEOUT
881 #if !LELY_NO_THREADS && !LELY_NO_TIMEOUT
882 }
else if (abs_time) {
887 &ctx->
cond, &loop->
mtx, abs_time);
895 #endif // !LELY_NO_THREADS
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);
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.
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 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.
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.
void * thr
The thread identifier of the polling instance.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
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.
#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.
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:
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.