42 #ifndef LELY_EV_FUTURE_MAX 43 #define LELY_EV_FUTURE_MAX MAX((LELY_VLA_SIZE_MAX / sizeof(ev_future_t *)), 1) 68 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__))) 70 #elif _WIN32 && !defined(__MINGW32__) 97 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__))) 99 #elif _WIN64 && !defined(__MINGW32__) 100 volatile LONGLONG refcnt;
101 #elif _WIN32 && !defined(__MINGW32__) 102 volatile LONG refcnt;
112 #define EV_PROMISE_SIZE ALIGN(sizeof(ev_promise_t), _Alignof(max_align_t)) 116 static void *ev_promise_alloc(
size_t size);
117 static void ev_promise_free(
void *ptr);
137 static void ev_future_when_all_func(
struct ev_task *task);
148 static void ev_future_when_any_func(
struct ev_task *task);
171 ev_promise_free(promise);
181 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__))) 183 #elif _WIN64 && !defined(__MINGW32__) 184 InterlockedIncrementNoFence64(&promise->
refcnt);
185 #elif _WIN32 && !defined(__MINGW32__) 186 InterlockedIncrementNoFence(&promise->
refcnt);
188 atomic_fetch_add_explicit(
189 &promise->
refcnt, 1, memory_order_relaxed);
199 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__))) 201 #elif _WIN64 && !defined(__MINGW32__) 202 if (!InterlockedDecrementRelease64(&promise->
refcnt)) {
204 #elif _WIN32 && !defined(__MINGW32__) 205 if (!InterlockedDecrementRelease(&promise->
refcnt)) {
208 if (atomic_fetch_sub_explicit(&promise->
refcnt, 1, memory_order_release)
210 atomic_thread_fence(memory_order_acquire);
212 ev_promise_fini(promise);
213 ev_promise_free(promise);
222 #if LELY_NO_THREADS || LELY_NO_ATOMICS 223 return promise->
refcnt == 1;
226 return atomic_load_explicit((atomic_size_t *)&promise->
refcnt,
227 memory_order_relaxed) == 1;
235 return promise ? (
char *)promise + EV_PROMISE_SIZE : NULL;
253 #if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__))) 258 #elif _WIN32 && !defined(__MINGW32__) 265 return atomic_compare_exchange_strong_explicit(&future->
state, &state,
267 memory_order_acquire);
276 #if LELY_NO_THREADS || LELY_NO_ATOMICS 279 assert(atomic_load_explicit(&future->
state, memory_order_acquire)
294 #if LELY_NO_THREADS || LELY_NO_ATOMICS 297 atomic_store_explicit(
340 #if LELY_NO_THREADS || LELY_NO_ATOMICS 344 return atomic_load_explicit((atomic_int *)&future->
state,
356 return future->
value;
393 ev_future_pop(future, &queue, task);
406 ev_future_pop(future, &queue, task);
415 va_start(ap, future);
429 for (n = 0; arg; n++, arg = va_arg(aq,
ev_future_t *))
432 return ev_future_when_all_nv(exec, n, future, ap);
439 assert(!n || futures);
450 when->promise = promise;
451 when->task = (
struct ev_task)EV_TASK_INIT(
452 exec, &ev_future_when_all_func);
455 for (
size_t i = 0; i < n; i++) {
471 va_start(ap, future);
485 for (n = 0; arg; n++, arg = va_arg(aq,
ev_future_t *))
488 return ev_future_when_any_nv(exec, n, future, ap);
495 assert(!n || futures);
504 for (
size_t i = 0; i < n; i++) {
508 wait[i].task = (
struct ev_task)EV_TASK_INIT(
509 exec, &ev_future_when_any_func);
517 #if LELY_NO_THREADS || LELY_NO_ATOMICS 518 assert(promise->
refcnt >= 2);
520 assert(atomic_load(&promise->
refcnt) >= 2);
523 #ifndef __clang_analyzer__ 535 #if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__)) 541 future->
value = NULL;
592 ev_promise_alloc(
size_t size)
594 void *ptr = calloc(1, EV_PROMISE_SIZE + size);
601 ev_promise_free(
void *ptr)
611 #if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__)) 614 atomic_init(&promise->
refcnt, 1);
617 promise->
dtor = dtor;
619 if (!ev_future_init(&promise->
future))
630 ev_future_fini(&promise->
future);
637 ev_future_when_all_nv(
640 if (n <= LELY_EV_FUTURE_MAX) {
641 #if __STDC_NO_VLA__ || defined(_MSC_VER) 646 for (
size_t i = 0; i < n; i++) {
652 ev_future_t **futures = malloc(n *
sizeof(*futures));
657 for (
size_t i = 0; i < n; i++) {
670 ev_future_when_all_func(
struct ev_task *task)
681 if (when->idx < when->n) {
686 for (
size_t i = when->idx; i < when->n; i++)
695 ev_future_when_any_nv(
698 if (n <= LELY_EV_FUTURE_MAX) {
699 #if __STDC_NO_VLA__ || defined(_MSC_VER) 704 for (
size_t i = 0; i < n; i++) {
710 ev_future_t **futures = malloc(n *
sizeof(*futures));
715 for (
size_t i = 0; i < n; i++) {
728 ev_future_when_any_func(
struct ev_task *task)
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
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...
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 sllist queue
The queue of tasks submitted by ev_future_submit() waiting for the future to become ready...
atomic_int state
The state of the future.
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.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
void * ev_future_get(const ev_future_t *future)
Returns the result of a ready future.
void * value
The value of the future, set by ev_promise_set_release().
Indicates that the requested operation succeeded.
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...
void ev_exec_on_task_fini(ev_exec_t *exec)
Undoes the effect of a previous call to ev_exec_on_task_init().
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.
A mutex type that supports neither timeout nor test and return.
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 ...
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
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...
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
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...
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...
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
ev_future_state
The state of a future.
This header file is part of the C11 and POSIX compatibility library; it includes <threads.h>, if it exists, and defines any missing functionality.
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
The promise is in the process of being satisfied (i.e., ev_promise_set_acquire() has been invoked)...
This header file is part of the utilities library; it contains the native and platform-independent er...
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
This header file is part of the C11 and POSIX compatibility library; it includes <stdatomic.h>, if it exists, and defines any missing functionality.
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.
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_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...
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
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...
struct ev_future future
The future used to monitor if the promise has been satisfied.
This header file is part of the C11 and POSIX compatibility library; it includes <stddef.h> and defines any missing functionality.
void ev_future_submit(ev_future_t *future, struct ev_task *task)
Submits a task to be executed once the specified future is ready.
atomic_size_t refcnt
The number of references to this promise or its future.
void ev_future_release(ev_future_t *future)
Releases a reference to a future.
This header file is part of the event library; it contains the futures and promises declarations...
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
void * ev_promise_data(const ev_promise_t *promise)
Returns a pointer to the shared state of a promise.
void ev_promise_release(ev_promise_t *promise)
Releases a reference to a promise.
ev_promise_t * ev_promise_create(size_t size, ev_promise_dtor_t *dtor)
Constructs a new promise with an optional empty shared state.
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 <stdint.h> and defines any missing functionality.
This header file is part of the event library; it contains the task declarations. ...
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
This header file is part of the event library; it contains the abstract task executor interface...
ev_future_t * ev_promise_get_future(ev_promise_t *promise)
Returns (a reference to) a future associated with the specified 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...
ev_promise_t * ev_promise_acquire(ev_promise_t *promise)
Acquires a reference to a promise.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
This is the internal header file of the event library.
ev_future_t * ev_future_acquire(ev_future_t *future)
Acquires a reference to a future.
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_dtor_t * dtor
The (destructor) function invoked when this struct is reclaimed.
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...
This is the public header file of the utilities library.
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 ...
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: ...
The future is ready (i.e., ev_promise_set_release() has been invoked).