Lely core libraries 2.3.4
future.c
Go to the documentation of this file.
1
24#include "ev.h"
25
26#if !LELY_NO_MALLOC
27
28#if !LELY_NO_THREADS
29#include <lely/libc/stdatomic.h>
30#endif
31#include <lely/libc/stddef.h>
32#if !LELY_NO_THREADS
33#include <lely/libc/threads.h>
34#endif
35#include <lely/ev/exec.h>
36#include <lely/ev/future.h>
37#include <lely/ev/task.h>
38#include <lely/util/errnum.h>
39#include <lely/util/util.h>
40
41#include <assert.h>
42#include <stdint.h>
43#include <stdlib.h>
44
45#ifndef LELY_EV_FUTURE_MAX
46#define LELY_EV_FUTURE_MAX MAX((LELY_VLA_SIZE_MAX / sizeof(ev_future_t *)), 1)
47#endif
48
63};
64
66struct ev_future {
71#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
72 int state;
73#elif _WIN32 && !defined(__MINGW32__)
74 volatile LONG state;
75#else
76 atomic_int state;
77#endif
79 void *value;
80#if !LELY_NO_THREADS
82 mtx_t mtx;
83#endif
88 struct sllist queue;
89};
90
91static ev_future_t *ev_future_init(ev_future_t *future);
92static void ev_future_fini(ev_future_t *future);
93
95struct ev_promise {
100#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
101 size_t refcnt;
102#elif _WIN64 && !defined(__MINGW32__)
103 volatile LONGLONG refcnt;
104#elif _WIN32 && !defined(__MINGW32__)
105 volatile LONG refcnt;
106#else
107 atomic_size_t refcnt;
108#endif
113};
114
115#define EV_PROMISE_SIZE ALIGN(sizeof(ev_promise_t), _Alignof(max_align_t))
116
117static inline ev_promise_t *ev_promise_from_future(const ev_future_t *future);
118
119static void *ev_promise_alloc(size_t size);
120static void ev_promise_free(void *ptr);
121
122static ev_promise_t *ev_promise_init(
123 ev_promise_t *promise, ev_promise_dtor_t *dtor);
124static void ev_promise_fini(ev_promise_t *promise);
125
126static void ev_future_pop(ev_future_t *future, struct sllist *queue,
127 struct ev_task *task);
128
129static ev_future_t *ev_future_when_all_nv(
130 ev_exec_t *exec, size_t n, ev_future_t *future, va_list ap);
131
133 size_t idx;
134 ev_promise_t *promise;
135 struct ev_task task;
136 size_t n;
137 ev_future_t *futures[];
138};
139
140static void ev_future_when_all_func(struct ev_task *task);
141
142static ev_future_t *ev_future_when_any_nv(
143 ev_exec_t *exec, size_t n, ev_future_t *future, va_list ap);
144
146 size_t idx;
147 ev_promise_t *promise;
148 struct ev_task task;
149};
150
151static void ev_future_when_any_func(struct ev_task *task);
152
155{
156 int errc = 0;
157
158 ev_promise_t *promise = ev_promise_alloc(size);
159 if (!promise) {
160 errc = get_errc();
161 goto error_alloc;
162 }
163
164 ev_promise_t *tmp = ev_promise_init(promise, dtor);
165 if (!tmp) {
166 errc = get_errc();
167 goto error_init;
168 }
169 promise = tmp;
170
171 return promise;
172
173error_init:
174 ev_promise_free(promise);
175error_alloc:
176 set_errc(errc);
177 return NULL;
178}
179
182{
183 if (promise)
184#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
185 promise->refcnt++;
186#elif _WIN64 && !defined(__MINGW32__)
187 InterlockedIncrementNoFence64(&promise->refcnt);
188#elif _WIN32 && !defined(__MINGW32__)
189 InterlockedIncrementNoFence(&promise->refcnt);
190#else
192 &promise->refcnt, 1, memory_order_relaxed);
193#endif
194 return promise;
195}
196
197void
199{
200 if (!promise)
201 return;
202#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
203 if (!--promise->refcnt) {
204#elif _WIN64 && !defined(__MINGW32__)
205 if (!InterlockedDecrementRelease64(&promise->refcnt)) {
206 MemoryBarrier();
207#elif _WIN32 && !defined(__MINGW32__)
208 if (!InterlockedDecrementRelease(&promise->refcnt)) {
209 MemoryBarrier();
210#else
212 == 1) {
214#endif
215 ev_promise_fini(promise);
216 ev_promise_free(promise);
217 }
218}
219
220int
222{
223 assert(promise);
224
225#if LELY_NO_THREADS || LELY_NO_ATOMICS
226 return promise->refcnt == 1;
227#else
228 // clang-format off
229 return atomic_load_explicit((atomic_size_t *)&promise->refcnt,
231 // clang-format on
232#endif
233}
234
235void *
237{
238 return promise ? (char *)promise + EV_PROMISE_SIZE : NULL;
239}
240
241int
242ev_promise_set(ev_promise_t *promise, void *value)
243{
244 int result = ev_promise_set_acquire(promise);
245 if (result)
246 ev_promise_set_release(promise, value);
247 return result;
248}
249
250int
252{
253 assert(promise);
254 ev_future_t *future = &promise->future;
255
256#if LELY_NO_THREADS || (LELY_NO_ATOMICS && (!_WIN32 || defined(__MINGW32__)))
257 int result = future->state == EV_FUTURE_WAITING;
258 if (result)
259 future->state = EV_FUTURE_SETTING;
260 return result;
261#elif _WIN32 && !defined(__MINGW32__)
262 // clang-format off
263 return InterlockedCompareExchange(&future->state, EV_FUTURE_SETTING,
265 // clang-format on
266#else
267 int state = EV_FUTURE_WAITING;
268 return atomic_compare_exchange_strong_explicit(&future->state, &state,
271#endif
272}
273
274void
276{
277 assert(promise);
278 ev_future_t *future = &promise->future;
279#if LELY_NO_THREADS || LELY_NO_ATOMICS
280 assert(future->state == EV_FUTURE_SETTING);
281#else
284#endif
285
286 future->value = value;
287
288 struct sllist queue;
289 sllist_init(&queue);
290
291#if !LELY_NO_THREADS
292 mtx_lock(&future->mtx);
293#endif
294
295 sllist_append(&queue, &future->queue);
296
297#if LELY_NO_THREADS || LELY_NO_ATOMICS
298 future->state = EV_FUTURE_READY;
299#else
302#endif
303
304#if !LELY_NO_THREADS
305 mtx_unlock(&future->mtx);
306#endif
307
308 ev_task_queue_post(&queue);
309}
310
313{
314 assert(promise);
315
316 return ev_future_acquire(&promise->future);
317}
318
321{
322 if (future)
323 ev_promise_acquire(ev_promise_from_future(future));
324 return future;
325}
326
327void
329{
330 if (future)
331 ev_promise_release(ev_promise_from_future(future));
332}
333
334int
336{
337 return ev_promise_is_unique(ev_promise_from_future(future));
338}
339
340int
342{
343 assert(future);
344
345#if LELY_NO_THREADS || LELY_NO_ATOMICS
346 return future->state == EV_FUTURE_READY;
347#else
348 // clang-format off
349 return atomic_load_explicit((atomic_int *)&future->state,
351 // clang-format on
352#endif
353}
354
355void *
357{
358 assert(ev_future_is_ready(future));
359
360 return future->value;
361}
362
363void
365{
366 assert(future);
367 assert(task);
368 ev_exec_t *exec = task->exec;
369 assert(exec);
370
372
373#if !LELY_NO_THREADS
374 mtx_lock(&future->mtx);
375#endif
376 if (ev_future_is_ready(future)) {
377#if !LELY_NO_THREADS
378 mtx_unlock(&future->mtx);
379#endif
380 ev_exec_post(exec, task);
382 } else {
383 sllist_push_back(&future->queue, &task->_node);
384#if !LELY_NO_THREADS
385 mtx_unlock(&future->mtx);
386#endif
387 }
388}
389
390size_t
392{
393 assert(future);
394
395 struct sllist queue;
396 sllist_init(&queue);
397
398 ev_future_pop(future, &queue, task);
399
400 return ev_task_queue_post(&queue);
401}
402
403size_t
404ev_future_abort(ev_future_t *future, struct ev_task *task)
405{
406 assert(future);
407
408 struct sllist queue;
409 sllist_init(&queue);
410
411 ev_future_pop(future, &queue, task);
412
413 return ev_task_queue_abort(&queue);
414}
415
418{
419 va_list ap;
420 va_start(ap, future);
421 ev_future_t *result = ev_future_when_all_v(exec, future, ap);
422 va_end(ap);
423 return result;
424}
425
427ev_future_when_all_v(ev_exec_t *exec, ev_future_t *future, va_list ap)
428{
429 size_t n;
430 va_list aq;
431 va_copy(aq, ap);
432 ev_future_t *arg = future;
433 // NOLINTNEXTLINE(clang-analyzer-valist.Uninitialized)
434 for (n = 0; arg; n++, arg = va_arg(aq, ev_future_t *))
435 ;
436 va_end(aq);
437 return ev_future_when_all_nv(exec, n, future, ap);
438}
439
441ev_future_when_all_n(ev_exec_t *exec, size_t n, ev_future_t *const *futures)
442{
443 assert(exec);
444 assert(!n || futures);
445
447 sizeof(struct ev_future_when_all)
448 + n * sizeof(ev_future_t *),
449 NULL);
450 if (!promise)
451 return NULL;
452
453 struct ev_future_when_all *when = ev_promise_data(promise);
454 when->idx = 0;
455 when->promise = ev_promise_acquire(promise);
456 when->task = (struct ev_task)EV_TASK_INIT(
457 exec, &ev_future_when_all_func);
458
459 if ((when->n = n) != 0) {
460 for (size_t i = 0; i < n; i++) {
461 assert(futures[i]);
462 when->futures[i] = ev_future_acquire(futures[i]);
463 }
464 ev_future_submit(when->futures[0], &when->task);
465 } else {
466 ev_promise_set(promise, NULL);
467 ev_promise_release(promise);
468 }
469
470 ev_future_t *future = ev_promise_get_future(promise);
471 ev_promise_release(promise);
472 return future;
473}
474
477{
478 va_list ap;
479 va_start(ap, future);
480 ev_future_t *result = ev_future_when_any_v(exec, future, ap);
481 va_end(ap);
482 return result;
483}
484
487{
488 size_t n;
489 va_list aq;
490 va_copy(aq, ap);
491 ev_future_t *arg = future;
492 // NOLINTNEXTLINE(clang-analyzer-valist.Uninitialized)
493 for (n = 0; arg; n++, arg = va_arg(aq, ev_future_t *))
494 ;
495 va_end(aq);
496 return ev_future_when_any_nv(exec, n, future, ap);
497}
498
500ev_future_when_any_n(ev_exec_t *exec, size_t n, ev_future_t *const *futures)
501{
502 assert(exec);
503 assert(!n || futures);
504
506 n * sizeof(struct ev_future_when_any), NULL);
507 if (!promise)
508 return NULL;
509
510 if (n) {
511 struct ev_future_when_any *wait = ev_promise_data(promise);
512 for (size_t i = 0; i < n; i++) {
513 assert(futures[i]);
514 wait[i].idx = i;
515 wait[i].promise = ev_promise_acquire(promise);
516 wait[i].task = (struct ev_task)EV_TASK_INIT(
517 exec, &ev_future_when_any_func);
518 ev_future_submit(futures[i], &wait[i].task);
519 }
520 } else {
521 ev_promise_set(promise, NULL);
522 }
523
524 ev_future_t *future = ev_promise_get_future(promise);
525#if LELY_NO_THREADS || LELY_NO_ATOMICS
526 assert(promise->refcnt >= 2);
527#else
528 assert(atomic_load(&promise->refcnt) >= 2);
529#endif
530 // Prevent false positive in scan-build.
531#ifndef __clang_analyzer__
532 ev_promise_release(promise);
533#endif
534 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc)
535 return future;
536}
537
538static ev_future_t *
539ev_future_init(ev_future_t *future)
540{
541 assert(future);
542
543#if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
544 future->state = EV_FUTURE_WAITING;
545#else
547#endif
548
549 future->value = NULL;
550
551#if !LELY_NO_THREADS
552 if (mtx_init(&future->mtx, mtx_plain) != thrd_success)
553 return NULL;
554#endif
555
556 sllist_init(&future->queue);
557
558 return future;
559}
560
561static void
562ev_future_fini(ev_future_t *future)
563{
564 assert(future);
565
566 ev_task_queue_post(&future->queue);
567
568#if !LELY_NO_THREADS
569 mtx_destroy(&future->mtx);
570#endif
571}
572
573static void
574ev_future_pop(ev_future_t *future, struct sllist *queue, struct ev_task *task)
575{
576 assert(future);
577 assert(queue);
578
579#if !LELY_NO_THREADS
580 mtx_lock(&future->mtx);
581#endif
582 if (!task)
583 sllist_append(queue, &future->queue);
584 else if (sllist_remove(&future->queue, &task->_node))
585 sllist_push_back(queue, &task->_node);
586#if !LELY_NO_THREADS
587 mtx_unlock(&future->mtx);
588#endif
589}
590
591static inline ev_promise_t *
592ev_promise_from_future(const ev_future_t *future)
593{
594 assert(future);
595
596 return structof(future, ev_promise_t, future);
597}
598
599static void *
600ev_promise_alloc(size_t size)
601{
602 // cppcheck-suppress AssignmentAddressToInteger
603 void *ptr = calloc(1, EV_PROMISE_SIZE + size);
604#if !LELY_NO_ERRNO
605 if (!ptr)
606 set_errc(errno2c(errno));
607#endif
608 return ptr;
609}
610
611static void
612ev_promise_free(void *ptr)
613{
614 free(ptr);
615}
616
617static ev_promise_t *
618ev_promise_init(ev_promise_t *promise, ev_promise_dtor_t *dtor)
619{
620 assert(promise);
621
622#if LELY_NO_THREADS || LELY_NO_ATOMICS || (_WIN32 && !defined(__MINGW32__))
623 promise->refcnt = 1;
624#else
625 atomic_init(&promise->refcnt, 1);
626#endif
627
628 promise->dtor = dtor;
629
630 if (!ev_future_init(&promise->future))
631 return NULL;
632
633 return promise;
634}
635
636static void
637ev_promise_fini(ev_promise_t *promise)
638{
639 assert(promise);
640
641 if (promise->dtor)
642 promise->dtor(ev_promise_data(promise));
643
644 ev_future_fini(&promise->future);
645}
646
647static ev_future_t *
648ev_future_when_all_nv(
649 ev_exec_t *exec, size_t n, ev_future_t *future, va_list ap)
650{
651 if (n <= LELY_EV_FUTURE_MAX) {
652#if __STDC_NO_VLA__ || defined(_MSC_VER)
653 ev_future_t *futures[LELY_EV_FUTURE_MAX];
654#else
655 ev_future_t *futures[n ? n : 1];
656#endif
657 for (size_t i = 0; i < n; i++) {
658 futures[i] = future;
659 future = va_arg(ap, ev_future_t *);
660 }
661 return ev_future_when_all_n(exec, n, futures);
662 } else {
663 ev_future_t **futures = malloc(n * sizeof(*futures));
664 if (!futures) {
665#if !LELY_NO_ERRNO
666 set_errc(errno2c(errno));
667#endif
668 return NULL;
669 }
670 for (size_t i = 0; i < n; i++) {
671 futures[i] = future;
672 future = va_arg(ap, ev_future_t *);
673 }
674 ev_future_t *result = ev_future_when_all_n(exec, n, futures);
675#if !LELY_NO_ERRNO
676 int errsv = errno;
677#endif
678 free(futures);
679#if !LELY_NO_ERRNO
680 errno = errsv;
681#endif
682 return result;
683 }
684}
685
686static void
687ev_future_when_all_func(struct ev_task *task)
688{
689 assert(task);
690 struct ev_future_when_all *when =
691 structof(task, struct ev_future_when_all, task);
692
693 ev_future_t **pfuture = when->futures + when->idx;
694 if (ev_future_is_ready(*pfuture)) {
695 ev_future_release(*pfuture);
696 while (++when->idx < when->n && ev_future_is_unique(*++pfuture))
697 ev_future_release(*pfuture);
698 if (when->idx < when->n) {
699 ev_future_submit(*pfuture, &when->task);
700 return;
701 }
702 } else {
703 for (size_t i = when->idx; i < when->n; i++)
704 ev_future_release(*pfuture++);
705 }
706
707 ev_promise_set(when->promise, &when->idx);
708 ev_promise_release(when->promise);
709}
710
711static ev_future_t *
712ev_future_when_any_nv(
713 ev_exec_t *exec, size_t n, ev_future_t *future, va_list ap)
714{
715 if (n <= LELY_EV_FUTURE_MAX) {
716#if __STDC_NO_VLA__ || defined(_MSC_VER)
717 ev_future_t *futures[LELY_EV_FUTURE_MAX];
718#else
719 ev_future_t *futures[n ? n : 1];
720#endif
721 for (size_t i = 0; i < n; i++) {
722 futures[i] = future;
723 future = va_arg(ap, ev_future_t *);
724 }
725 return ev_future_when_any_n(exec, n, futures);
726 } else {
727 ev_future_t **futures = malloc(n * sizeof(*futures));
728 if (!futures) {
729#if !LELY_NO_ERRNO
730 set_errc(errno2c(errno));
731#endif
732 return NULL;
733 }
734 for (size_t i = 0; i < n; i++) {
735 futures[i] = future;
736 future = va_arg(ap, ev_future_t *);
737 }
738 ev_future_t *result = ev_future_when_any_n(exec, n, futures);
739#if !LELY_NO_ERRNO
740 int errsv = errno;
741#endif
742 free(futures);
743#if !LELY_NO_ERRNO
744 errno = errsv;
745#endif
746 return result;
747 }
748}
749
750static void
751ev_future_when_any_func(struct ev_task *task)
752{
753 assert(task);
754 struct ev_future_when_any *when =
755 structof(task, struct ev_future_when_any, task);
756
757 ev_promise_set(when->promise, &when->idx);
758 ev_promise_release(when->promise);
759}
760
761#endif // !LELY_NO_MALLOC
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.
Definition: errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
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.
Definition: exec.h:124
void ev_exec_on_task_fini(ev_exec_t *exec)
Undoes the effect of a previous call to ev_exec_on_task_init().
Definition: exec.h:112
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.
Definition: exec.h:106
ev_promise_t * ev_promise_acquire(ev_promise_t *promise)
Acquires a reference to a promise.
Definition: future.c:181
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...
Definition: future.c:335
void ev_promise_release(ev_promise_t *promise)
Releases a reference to a promise.
Definition: future.c:198
ev_future_state
The state of a future.
Definition: future.c:50
@ EV_FUTURE_SETTING
The promise is in the process of being satisfied (i.e., ev_promise_set_acquire() has been invoked).
Definition: future.c:57
@ EV_FUTURE_READY
The future is ready (i.e., ev_promise_set_release() has been invoked).
Definition: future.c:62
@ EV_FUTURE_WAITING
The future is waiting.
Definition: future.c:52
ev_future_t * ev_promise_get_future(ev_promise_t *promise)
Returns (a reference to) a future associated with the specified promise.
Definition: future.c:312
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 ...
Definition: future.c:221
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...
Definition: future.c:404
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...
Definition: future.c:391
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...
Definition: future.c:417
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...
Definition: future.c:242
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 ...
Definition: future.c:427
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...
Definition: future.c:275
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...
Definition: future.c:500
void * ev_promise_data(const ev_promise_t *promise)
Returns a pointer to the shared state of a promise.
Definition: future.c:236
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...
Definition: future.c:441
void * ev_future_get(const ev_future_t *future)
Returns the result of a ready future.
Definition: future.c:356
void ev_future_submit(ev_future_t *future, struct ev_task *task)
Submits a task to be executed once the specified future is ready.
Definition: future.c:364
void ev_future_release(ev_future_t *future)
Releases a reference to a future.
Definition: future.c:328
ev_future_t * ev_future_acquire(ev_future_t *future)
Acquires a reference to a future.
Definition: future.c:320
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...
Definition: future.c:476
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 ...
Definition: future.c:486
ev_promise_t * ev_promise_create(size_t size, ev_promise_dtor_t *dtor)
Constructs a new promise with an optional empty shared state.
Definition: future.c:154
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.
Definition: future.c:341
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...
Definition: future.c:251
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...
Definition: future.h:55
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
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.
Definition: util.h:93
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition: sllist.h:194
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
Definition: sllist.h:257
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
Definition: sllist.c:46
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
Definition: sllist.h:232
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.
Definition: stdatomic.h:158
@ memory_order_relaxed
No operation orders memory.
Definition: stdatomic.h:131
@ memory_order_acq_rel
A load operation performs an acquire operation on the affected memory location, and a store operation...
Definition: stdatomic.h:168
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
Definition: stdatomic.h:149
#define atomic_fetch_add_explicit(object, operand, order)
Atomically replaces the value at object with *object + operand.
Definition: stdatomic.h:480
#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,...
Definition: stdatomic.h:405
#define atomic_load_explicit(object, order)
Atomically returns the value at object.
Definition: stdatomic.h:344
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
Definition: stdatomic.h:617
#define atomic_load(object)
Equivalent to atomic_load_explicit(object, memory_order_seq_cst).
Definition: stdatomic.h:333
#define atomic_store_explicit(object, desired, order)
Atomically replaces the value at object with the value of desired.
Definition: stdatomic.h:325
#define atomic_init(obj, value)
Initializes the atomic object at obj with the value value.
Definition: stdatomic.h:222
#define atomic_fetch_sub_explicit(object, operand, order)
Atomically replaces the value at object with *object - operand.
Definition: stdatomic.h:504
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....
A future.
Definition: future.c:66
atomic_int state
The state of the future.
Definition: future.c:76
void * value
The value of the future, set by ev_promise_set_release().
Definition: future.c:79
struct sllist queue
The queue of tasks submitted by ev_future_submit() waiting for the future to become ready.
Definition: future.c:88
A promise.
Definition: future.c:95
atomic_size_t refcnt
The number of references to this promise or its future.
Definition: future.c:107
ev_promise_dtor_t * dtor
The (destructor) function invoked when this struct is reclaimed.
Definition: future.c:110
struct ev_future future
The future used to monitor if the promise has been satisfied.
Definition: future.c:112
An executable task.
Definition: task.h:41
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition: task.h:43
A singly-linked list.
Definition: sllist.h:52
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.
Definition: task.c:55
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition: task.h:53
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 ...
Definition: task.c:38
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.
Definition: threads.h:121
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.
Definition: threads.h:102
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.
Definition: threads.h:109