45#ifndef LELY_EV_FUTURE_MAX
46#define LELY_EV_FUTURE_MAX MAX((LELY_VLA_SIZE_MAX / sizeof(ev_future_t *)), 1)
71#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
73#elif _WIN32 && !defined(__MINGW32__)
100#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
102#elif _WIN64 && !defined(__MINGW32__)
104#elif _WIN32 && !defined(__MINGW32__)
115#define EV_PROMISE_SIZE ALIGN(sizeof(ev_promise_t), _Alignof(max_align_t))
119static void *ev_promise_alloc(
size_t size);
120static void ev_promise_free(
void *ptr);
140static void ev_future_when_all_func(
struct ev_task *task);
151static void ev_future_when_any_func(
struct ev_task *task);
174 ev_promise_free(promise);
184#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
186#elif _WIN64 && !defined(__MINGW32__)
187 InterlockedIncrementNoFence64(&promise->
refcnt);
188#elif _WIN32 && !defined(__MINGW32__)
189 InterlockedIncrementNoFence(&promise->
refcnt);
202#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
204#elif _WIN64 && !defined(__MINGW32__)
205 if (!InterlockedDecrementRelease64(&promise->
refcnt)) {
207#elif _WIN32 && !defined(__MINGW32__)
208 if (!InterlockedDecrementRelease(&promise->
refcnt)) {
215 ev_promise_fini(promise);
216 ev_promise_free(promise);
225#if LELY_NO_THREADS || LELY_NO_ATOMICS
226 return promise->
refcnt == 1;
238 return promise ? (
char *)promise + EV_PROMISE_SIZE : NULL;
256#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
261#elif _WIN32 && !defined(__MINGW32__)
279#if LELY_NO_THREADS || LELY_NO_ATOMICS
286 future->
value = value;
297#if LELY_NO_THREADS || LELY_NO_ATOMICS
345#if LELY_NO_THREADS || LELY_NO_ATOMICS
360 return future->
value;
398 ev_future_pop(future, &queue, task);
411 ev_future_pop(future, &queue, task);
420 va_start(ap, future);
434 for (n = 0; arg; n++, arg = va_arg(aq,
ev_future_t *))
437 return ev_future_when_all_nv(exec, n, future, ap);
444 assert(!n || futures);
457 exec, &ev_future_when_all_func);
459 if ((when->n = n) != 0) {
460 for (
size_t i = 0; i < n; i++) {
479 va_start(ap, future);
493 for (n = 0; arg; n++, arg = va_arg(aq,
ev_future_t *))
496 return ev_future_when_any_nv(
exec, n, future, ap);
503 assert(!n || futures);
512 for (
size_t i = 0; i < n; i++) {
517 exec, &ev_future_when_any_func);
525#if LELY_NO_THREADS || LELY_NO_ATOMICS
526 assert(promise->
refcnt >= 2);
531#ifndef __clang_analyzer__
543#if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
549 future->
value = NULL;
600ev_promise_alloc(
size_t size)
603 void *ptr = calloc(1, EV_PROMISE_SIZE + size);
612ev_promise_free(
void *ptr)
622#if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
628 promise->
dtor = dtor;
630 if (!ev_future_init(&promise->
future))
644 ev_future_fini(&promise->
future);
648ev_future_when_all_nv(
651 if (n <= LELY_EV_FUTURE_MAX) {
652#if __STDC_NO_VLA__ || defined(_MSC_VER)
657 for (
size_t i = 0; i < n; i++) {
663 ev_future_t **futures = malloc(n *
sizeof(*futures));
670 for (
size_t i = 0; i < n; i++) {
687ev_future_when_all_func(
struct ev_task *task)
698 if (when->idx < when->n) {
703 for (
size_t i = when->idx; i < when->n; i++)
712ev_future_when_any_nv(
715 if (n <= LELY_EV_FUTURE_MAX) {
716#if __STDC_NO_VLA__ || defined(_MSC_VER)
721 for (
size_t i = 0; i < n; i++) {
727 ev_future_t **futures = malloc(n *
sizeof(*futures));
734 for (
size_t i = 0; i < n; i++) {
751ev_future_when_any_func(
struct ev_task *task)
This header file is part of the utilities library; it contains the native and platform-independent er...
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.
This header file is part of the event library; it contains the abstract task executor interface.
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.
ev_promise_t * ev_promise_acquire(ev_promise_t *promise)
Acquires a reference to a promise.
int ev_future_is_unique(const ev_future_t *future)
Returns 1 if future is the only reference to the future and no references to its associated promise a...
void ev_promise_release(ev_promise_t *promise)
Releases a reference to a promise.
ev_future_state
The state of a future.
@ EV_FUTURE_SETTING
The promise is in the process of being satisfied (i.e., ev_promise_set_acquire() has been invoked).
@ EV_FUTURE_READY
The future is ready (i.e., ev_promise_set_release() has been invoked).
@ EV_FUTURE_WAITING
The future is waiting.
ev_future_t * ev_promise_get_future(ev_promise_t *promise)
Returns (a reference to) a future associated with the specified promise.
int ev_promise_is_unique(const ev_promise_t *promise)
Returns 1 if promise is the only reference to the promise and no references to its associated future ...
size_t ev_future_abort(ev_future_t *future, struct ev_task *task)
Aborts the specified task submitted with ev_future_submit(), if it has not yet been scheduled for exe...
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...
ev_future_t * ev_future_when_all(ev_exec_t *exec, ev_future_t *future,...)
Equivalent to ev_future_when_all_n(), except that it accepts a variable number of arguments instead o...
int ev_promise_set(ev_promise_t *promise, void *value)
Satiesfies a promise, if it was not aready satisfied, and stores the specified value for retrieval by...
ev_future_t * ev_future_when_all_v(ev_exec_t *exec, ev_future_t *future, va_list ap)
Equivalent to ev_future_when_all(), except that it accepts a va_list instead of a variable number of ...
void ev_promise_set_release(ev_promise_t *promise, void *value)
Satisfies a promise prepared by ev_promise_set_acquire(), and stores the specified value for retrieva...
ev_future_t * ev_future_when_any_n(ev_exec_t *exec, size_t n, ev_future_t *const *futures)
Creates a future that becomes ready when at least one of the input futures becomes ready or is abando...
void * ev_promise_data(const ev_promise_t *promise)
Returns a pointer to the shared state of a promise.
ev_future_t * ev_future_when_all_n(ev_exec_t *exec, size_t n, ev_future_t *const *futures)
Creates a future that becomes ready when all of the input futures become ready or one of the input fu...
void * ev_future_get(const ev_future_t *future)
Returns the result of a ready future.
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.
ev_future_t * ev_future_when_any(ev_exec_t *exec, ev_future_t *future,...)
Equivalent to ev_future_when_any_n(), except that it accepts a variable number of arguments instead o...
ev_future_t * ev_future_when_any_v(ev_exec_t *exec, ev_future_t *future, va_list ap)
Equivalent to ev_future_when_any(), except that it accepts a va_list instead of a variable number of ...
ev_promise_t * ev_promise_create(size_t size, ev_promise_dtor_t *dtor)
Constructs a new promise with an optional empty shared state.
int ev_future_is_ready(const ev_future_t *future)
Checks if the specified future is ready, i.e., its associated promise has been satisfied.
int ev_promise_set_acquire(ev_promise_t *promise)
Checks if the specified promise can be satisfied by the caller and, if so, prevents others from satis...
This header file is part of the event library; it contains the futures and promises declarations.
void ev_promise_dtor_t(void *ptr)
The type of the function used to destroy (but not free) the shared state of a promise once the last r...
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.
This is the internal header file of the event library.
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_acq_rel
A load operation performs an acquire operation on the affected memory location, and a store operation...
@ 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_compare_exchange_strong_explicit(object, expected, desired, success, failure)
Atomically compares the value at object for equality with that at expected, and if true,...
#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_load(object)
Equivalent to atomic_load_explicit(object, memory_order_seq_cst).
#define atomic_store_explicit(object, desired, order)
Atomically replaces the value at object with the value of desired.
#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 <stddef....
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....
atomic_int state
The state of the future.
void * value
The value of the future, set by ev_promise_set_release().
struct sllist queue
The queue of tasks submitted by ev_future_submit() waiting for the future to become ready.
atomic_size_t refcnt
The number of references to this promise or its future.
ev_promise_dtor_t * dtor
The (destructor) function invoked when this struct is reclaimed.
struct ev_future future
The future used to monitor if the promise has been satisfied.
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
This header file is part of the event library; it contains the task declarations.
size_t ev_task_queue_abort(struct sllist *queue)
Aborts the tasks in queue by invoking ev_exec_on_task_fini() for each of them.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
size_t ev_task_queue_post(struct sllist *queue)
Post the tasks in queue to their respective executors and invokes ev_exec_on_task_fini() for each of ...
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.
@ 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.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.