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 
66 struct 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
78  void *value;
80 #if !LELY_NO_THREADS
81  mtx_t mtx;
83 #endif
84 
88  struct sllist queue;
89 };
90 
91 static ev_future_t *ev_future_init(ev_future_t *future);
92 static void ev_future_fini(ev_future_t *future);
93 
95 struct 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 
117 static inline ev_promise_t *ev_promise_from_future(const ev_future_t *future);
118 
119 static void *ev_promise_alloc(size_t size);
120 static void ev_promise_free(void *ptr);
121 
122 static ev_promise_t *ev_promise_init(
123  ev_promise_t *promise, ev_promise_dtor_t *dtor);
124 static void ev_promise_fini(ev_promise_t *promise);
125 
126 static void ev_future_pop(ev_future_t *future, struct sllist *queue,
127  struct ev_task *task);
128 
129 static 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 
140 static void ev_future_when_all_func(struct ev_task *task);
141 
142 static 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 
151 static void ev_future_when_any_func(struct ev_task *task);
152 
153 ev_promise_t *
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 
173 error_init:
174  ev_promise_free(promise);
175 error_alloc:
176  set_errc(errc);
177  return NULL;
178 }
179 
180 ev_promise_t *
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 
197 void
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 
220 int
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,
230  memory_order_relaxed) == 1;
231  // clang-format on
232 #endif
233 }
234 
235 void *
237 {
238  return promise ? (char *)promise + EV_PROMISE_SIZE : NULL;
239 }
240 
241 int
242 ev_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 
250 int
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 
274 void
275 ev_promise_set_release(ev_promise_t *promise, void *value)
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
283  == EV_FUTURE_SETTING);
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 
311 ev_future_t *
313 {
314  assert(promise);
315 
316  return ev_future_acquire(&promise->future);
317 }
318 
319 ev_future_t *
321 {
322  if (future)
323  ev_promise_acquire(ev_promise_from_future(future));
324  return future;
325 }
326 
327 void
329 {
330  if (future)
331  ev_promise_release(ev_promise_from_future(future));
332 }
333 
334 int
336 {
337  return ev_promise_is_unique(ev_promise_from_future(future));
338 }
339 
340 int
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 
355 void *
357 {
358  assert(ev_future_is_ready(future));
359 
360  return future->value;
361 }
362 
363 void
364 ev_future_submit(ev_future_t *future, struct ev_task *task)
365 {
366  assert(future);
367  assert(task);
368  ev_exec_t *exec = task->exec;
369  assert(exec);
370 
371  ev_exec_on_task_init(exec);
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);
381  ev_exec_on_task_fini(exec);
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 
390 size_t
391 ev_future_cancel(ev_future_t *future, struct ev_task *task)
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 
403 size_t
404 ev_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 
416 ev_future_t *
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 
426 ev_future_t *
427 ev_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 
440 ev_future_t *
441 ev_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 
446  ev_promise_t *promise = ev_promise_create(
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 
475 ev_future_t *
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 
485 ev_future_t *
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 
499 ev_future_t *
500 ev_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 
505  ev_promise_t *promise = ev_promise_create(
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 
538 static ev_future_t *
539 ev_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 
561 static void
562 ev_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 
573 static void
574 ev_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 
591 static inline ev_promise_t *
592 ev_promise_from_future(const ev_future_t *future)
593 {
594  assert(future);
595 
596  return structof(future, ev_promise_t, future);
597 }
598 
599 static void *
600 ev_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 
611 static void
612 ev_promise_free(void *ptr)
613 {
614  free(ptr);
615 }
616 
617 static ev_promise_t *
618 ev_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 
636 static void
637 ev_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 
647 static ev_future_t *
648 ev_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 
686 static void
687 ev_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 
711 static ev_future_t *
712 ev_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 
750 static void
751 ev_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
ev_future_when_any_v
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_is_unique
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
ev_future_get
void * ev_future_get(const ev_future_t *future)
Returns the result of a ready future.
Definition: future.c:356
ev_future
A future.
Definition: future.c:66
ev_exec_t
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
task.h
mtx_destroy
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
Definition: threads-pthread.c:113
sllist_remove
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
Definition: sllist.c:46
memory_order_relaxed
@ memory_order_relaxed
No operation orders memory.
Definition: stdatomic.h:131
future.h
ev_future_cancel
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_promise_get_future
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
ev_future::queue
struct sllist queue
The queue of tasks submitted by ev_future_submit() waiting for the future to become ready.
Definition: future.c:88
atomic_load
#define atomic_load(object)
Equivalent to atomic_load_explicit(object, memory_order_seq_cst).
Definition: stdatomic.h:333
ev_future::state
atomic_int state
The state of the future.
Definition: future.c:76
threads.h
util.h
atomic_store_explicit
#define atomic_store_explicit(object, desired, order)
Atomically replaces the value at object with the value of desired.
Definition: stdatomic.h:325
mtx_lock
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
Definition: threads-pthread.c:150
ev_promise
A promise.
Definition: future.c:95
atomic_init
#define atomic_init(obj, value)
Initializes the atomic object at obj with the value value.
Definition: stdatomic.h:222
ev_future_when_all_n
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
EV_FUTURE_SETTING
@ 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
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
memory_order_release
@ memory_order_release
A store operation performs a release operation on the affected memory location.
Definition: stdatomic.h:158
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
exec.h
ev_future_when_any
Definition: future.c:145
sllist_append
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
ev_future_when_all
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
ev_promise::dtor
ev_promise_dtor_t * dtor
The (destructor) function invoked when this struct is reclaimed.
Definition: future.c:110
mtx_t
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
Definition: threads.h:102
thrd_success
@ thrd_success
Indicates that the requested operation succeeded.
Definition: threads.h:121
ev_future::value
void * value
The value of the future, set by ev_promise_set_release().
Definition: future.c:79
ev_promise::future
struct ev_future future
The future used to monitor if the promise has been satisfied.
Definition: future.c:112
ev_task_queue_post
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
ev_promise_release
void ev_promise_release(ev_promise_t *promise)
Releases a reference to a promise.
Definition: future.c:198
ev_future_when_any
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
mtx_unlock
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
Definition: threads-pthread.c:183
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
ev_task_queue_abort
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
errnum.h
atomic_compare_exchange_strong_explicit
#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
ev_future_is_unique
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
ev_promise::refcnt
atomic_size_t refcnt
The number of references to this promise or its future.
Definition: future.c:107
memory_order_acquire
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
Definition: stdatomic.h:149
ev_exec_on_task_fini
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
ev_future_abort
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
stdint.h
ev_promise_acquire
ev_promise_t * ev_promise_acquire(ev_promise_t *promise)
Acquires a reference to a promise.
Definition: future.c:181
sllist_init
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition: sllist.h:194
atomic_fetch_add_explicit
#define atomic_fetch_add_explicit(object, operand, order)
Atomically replaces the value at object with *object + operand.
Definition: stdatomic.h:480
ev_promise_create
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
ev_future_state
ev_future_state
The state of a future.
Definition: future.c:50
ev_future_release
void ev_future_release(ev_future_t *future)
Releases a reference to a future.
Definition: future.c:328
ev_future_submit
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
ev_future_when_all_v
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
sllist
A singly-linked list.
Definition: sllist.h:52
ev_promise_dtor_t
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
stdatomic.h
ev_future_acquire
ev_future_t * ev_future_acquire(ev_future_t *future)
Acquires a reference to a future.
Definition: future.c:320
atomic_thread_fence
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
Definition: stdatomic.h:617
EV_FUTURE_WAITING
@ EV_FUTURE_WAITING
The future is waiting.
Definition: future.c:52
EV_FUTURE_READY
@ EV_FUTURE_READY
The future is ready (i.e., ev_promise_set_release() has been invoked).
Definition: future.c:62
structof
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
ev_task
An executable task.
Definition: task.h:41
ev_promise_data
void * ev_promise_data(const ev_promise_t *promise)
Returns a pointer to the shared state of a promise.
Definition: future.c:236
ev.h
EV_TASK_INIT
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition: task.h:53
ev_future_is_ready
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
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.
Definition: exec.h:106
atomic_fetch_sub_explicit
#define atomic_fetch_sub_explicit(object, operand, order)
Atomically replaces the value at object with *object - operand.
Definition: stdatomic.h:504
ev_exec_post
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
Definition: exec.h:124
ev_promise_set_acquire
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
stdlib.h
ev_future_when_all
Definition: future.c:132
ev_promise_set_release
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
stddef.h
sllist_push_back
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
memory_order_acq_rel
@ memory_order_acq_rel
A load operation performs an acquire operation on the affected memory location, and a store operation...
Definition: stdatomic.h:168
mtx_init
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:
Definition: threads-pthread.c:119
atomic_load_explicit
#define atomic_load_explicit(object, order)
Atomically returns the value at object.
Definition: stdatomic.h:344
ev_task::exec
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition: task.h:43
mtx_plain
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
Definition: threads.h:109
ev_future_when_any_n
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
ev_promise_set
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