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